Switched to spaces
This commit is contained in:
parent
79df9b56d3
commit
2702518e31
265 changed files with 14902 additions and 14902 deletions
|
@ -2,130 +2,130 @@ var App = App || {};
|
||||||
|
|
||||||
App.API = function(_, jQuery, promise, appState) {
|
App.API = function(_, jQuery, promise, appState) {
|
||||||
|
|
||||||
var baseUrl = '/api/';
|
var baseUrl = '/api/';
|
||||||
var AJAX_UNSENT = 0;
|
var AJAX_UNSENT = 0;
|
||||||
var AJAX_OPENED = 1;
|
var AJAX_OPENED = 1;
|
||||||
var AJAX_HEADERS_RECEIVED = 2;
|
var AJAX_HEADERS_RECEIVED = 2;
|
||||||
var AJAX_LOADING = 3;
|
var AJAX_LOADING = 3;
|
||||||
var AJAX_DONE = 4;
|
var AJAX_DONE = 4;
|
||||||
|
|
||||||
var cache = {};
|
var cache = {};
|
||||||
|
|
||||||
function get(url, data) {
|
function get(url, data) {
|
||||||
return request('GET', url, data);
|
return request('GET', url, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
function post(url, data) {
|
function post(url, data) {
|
||||||
return request('POST', url, data);
|
return request('POST', url, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
function put(url, data) {
|
function put(url, data) {
|
||||||
return request('PUT', url, data);
|
return request('PUT', url, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
function _delete(url, data) {
|
function _delete(url, data) {
|
||||||
return request('DELETE', url, data);
|
return request('DELETE', url, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCacheKey(method, url, data) {
|
function getCacheKey(method, url, data) {
|
||||||
return JSON.stringify({method: method, url: url, data: data});
|
return JSON.stringify({method: method, url: url, data: data});
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearCache() {
|
function clearCache() {
|
||||||
cache = {};
|
cache = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
function request(method, url, data) {
|
function request(method, url, data) {
|
||||||
if (method === 'GET') {
|
if (method === 'GET') {
|
||||||
return requestWithCache(method, url, data);
|
return requestWithCache(method, url, data);
|
||||||
}
|
}
|
||||||
clearCache();
|
clearCache();
|
||||||
return requestWithAjax(method, url, data);
|
return requestWithAjax(method, url, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
function requestWithCache(method, url, data) {
|
function requestWithCache(method, url, data) {
|
||||||
var cacheKey = getCacheKey(method, url, data);
|
var cacheKey = getCacheKey(method, url, data);
|
||||||
if (_.has(cache, cacheKey)) {
|
if (_.has(cache, cacheKey)) {
|
||||||
return promise.make(function(resolve, reject) {
|
return promise.make(function(resolve, reject) {
|
||||||
resolve(cache[cacheKey]);
|
resolve(cache[cacheKey]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return promise.make(function(resolve, reject) {
|
return promise.make(function(resolve, reject) {
|
||||||
promise.wait(requestWithAjax(method, url, data))
|
promise.wait(requestWithAjax(method, url, data))
|
||||||
.then(function(response) {
|
.then(function(response) {
|
||||||
setCache(method, url, data, response);
|
setCache(method, url, data, response);
|
||||||
resolve(response);
|
resolve(response);
|
||||||
}).fail(function(response) {
|
}).fail(function(response) {
|
||||||
reject(response);
|
reject(response);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function setCache(method, url, data, response) {
|
function setCache(method, url, data, response) {
|
||||||
var cacheKey = getCacheKey(method, url, data);
|
var cacheKey = getCacheKey(method, url, data);
|
||||||
cache[cacheKey] = response;
|
cache[cacheKey] = response;
|
||||||
}
|
}
|
||||||
|
|
||||||
function requestWithAjax(method, url, data) {
|
function requestWithAjax(method, url, data) {
|
||||||
var fullUrl = baseUrl + '/' + url;
|
var fullUrl = baseUrl + '/' + url;
|
||||||
fullUrl = fullUrl.replace(/\/{2,}/, '/');
|
fullUrl = fullUrl.replace(/\/{2,}/, '/');
|
||||||
|
|
||||||
var xhr = null;
|
var xhr = null;
|
||||||
var apiPromise = promise.make(function(resolve, reject) {
|
var apiPromise = promise.make(function(resolve, reject) {
|
||||||
var options = {
|
var options = {
|
||||||
headers: {
|
headers: {
|
||||||
'X-Authorization-Token': appState.get('loginToken') || '',
|
'X-Authorization-Token': appState.get('loginToken') || '',
|
||||||
},
|
},
|
||||||
success: function(data, textStatus, xhr) {
|
success: function(data, textStatus, xhr) {
|
||||||
resolve({
|
resolve({
|
||||||
status: xhr.status,
|
status: xhr.status,
|
||||||
json: stripMeta(data)});
|
json: stripMeta(data)});
|
||||||
},
|
},
|
||||||
error: function(xhr, textStatus, errorThrown) {
|
error: function(xhr, textStatus, errorThrown) {
|
||||||
reject({
|
reject({
|
||||||
status: xhr.status,
|
status: xhr.status,
|
||||||
json: xhr.responseJSON ?
|
json: xhr.responseJSON ?
|
||||||
stripMeta(xhr.responseJSON) :
|
stripMeta(xhr.responseJSON) :
|
||||||
{error: errorThrown}});
|
{error: errorThrown}});
|
||||||
},
|
},
|
||||||
type: method,
|
type: method,
|
||||||
url: fullUrl,
|
url: fullUrl,
|
||||||
data: data,
|
data: data,
|
||||||
cache: false,
|
cache: false,
|
||||||
};
|
};
|
||||||
if (data instanceof FormData) {
|
if (data instanceof FormData) {
|
||||||
options.processData = false;
|
options.processData = false;
|
||||||
options.contentType = false;
|
options.contentType = false;
|
||||||
}
|
}
|
||||||
xhr = jQuery.ajax(options);
|
xhr = jQuery.ajax(options);
|
||||||
});
|
});
|
||||||
apiPromise.xhr = xhr;
|
apiPromise.xhr = xhr;
|
||||||
return apiPromise;
|
return apiPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
function stripMeta(data) {
|
function stripMeta(data) {
|
||||||
var result = {};
|
var result = {};
|
||||||
_.each(data, function(v, k) {
|
_.each(data, function(v, k) {
|
||||||
if (!k.match(/^__/)) {
|
if (!k.match(/^__/)) {
|
||||||
result[k] = v;
|
result[k] = v;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
get: get,
|
get: get,
|
||||||
post: post,
|
post: post,
|
||||||
put: put,
|
put: put,
|
||||||
delete: _delete,
|
delete: _delete,
|
||||||
|
|
||||||
AJAX_UNSENT: AJAX_UNSENT,
|
AJAX_UNSENT: AJAX_UNSENT,
|
||||||
AJAX_OPENED: AJAX_OPENED,
|
AJAX_OPENED: AJAX_OPENED,
|
||||||
AJAX_HEADERS_RECEIVED: AJAX_HEADERS_RECEIVED,
|
AJAX_HEADERS_RECEIVED: AJAX_HEADERS_RECEIVED,
|
||||||
AJAX_LOADING: AJAX_LOADING,
|
AJAX_LOADING: AJAX_LOADING,
|
||||||
AJAX_DONE: AJAX_DONE,
|
AJAX_DONE: AJAX_DONE,
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,198 +2,198 @@ var App = App || {};
|
||||||
|
|
||||||
App.Auth = function(_, jQuery, util, api, appState, promise) {
|
App.Auth = function(_, jQuery, util, api, appState, promise) {
|
||||||
|
|
||||||
var privileges = {
|
var privileges = {
|
||||||
register: 'register',
|
register: 'register',
|
||||||
listUsers: 'listUsers',
|
listUsers: 'listUsers',
|
||||||
viewUsers: 'viewUsers',
|
viewUsers: 'viewUsers',
|
||||||
viewAllAccessRanks: 'viewAllAccessRanks',
|
viewAllAccessRanks: 'viewAllAccessRanks',
|
||||||
viewAllEmailAddresses: 'viewAllEmailAddresses',
|
viewAllEmailAddresses: 'viewAllEmailAddresses',
|
||||||
changeAccessRank: 'changeAccessRank',
|
changeAccessRank: 'changeAccessRank',
|
||||||
changeOwnAvatarStyle: 'changeOwnAvatarStyle',
|
changeOwnAvatarStyle: 'changeOwnAvatarStyle',
|
||||||
changeOwnEmailAddress: 'changeOwnEmailAddress',
|
changeOwnEmailAddress: 'changeOwnEmailAddress',
|
||||||
changeOwnName: 'changeOwnName',
|
changeOwnName: 'changeOwnName',
|
||||||
changeOwnPassword: 'changeOwnPassword',
|
changeOwnPassword: 'changeOwnPassword',
|
||||||
changeAllAvatarStyles: 'changeAllAvatarStyles',
|
changeAllAvatarStyles: 'changeAllAvatarStyles',
|
||||||
changeAllEmailAddresses: 'changeAllEmailAddresses',
|
changeAllEmailAddresses: 'changeAllEmailAddresses',
|
||||||
changeAllNames: 'changeAllNames',
|
changeAllNames: 'changeAllNames',
|
||||||
changeAllPasswords: 'changeAllPasswords',
|
changeAllPasswords: 'changeAllPasswords',
|
||||||
deleteOwnAccount: 'deleteOwnAccount',
|
deleteOwnAccount: 'deleteOwnAccount',
|
||||||
deleteAllAccounts: 'deleteAllAccounts',
|
deleteAllAccounts: 'deleteAllAccounts',
|
||||||
banUsers: 'banUsers',
|
banUsers: 'banUsers',
|
||||||
|
|
||||||
listPosts: 'listPosts',
|
listPosts: 'listPosts',
|
||||||
viewPosts: 'viewPosts',
|
viewPosts: 'viewPosts',
|
||||||
uploadPosts: 'uploadPosts',
|
uploadPosts: 'uploadPosts',
|
||||||
uploadPostsAnonymously: 'uploadPostsAnonymously',
|
uploadPostsAnonymously: 'uploadPostsAnonymously',
|
||||||
deletePosts: 'deletePosts',
|
deletePosts: 'deletePosts',
|
||||||
featurePosts: 'featurePosts',
|
featurePosts: 'featurePosts',
|
||||||
changePostSafety: 'changePostSafety',
|
changePostSafety: 'changePostSafety',
|
||||||
changePostSource: 'changePostSource',
|
changePostSource: 'changePostSource',
|
||||||
changePostTags: 'changePostTags',
|
changePostTags: 'changePostTags',
|
||||||
changePostContent: 'changePostContent',
|
changePostContent: 'changePostContent',
|
||||||
changePostThumbnail: 'changePostThumbnail',
|
changePostThumbnail: 'changePostThumbnail',
|
||||||
changePostRelations: 'changePostRelations',
|
changePostRelations: 'changePostRelations',
|
||||||
changePostFlags: 'changePostFlags',
|
changePostFlags: 'changePostFlags',
|
||||||
|
|
||||||
addPostNotes: 'addPostNotes',
|
addPostNotes: 'addPostNotes',
|
||||||
editPostNotes: 'editPostNotes',
|
editPostNotes: 'editPostNotes',
|
||||||
deletePostNotes: 'deletePostNotes',
|
deletePostNotes: 'deletePostNotes',
|
||||||
|
|
||||||
listComments: 'listComments',
|
listComments: 'listComments',
|
||||||
addComments: 'addComments',
|
addComments: 'addComments',
|
||||||
editOwnComments: 'editOwnComments',
|
editOwnComments: 'editOwnComments',
|
||||||
editAllComments: 'editAllComments',
|
editAllComments: 'editAllComments',
|
||||||
deleteOwnComments: 'deleteOwnComments',
|
deleteOwnComments: 'deleteOwnComments',
|
||||||
deleteAllComments: 'deleteAllComments',
|
deleteAllComments: 'deleteAllComments',
|
||||||
deleteTags: 'deleteTags',
|
deleteTags: 'deleteTags',
|
||||||
mergeTags: 'mergeTags',
|
mergeTags: 'mergeTags',
|
||||||
|
|
||||||
listTags: 'listTags',
|
listTags: 'listTags',
|
||||||
massTag: 'massTag',
|
massTag: 'massTag',
|
||||||
changeTagName: 'changeTagName',
|
changeTagName: 'changeTagName',
|
||||||
changeTagCategory: 'changeTagCategory',
|
changeTagCategory: 'changeTagCategory',
|
||||||
changeTagImplications: 'changeTagImplications',
|
changeTagImplications: 'changeTagImplications',
|
||||||
changeTagSuggestions: 'changeTagSuggestions',
|
changeTagSuggestions: 'changeTagSuggestions',
|
||||||
banTags: 'banTags',
|
banTags: 'banTags',
|
||||||
|
|
||||||
viewHistory: 'viewHistory',
|
viewHistory: 'viewHistory',
|
||||||
};
|
};
|
||||||
|
|
||||||
function loginFromCredentials(userNameOrEmail, password, remember) {
|
function loginFromCredentials(userNameOrEmail, password, remember) {
|
||||||
return promise.make(function(resolve, reject) {
|
return promise.make(function(resolve, reject) {
|
||||||
promise.wait(api.post('/login', {userNameOrEmail: userNameOrEmail, password: password}))
|
promise.wait(api.post('/login', {userNameOrEmail: userNameOrEmail, password: password}))
|
||||||
.then(function(response) {
|
.then(function(response) {
|
||||||
updateAppState(response);
|
updateAppState(response);
|
||||||
jQuery.cookie(
|
jQuery.cookie(
|
||||||
'auth',
|
'auth',
|
||||||
response.json.token.name,
|
response.json.token.name,
|
||||||
remember ? { expires: 365 } : {});
|
remember ? { expires: 365 } : {});
|
||||||
resolve(response);
|
resolve(response);
|
||||||
}).fail(function(response) {
|
}).fail(function(response) {
|
||||||
reject(response);
|
reject(response);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function loginFromToken(token, isFromCookie) {
|
function loginFromToken(token, isFromCookie) {
|
||||||
return promise.make(function(resolve, reject) {
|
return promise.make(function(resolve, reject) {
|
||||||
var fd = {
|
var fd = {
|
||||||
token: token,
|
token: token,
|
||||||
isFromCookie: isFromCookie
|
isFromCookie: isFromCookie
|
||||||
};
|
};
|
||||||
promise.wait(api.post('/login', fd))
|
promise.wait(api.post('/login', fd))
|
||||||
.then(function(response) {
|
.then(function(response) {
|
||||||
updateAppState(response);
|
updateAppState(response);
|
||||||
resolve(response);
|
resolve(response);
|
||||||
}).fail(function(response) {
|
}).fail(function(response) {
|
||||||
reject(response);
|
reject(response);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function loginAnonymous() {
|
function loginAnonymous() {
|
||||||
return promise.make(function(resolve, reject) {
|
return promise.make(function(resolve, reject) {
|
||||||
promise.wait(api.post('/login'))
|
promise.wait(api.post('/login'))
|
||||||
.then(function(response) {
|
.then(function(response) {
|
||||||
updateAppState(response);
|
updateAppState(response);
|
||||||
resolve(response);
|
resolve(response);
|
||||||
}).fail(function(response) {
|
}).fail(function(response) {
|
||||||
reject(response);
|
reject(response);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function logout() {
|
function logout() {
|
||||||
return promise.make(function(resolve, reject) {
|
return promise.make(function(resolve, reject) {
|
||||||
jQuery.removeCookie('auth');
|
jQuery.removeCookie('auth');
|
||||||
appState.set('loginToken', null);
|
appState.set('loginToken', null);
|
||||||
return promise.wait(loginAnonymous())
|
return promise.wait(loginAnonymous())
|
||||||
.then(resolve)
|
.then(resolve)
|
||||||
.fail(reject);
|
.fail(reject);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function tryLoginFromCookie() {
|
function tryLoginFromCookie() {
|
||||||
return promise.make(function(resolve, reject) {
|
return promise.make(function(resolve, reject) {
|
||||||
if (isLoggedIn()) {
|
if (isLoggedIn()) {
|
||||||
resolve();
|
resolve();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var authCookie = jQuery.cookie('auth');
|
var authCookie = jQuery.cookie('auth');
|
||||||
if (!authCookie) {
|
if (!authCookie) {
|
||||||
reject();
|
reject();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
promise.wait(loginFromToken(authCookie, true))
|
promise.wait(loginFromToken(authCookie, true))
|
||||||
.then(function(response) {
|
.then(function(response) {
|
||||||
resolve();
|
resolve();
|
||||||
}).fail(function(response) {
|
}).fail(function(response) {
|
||||||
jQuery.removeCookie('auth');
|
jQuery.removeCookie('auth');
|
||||||
reject();
|
reject();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateAppState(response) {
|
function updateAppState(response) {
|
||||||
appState.set('privileges', response.json.privileges || []);
|
appState.set('privileges', response.json.privileges || []);
|
||||||
appState.set('loginToken', response.json.token && response.json.token.name);
|
appState.set('loginToken', response.json.token && response.json.token.name);
|
||||||
appState.set('loggedIn', response.json.user && !!response.json.user.id);
|
appState.set('loggedIn', response.json.user && !!response.json.user.id);
|
||||||
appState.set('loggedInUser', response.json.user);
|
appState.set('loggedInUser', response.json.user);
|
||||||
}
|
}
|
||||||
|
|
||||||
function isLoggedIn(userName) {
|
function isLoggedIn(userName) {
|
||||||
if (!appState.get('loggedIn')) {
|
if (!appState.get('loggedIn')) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (typeof(userName) !== 'undefined') {
|
if (typeof(userName) !== 'undefined') {
|
||||||
if (getCurrentUser().name !== userName) {
|
if (getCurrentUser().name !== userName) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCurrentUser() {
|
function getCurrentUser() {
|
||||||
return appState.get('loggedInUser');
|
return appState.get('loggedInUser');
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCurrentPrivileges() {
|
function getCurrentPrivileges() {
|
||||||
return appState.get('privileges');
|
return appState.get('privileges');
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateCurrentUser(user) {
|
function updateCurrentUser(user) {
|
||||||
if (user.id !== getCurrentUser().id) {
|
if (user.id !== getCurrentUser().id) {
|
||||||
throw new Error('Cannot set current user to other user this way.');
|
throw new Error('Cannot set current user to other user this way.');
|
||||||
}
|
}
|
||||||
appState.set('loggedInUser', user);
|
appState.set('loggedInUser', user);
|
||||||
}
|
}
|
||||||
|
|
||||||
function hasPrivilege(privilege) {
|
function hasPrivilege(privilege) {
|
||||||
return _.contains(getCurrentPrivileges(), privilege);
|
return _.contains(getCurrentPrivileges(), privilege);
|
||||||
}
|
}
|
||||||
|
|
||||||
function startObservingLoginChanges(listenerName, callback) {
|
function startObservingLoginChanges(listenerName, callback) {
|
||||||
appState.startObserving('loggedInUser', listenerName, callback);
|
appState.startObserving('loggedInUser', listenerName, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
loginFromCredentials: loginFromCredentials,
|
loginFromCredentials: loginFromCredentials,
|
||||||
loginFromToken: loginFromToken,
|
loginFromToken: loginFromToken,
|
||||||
loginAnonymous: loginAnonymous,
|
loginAnonymous: loginAnonymous,
|
||||||
tryLoginFromCookie: tryLoginFromCookie,
|
tryLoginFromCookie: tryLoginFromCookie,
|
||||||
logout: logout,
|
logout: logout,
|
||||||
|
|
||||||
startObservingLoginChanges: startObservingLoginChanges,
|
startObservingLoginChanges: startObservingLoginChanges,
|
||||||
isLoggedIn: isLoggedIn,
|
isLoggedIn: isLoggedIn,
|
||||||
getCurrentUser: getCurrentUser,
|
getCurrentUser: getCurrentUser,
|
||||||
updateCurrentUser: updateCurrentUser,
|
updateCurrentUser: updateCurrentUser,
|
||||||
getCurrentPrivileges: getCurrentPrivileges,
|
getCurrentPrivileges: getCurrentPrivileges,
|
||||||
hasPrivilege: hasPrivilege,
|
hasPrivilege: hasPrivilege,
|
||||||
|
|
||||||
privileges: privileges,
|
privileges: privileges,
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,29 +2,29 @@ var App = App || {};
|
||||||
|
|
||||||
App.Bootstrap = function(auth, router, promise, presenterManager) {
|
App.Bootstrap = function(auth, router, promise, presenterManager) {
|
||||||
|
|
||||||
promise.wait(presenterManager.init())
|
promise.wait(presenterManager.init())
|
||||||
.then(function() {
|
.then(function() {
|
||||||
promise.wait(auth.tryLoginFromCookie())
|
promise.wait(auth.tryLoginFromCookie())
|
||||||
.then(startRouting)
|
.then(startRouting)
|
||||||
.fail(function(error) {
|
.fail(function(error) {
|
||||||
promise.wait(auth.loginAnonymous())
|
promise.wait(auth.loginAnonymous())
|
||||||
.then(startRouting)
|
.then(startRouting)
|
||||||
.fail(function() {
|
.fail(function() {
|
||||||
console.log(arguments);
|
console.log(arguments);
|
||||||
window.alert('Fatal authentication error');
|
window.alert('Fatal authentication error');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}).fail(function() {
|
}).fail(function() {
|
||||||
console.log(arguments);
|
console.log(arguments);
|
||||||
});
|
});
|
||||||
|
|
||||||
function startRouting() {
|
function startRouting() {
|
||||||
try {
|
try {
|
||||||
router.start();
|
router.start();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,96 +1,96 @@
|
||||||
var App = App || {};
|
var App = App || {};
|
||||||
|
|
||||||
App.BrowsingSettings = function(
|
App.BrowsingSettings = function(
|
||||||
promise,
|
promise,
|
||||||
auth,
|
auth,
|
||||||
api) {
|
api) {
|
||||||
|
|
||||||
var settings = getDefaultSettings();
|
var settings = getDefaultSettings();
|
||||||
|
|
||||||
auth.startObservingLoginChanges('browsing-settings', loginStateChanged);
|
auth.startObservingLoginChanges('browsing-settings', loginStateChanged);
|
||||||
|
|
||||||
readFromLocalStorage();
|
readFromLocalStorage();
|
||||||
if (auth.isLoggedIn()) {
|
if (auth.isLoggedIn()) {
|
||||||
loginStateChanged();
|
loginStateChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
function setSettings(newSettings) {
|
function setSettings(newSettings) {
|
||||||
settings = newSettings;
|
settings = newSettings;
|
||||||
return save();
|
return save();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSettings() {
|
function getSettings() {
|
||||||
return settings;
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDefaultSettings() {
|
function getDefaultSettings() {
|
||||||
return {
|
return {
|
||||||
hideDownvoted: true,
|
hideDownvoted: true,
|
||||||
endlessScroll: false,
|
endlessScroll: false,
|
||||||
listPosts: {
|
listPosts: {
|
||||||
safe: true,
|
safe: true,
|
||||||
sketchy: true,
|
sketchy: true,
|
||||||
unsafe: true,
|
unsafe: true,
|
||||||
},
|
},
|
||||||
keyboardShortcuts: true,
|
keyboardShortcuts: true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function loginStateChanged() {
|
function loginStateChanged() {
|
||||||
readFromUser(auth.getCurrentUser());
|
readFromUser(auth.getCurrentUser());
|
||||||
}
|
}
|
||||||
|
|
||||||
function readFromLocalStorage() {
|
function readFromLocalStorage() {
|
||||||
readFromString(localStorage.getItem('browsingSettings'));
|
readFromString(localStorage.getItem('browsingSettings'));
|
||||||
}
|
}
|
||||||
|
|
||||||
function readFromUser(user) {
|
function readFromUser(user) {
|
||||||
readFromString(user.browsingSettings);
|
readFromString(user.browsingSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
function readFromString(string) {
|
function readFromString(string) {
|
||||||
if (!string) {
|
if (!string) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (typeof(string) === 'string' || string instanceof String) {
|
if (typeof(string) === 'string' || string instanceof String) {
|
||||||
settings = JSON.parse(string);
|
settings = JSON.parse(string);
|
||||||
} else {
|
} else {
|
||||||
settings = string;
|
settings = string;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveToLocalStorage() {
|
function saveToLocalStorage() {
|
||||||
localStorage.setItem('browsingSettings', JSON.stringify(settings));
|
localStorage.setItem('browsingSettings', JSON.stringify(settings));
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveToUser(user) {
|
function saveToUser(user) {
|
||||||
var formData = {
|
var formData = {
|
||||||
browsingSettings: JSON.stringify(settings),
|
browsingSettings: JSON.stringify(settings),
|
||||||
};
|
};
|
||||||
return api.post('/users/' + user.name, formData);
|
return api.post('/users/' + user.name, formData);
|
||||||
}
|
}
|
||||||
|
|
||||||
function save() {
|
function save() {
|
||||||
return promise.make(function(resolve, reject) {
|
return promise.make(function(resolve, reject) {
|
||||||
saveToLocalStorage();
|
saveToLocalStorage();
|
||||||
if (auth.isLoggedIn()) {
|
if (auth.isLoggedIn()) {
|
||||||
promise.wait(saveToUser(auth.getCurrentUser()))
|
promise.wait(saveToUser(auth.getCurrentUser()))
|
||||||
.then(resolve)
|
.then(resolve)
|
||||||
.fail(reject);
|
.fail(reject);
|
||||||
} else {
|
} else {
|
||||||
resolve();
|
resolve();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
getSettings: getSettings,
|
getSettings: getSettings,
|
||||||
setSettings: setSettings,
|
setSettings: setSettings,
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,273 +2,273 @@ var App = App || {};
|
||||||
App.Controls = App.Controls || {};
|
App.Controls = App.Controls || {};
|
||||||
|
|
||||||
App.Controls.AutoCompleteInput = function($input) {
|
App.Controls.AutoCompleteInput = function($input) {
|
||||||
var _ = App.DI.get('_');
|
var _ = App.DI.get('_');
|
||||||
var jQuery = App.DI.get('jQuery');
|
var jQuery = App.DI.get('jQuery');
|
||||||
var tagList = App.DI.get('tagList');
|
var tagList = App.DI.get('tagList');
|
||||||
|
|
||||||
var KEY_TAB = 9;
|
var KEY_TAB = 9;
|
||||||
var KEY_RETURN = 13;
|
var KEY_RETURN = 13;
|
||||||
var KEY_DELETE = 46;
|
var KEY_DELETE = 46;
|
||||||
var KEY_ESCAPE = 27;
|
var KEY_ESCAPE = 27;
|
||||||
var KEY_UP = 38;
|
var KEY_UP = 38;
|
||||||
var KEY_DOWN = 40;
|
var KEY_DOWN = 40;
|
||||||
|
|
||||||
var options = {
|
var options = {
|
||||||
caseSensitive: false,
|
caseSensitive: false,
|
||||||
source: null,
|
source: null,
|
||||||
maxResults: 15,
|
maxResults: 15,
|
||||||
minLengthToArbitrarySearch: 3,
|
minLengthToArbitrarySearch: 3,
|
||||||
onApply: null,
|
onApply: null,
|
||||||
onDelete: null,
|
onDelete: null,
|
||||||
onRender: null,
|
onRender: null,
|
||||||
additionalFilter: null,
|
additionalFilter: null,
|
||||||
};
|
};
|
||||||
var showTimeout = null;
|
var showTimeout = null;
|
||||||
var cachedSource = null;
|
var cachedSource = null;
|
||||||
var results = [];
|
var results = [];
|
||||||
var activeResult = -1;
|
var activeResult = -1;
|
||||||
var monitorInputHidingInterval = null;
|
var monitorInputHidingInterval = null;
|
||||||
|
|
||||||
if ($input.length === 0) {
|
if ($input.length === 0) {
|
||||||
throw new Error('Input element was not found');
|
throw new Error('Input element was not found');
|
||||||
}
|
}
|
||||||
if ($input.length > 1) {
|
if ($input.length > 1) {
|
||||||
throw new Error('Cannot add autocompletion to more than one element at once');
|
throw new Error('Cannot add autocompletion to more than one element at once');
|
||||||
}
|
}
|
||||||
if ($input.attr('data-autocomplete')) {
|
if ($input.attr('data-autocomplete')) {
|
||||||
throw new Error('Autocompletion was already added for this element');
|
throw new Error('Autocompletion was already added for this element');
|
||||||
}
|
}
|
||||||
$input.attr('data-autocomplete', true);
|
$input.attr('data-autocomplete', true);
|
||||||
$input.attr('autocomplete', 'off');
|
$input.attr('autocomplete', 'off');
|
||||||
|
|
||||||
var $div = jQuery('<div>');
|
var $div = jQuery('<div>');
|
||||||
var $list = jQuery('<ul>');
|
var $list = jQuery('<ul>');
|
||||||
$div.addClass('autocomplete');
|
$div.addClass('autocomplete');
|
||||||
$div.append($list);
|
$div.append($list);
|
||||||
jQuery(document.body).append($div);
|
jQuery(document.body).append($div);
|
||||||
|
|
||||||
function getSource() {
|
function getSource() {
|
||||||
if (cachedSource) {
|
if (cachedSource) {
|
||||||
return cachedSource;
|
return cachedSource;
|
||||||
} else {
|
} else {
|
||||||
var source = tagList.getTags();
|
var source = tagList.getTags();
|
||||||
source = _.sortBy(source, function(a) { return -a.usages; });
|
source = _.sortBy(source, function(a) { return -a.usages; });
|
||||||
source = _.filter(source, function(a) { return a.usages >= 0; });
|
source = _.filter(source, function(a) { return a.usages >= 0; });
|
||||||
source = _.map(source, function(a) {
|
source = _.map(source, function(a) {
|
||||||
return {
|
return {
|
||||||
tag: a.name,
|
tag: a.name,
|
||||||
caption: a.name + ' (' + a.usages + ')',
|
caption: a.name + ' (' + a.usages + ')',
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
cachedSource = source;
|
cachedSource = source;
|
||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$input.bind('keydown', function(e) {
|
$input.bind('keydown', function(e) {
|
||||||
var func = null;
|
var func = null;
|
||||||
if (isShown() && e.which === KEY_ESCAPE) {
|
if (isShown() && e.which === KEY_ESCAPE) {
|
||||||
func = hide;
|
func = hide;
|
||||||
} else if (isShown() && e.which === KEY_TAB) {
|
} else if (isShown() && e.which === KEY_TAB) {
|
||||||
if (e.shiftKey) {
|
if (e.shiftKey) {
|
||||||
func = selectPrevious;
|
func = selectPrevious;
|
||||||
} else {
|
} else {
|
||||||
func = selectNext;
|
func = selectNext;
|
||||||
}
|
}
|
||||||
} else if (isShown() && e.which === KEY_DOWN) {
|
} else if (isShown() && e.which === KEY_DOWN) {
|
||||||
func = selectNext;
|
func = selectNext;
|
||||||
} else if (isShown() && e.which === KEY_UP) {
|
} else if (isShown() && e.which === KEY_UP) {
|
||||||
func = selectPrevious;
|
func = selectPrevious;
|
||||||
} else if (isShown() && e.which === KEY_RETURN && activeResult >= 0) {
|
} else if (isShown() && e.which === KEY_RETURN && activeResult >= 0) {
|
||||||
func = function() { applyAutocomplete(); hide(); };
|
func = function() { applyAutocomplete(); hide(); };
|
||||||
} else if (isShown() && e.which === KEY_DELETE && activeResult >= 0) {
|
} else if (isShown() && e.which === KEY_DELETE && activeResult >= 0) {
|
||||||
func = function() { applyDelete(); hide(); };
|
func = function() { applyDelete(); hide(); };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (func !== null) {
|
if (func !== null) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.stopImmediatePropagation();
|
e.stopImmediatePropagation();
|
||||||
func();
|
func();
|
||||||
} else {
|
} else {
|
||||||
window.clearTimeout(showTimeout);
|
window.clearTimeout(showTimeout);
|
||||||
showTimeout = window.setTimeout(showOrHide, 250);
|
showTimeout = window.setTimeout(showOrHide, 250);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$input.blur(function(e) {
|
$input.blur(function(e) {
|
||||||
window.clearTimeout(showTimeout);
|
window.clearTimeout(showTimeout);
|
||||||
window.setTimeout(function() { hide(); }, 50);
|
window.setTimeout(function() { hide(); }, 50);
|
||||||
});
|
});
|
||||||
|
|
||||||
function getSelectionStart(){
|
function getSelectionStart(){
|
||||||
var input = $input.get(0);
|
var input = $input.get(0);
|
||||||
if (!input) {
|
if (!input) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ('selectionStart' in input) {
|
if ('selectionStart' in input) {
|
||||||
return input.selectionStart;
|
return input.selectionStart;
|
||||||
} else if (document.selection) {
|
} else if (document.selection) {
|
||||||
input.focus();
|
input.focus();
|
||||||
var sel = document.selection.createRange();
|
var sel = document.selection.createRange();
|
||||||
var selLen = document.selection.createRange().text.length;
|
var selLen = document.selection.createRange().text.length;
|
||||||
sel.moveStart('character', -input.value.length);
|
sel.moveStart('character', -input.value.length);
|
||||||
return sel.text.length - selLen;
|
return sel.text.length - selLen;
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTextToFind() {
|
function getTextToFind() {
|
||||||
var val = $input.val();
|
var val = $input.val();
|
||||||
var start = getSelectionStart();
|
var start = getSelectionStart();
|
||||||
return val.substring(0, start).replace(/.*\s/, '');
|
return val.substring(0, start).replace(/.*\s/, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
function showOrHide() {
|
function showOrHide() {
|
||||||
var textToFind = getTextToFind();
|
var textToFind = getTextToFind();
|
||||||
if (textToFind.length === 0) {
|
if (textToFind.length === 0) {
|
||||||
hide();
|
hide();
|
||||||
} else {
|
} else {
|
||||||
updateResults(textToFind);
|
updateResults(textToFind);
|
||||||
refreshList();
|
refreshList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function isShown() {
|
function isShown() {
|
||||||
return $div.is(':visible');
|
return $div.is(':visible');
|
||||||
}
|
}
|
||||||
|
|
||||||
function hide() {
|
function hide() {
|
||||||
$div.hide();
|
$div.hide();
|
||||||
window.clearInterval(monitorInputHidingInterval);
|
window.clearInterval(monitorInputHidingInterval);
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectPrevious() {
|
function selectPrevious() {
|
||||||
select(activeResult === -1 ? results.length - 1 : activeResult - 1);
|
select(activeResult === -1 ? results.length - 1 : activeResult - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectNext() {
|
function selectNext() {
|
||||||
select(activeResult === -1 ? 0 : activeResult + 1);
|
select(activeResult === -1 ? 0 : activeResult + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
function select(newActiveResult) {
|
function select(newActiveResult) {
|
||||||
if (newActiveResult >= 0 && newActiveResult < results.length) {
|
if (newActiveResult >= 0 && newActiveResult < results.length) {
|
||||||
activeResult = newActiveResult;
|
activeResult = newActiveResult;
|
||||||
refreshActiveResult();
|
refreshActiveResult();
|
||||||
} else {
|
} else {
|
||||||
activeResult = - 1;
|
activeResult = - 1;
|
||||||
refreshActiveResult();
|
refreshActiveResult();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getResultsFilter(textToFind) {
|
function getResultsFilter(textToFind) {
|
||||||
if (textToFind.length < options.minLengthToArbitrarySearch) {
|
if (textToFind.length < options.minLengthToArbitrarySearch) {
|
||||||
return options.caseSensitive ?
|
return options.caseSensitive ?
|
||||||
function(resultItem) { return resultItem.tag.indexOf(textToFind) === 0; } :
|
function(resultItem) { return resultItem.tag.indexOf(textToFind) === 0; } :
|
||||||
function(resultItem) { return resultItem.tag.toLowerCase().indexOf(textToFind.toLowerCase()) === 0; };
|
function(resultItem) { return resultItem.tag.toLowerCase().indexOf(textToFind.toLowerCase()) === 0; };
|
||||||
} else {
|
} else {
|
||||||
return options.caseSensitive ?
|
return options.caseSensitive ?
|
||||||
function(resultItem) { return resultItem.tag.indexOf(textToFind) >= 0; } :
|
function(resultItem) { return resultItem.tag.indexOf(textToFind) >= 0; } :
|
||||||
function(resultItem) { return resultItem.tag.toLowerCase().indexOf(textToFind.toLowerCase()) >= 0; };
|
function(resultItem) { return resultItem.tag.toLowerCase().indexOf(textToFind.toLowerCase()) >= 0; };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateResults(textToFind) {
|
function updateResults(textToFind) {
|
||||||
var oldResults = results.slice();
|
var oldResults = results.slice();
|
||||||
var source = getSource();
|
var source = getSource();
|
||||||
var filter = getResultsFilter(textToFind);
|
var filter = getResultsFilter(textToFind);
|
||||||
results = _.filter(source, filter);
|
results = _.filter(source, filter);
|
||||||
if (options.additionalFilter) {
|
if (options.additionalFilter) {
|
||||||
results = options.additionalFilter(results);
|
results = options.additionalFilter(results);
|
||||||
}
|
}
|
||||||
results = results.slice(0, options.maxResults);
|
results = results.slice(0, options.maxResults);
|
||||||
if (!_.isEqual(oldResults, results)) {
|
if (!_.isEqual(oldResults, results)) {
|
||||||
activeResult = -1;
|
activeResult = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyDelete() {
|
function applyDelete() {
|
||||||
if (options.onDelete) {
|
if (options.onDelete) {
|
||||||
options.onDelete(results[activeResult].tag);
|
options.onDelete(results[activeResult].tag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyAutocomplete() {
|
function applyAutocomplete() {
|
||||||
if (options.onApply) {
|
if (options.onApply) {
|
||||||
options.onApply(results[activeResult].tag);
|
options.onApply(results[activeResult].tag);
|
||||||
} else {
|
} else {
|
||||||
var val = $input.val();
|
var val = $input.val();
|
||||||
var start = getSelectionStart();
|
var start = getSelectionStart();
|
||||||
var prefix = '';
|
var prefix = '';
|
||||||
var suffix = val.substring(start);
|
var suffix = val.substring(start);
|
||||||
var middle = val.substring(0, start);
|
var middle = val.substring(0, start);
|
||||||
var index = middle.lastIndexOf(' ');
|
var index = middle.lastIndexOf(' ');
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
prefix = val.substring(0, index + 1);
|
prefix = val.substring(0, index + 1);
|
||||||
middle = val.substring(index + 1);
|
middle = val.substring(index + 1);
|
||||||
}
|
}
|
||||||
$input.val(prefix + results[activeResult].tag + ' ' + suffix.trimLeft());
|
$input.val(prefix + results[activeResult].tag + ' ' + suffix.trimLeft());
|
||||||
$input.focus();
|
$input.focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function refreshList() {
|
function refreshList() {
|
||||||
if (results.length === 0) {
|
if (results.length === 0) {
|
||||||
hide();
|
hide();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$list.empty();
|
$list.empty();
|
||||||
_.each(results, function(resultItem, resultIndex) {
|
_.each(results, function(resultItem, resultIndex) {
|
||||||
var $listItem = jQuery('<li/>');
|
var $listItem = jQuery('<li/>');
|
||||||
$listItem.text(resultItem.caption);
|
$listItem.text(resultItem.caption);
|
||||||
$listItem.attr('data-key', resultItem.tag);
|
$listItem.attr('data-key', resultItem.tag);
|
||||||
$listItem.hover(function(e) {
|
$listItem.hover(function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
activeResult = resultIndex;
|
activeResult = resultIndex;
|
||||||
refreshActiveResult();
|
refreshActiveResult();
|
||||||
});
|
});
|
||||||
$listItem.mousedown(function(e) {
|
$listItem.mousedown(function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
activeResult = resultIndex;
|
activeResult = resultIndex;
|
||||||
applyAutocomplete();
|
applyAutocomplete();
|
||||||
hide();
|
hide();
|
||||||
});
|
});
|
||||||
$list.append($listItem);
|
$list.append($listItem);
|
||||||
});
|
});
|
||||||
if (options.onRender) {
|
if (options.onRender) {
|
||||||
options.onRender($list);
|
options.onRender($list);
|
||||||
}
|
}
|
||||||
refreshActiveResult();
|
refreshActiveResult();
|
||||||
|
|
||||||
var x = $input.offset().left;
|
var x = $input.offset().left;
|
||||||
var y = $input.offset().top + $input.outerHeight() - 2;
|
var y = $input.offset().top + $input.outerHeight() - 2;
|
||||||
if (y + $div.height() > window.innerHeight) {
|
if (y + $div.height() > window.innerHeight) {
|
||||||
y = $input.offset().top - $div.height();
|
y = $input.offset().top - $div.height();
|
||||||
}
|
}
|
||||||
$div.css({
|
$div.css({
|
||||||
left: x + 'px',
|
left: x + 'px',
|
||||||
top: y + 'px',
|
top: y + 'px',
|
||||||
});
|
});
|
||||||
$div.show();
|
$div.show();
|
||||||
monitorInputHiding();
|
monitorInputHiding();
|
||||||
}
|
}
|
||||||
|
|
||||||
function refreshActiveResult() {
|
function refreshActiveResult() {
|
||||||
$list.find('li.active').removeClass('active');
|
$list.find('li.active').removeClass('active');
|
||||||
if (activeResult >= 0) {
|
if (activeResult >= 0) {
|
||||||
$list.find('li').eq(activeResult).addClass('active');
|
$list.find('li').eq(activeResult).addClass('active');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function monitorInputHiding() {
|
function monitorInputHiding() {
|
||||||
monitorInputHidingInterval = window.setInterval(function() {
|
monitorInputHidingInterval = window.setInterval(function() {
|
||||||
if (!$input.is(':visible')) {
|
if (!$input.is(':visible')) {
|
||||||
hide();
|
hide();
|
||||||
}
|
}
|
||||||
}, 100);
|
}, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
return options;
|
return options;
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,64 +2,64 @@ var App = App || {};
|
||||||
App.Controls = App.Controls || {};
|
App.Controls = App.Controls || {};
|
||||||
|
|
||||||
App.Controls.FileDropper = function($fileInput) {
|
App.Controls.FileDropper = function($fileInput) {
|
||||||
var _ = App.DI.get('_');
|
var _ = App.DI.get('_');
|
||||||
var jQuery = App.DI.get('jQuery');
|
var jQuery = App.DI.get('jQuery');
|
||||||
|
|
||||||
var options = {
|
var options = {
|
||||||
onChange: null,
|
onChange: null,
|
||||||
setNames: false,
|
setNames: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
var $dropDiv = jQuery('<button type="button" class="file-handler"></button>');
|
var $dropDiv = jQuery('<button type="button" class="file-handler"></button>');
|
||||||
var allowMultiple = $fileInput.attr('multiple');
|
var allowMultiple = $fileInput.attr('multiple');
|
||||||
$dropDiv.html((allowMultiple ? 'Drop files here!' : 'Drop file here!') + '<br/>Or just click on this box.');
|
$dropDiv.html((allowMultiple ? 'Drop files here!' : 'Drop file here!') + '<br/>Or just click on this box.');
|
||||||
$dropDiv.insertBefore($fileInput);
|
$dropDiv.insertBefore($fileInput);
|
||||||
$fileInput.attr('multiple', allowMultiple);
|
$fileInput.attr('multiple', allowMultiple);
|
||||||
$fileInput.hide();
|
$fileInput.hide();
|
||||||
|
|
||||||
$fileInput.change(function(e) {
|
$fileInput.change(function(e) {
|
||||||
addFiles(this.files);
|
addFiles(this.files);
|
||||||
});
|
});
|
||||||
|
|
||||||
$dropDiv.on('dragenter', function(e) {
|
$dropDiv.on('dragenter', function(e) {
|
||||||
$dropDiv.addClass('active');
|
$dropDiv.addClass('active');
|
||||||
}).on('dragleave', function(e) {
|
}).on('dragleave', function(e) {
|
||||||
$dropDiv.removeClass('active');
|
$dropDiv.removeClass('active');
|
||||||
}).on('dragover', function(e) {
|
}).on('dragover', function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}).on('drop', function(e) {
|
}).on('drop', function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
addFiles(e.originalEvent.dataTransfer.files);
|
addFiles(e.originalEvent.dataTransfer.files);
|
||||||
}).on('click', function(e) {
|
}).on('click', function(e) {
|
||||||
$fileInput.show().focus().trigger('click').hide();
|
$fileInput.show().focus().trigger('click').hide();
|
||||||
$dropDiv.addClass('active');
|
$dropDiv.addClass('active');
|
||||||
});
|
});
|
||||||
|
|
||||||
function addFiles(files) {
|
function addFiles(files) {
|
||||||
$dropDiv.removeClass('active');
|
$dropDiv.removeClass('active');
|
||||||
if (!allowMultiple && files.length > 1) {
|
if (!allowMultiple && files.length > 1) {
|
||||||
window.alert('Cannot select multiple files.');
|
window.alert('Cannot select multiple files.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (typeof(options.onChange) !== 'undefined') {
|
if (typeof(options.onChange) !== 'undefined') {
|
||||||
options.onChange(files);
|
options.onChange(files);
|
||||||
}
|
}
|
||||||
if (options.setNames && !allowMultiple) {
|
if (options.setNames && !allowMultiple) {
|
||||||
$dropDiv.text(files[0].name);
|
$dropDiv.text(files[0].name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function readAsDataURL(file, callback) {
|
function readAsDataURL(file, callback) {
|
||||||
var reader = new FileReader();
|
var reader = new FileReader();
|
||||||
reader.onloadend = function() {
|
reader.onloadend = function() {
|
||||||
callback(reader.result);
|
callback(reader.result);
|
||||||
};
|
};
|
||||||
reader.readAsDataURL(file);
|
reader.readAsDataURL(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
_.extend(options, {
|
_.extend(options, {
|
||||||
readAsDataURL: readAsDataURL,
|
readAsDataURL: readAsDataURL,
|
||||||
});
|
});
|
||||||
|
|
||||||
return options;
|
return options;
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,419 +2,419 @@ var App = App || {};
|
||||||
App.Controls = App.Controls || {};
|
App.Controls = App.Controls || {};
|
||||||
|
|
||||||
App.Controls.TagInput = function($underlyingInput) {
|
App.Controls.TagInput = function($underlyingInput) {
|
||||||
var _ = App.DI.get('_');
|
var _ = App.DI.get('_');
|
||||||
var jQuery = App.DI.get('jQuery');
|
var jQuery = App.DI.get('jQuery');
|
||||||
var promise = App.DI.get('promise');
|
var promise = App.DI.get('promise');
|
||||||
var api = App.DI.get('api');
|
var api = App.DI.get('api');
|
||||||
var tagList = App.DI.get('tagList');
|
var tagList = App.DI.get('tagList');
|
||||||
|
|
||||||
var KEY_RETURN = 13;
|
var KEY_RETURN = 13;
|
||||||
var KEY_SPACE = 32;
|
var KEY_SPACE = 32;
|
||||||
var KEY_BACKSPACE = 8;
|
var KEY_BACKSPACE = 8;
|
||||||
var tagConfirmKeys = [KEY_RETURN, KEY_SPACE];
|
var tagConfirmKeys = [KEY_RETURN, KEY_SPACE];
|
||||||
var inputConfirmKeys = [KEY_RETURN];
|
var inputConfirmKeys = [KEY_RETURN];
|
||||||
|
|
||||||
var SOURCE_INITIAL_TEXT = 1;
|
var SOURCE_INITIAL_TEXT = 1;
|
||||||
var SOURCE_AUTOCOMPLETION = 2;
|
var SOURCE_AUTOCOMPLETION = 2;
|
||||||
var SOURCE_PASTE = 3;
|
var SOURCE_PASTE = 3;
|
||||||
var SOURCE_IMPLICATIONS = 4;
|
var SOURCE_IMPLICATIONS = 4;
|
||||||
var SOURCE_INPUT_BLUR = 5;
|
var SOURCE_INPUT_BLUR = 5;
|
||||||
var SOURCE_INPUT_ENTER = 6;
|
var SOURCE_INPUT_ENTER = 6;
|
||||||
var SOURCE_SUGGESTIONS = 7;
|
var SOURCE_SUGGESTIONS = 7;
|
||||||
|
|
||||||
var tags = [];
|
var tags = [];
|
||||||
var options = {
|
var options = {
|
||||||
beforeTagAdded: null,
|
beforeTagAdded: null,
|
||||||
beforeTagRemoved: null,
|
beforeTagRemoved: null,
|
||||||
inputConfirmed: null,
|
inputConfirmed: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
var $wrapper = jQuery('<div class="tag-input">');
|
var $wrapper = jQuery('<div class="tag-input">');
|
||||||
var $tagList = jQuery('<ul class="tags">');
|
var $tagList = jQuery('<ul class="tags">');
|
||||||
var tagInputId = 'tags' + Math.random();
|
var tagInputId = 'tags' + Math.random();
|
||||||
var $label = jQuery('<label for="' + tagInputId + '" style="display: none">Tags:</label>');
|
var $label = jQuery('<label for="' + tagInputId + '" style="display: none">Tags:</label>');
|
||||||
var $input = jQuery('<input class="tag-real-input" type="text" id="' + tagInputId + '"/>');
|
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 $siblings = jQuery('<div class="related-tags"><span>Sibling tags:</span><ul>');
|
||||||
var $suggestions = jQuery('<div class="related-tags"><span>Suggested tags:</span><ul>');
|
var $suggestions = jQuery('<div class="related-tags"><span>Suggested tags:</span><ul>');
|
||||||
init();
|
init();
|
||||||
render();
|
render();
|
||||||
initAutoComplete();
|
initAutoComplete();
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
if ($underlyingInput.length === 0) {
|
if ($underlyingInput.length === 0) {
|
||||||
throw new Error('Tag input element was not found');
|
throw new Error('Tag input element was not found');
|
||||||
}
|
}
|
||||||
if ($underlyingInput.length > 1) {
|
if ($underlyingInput.length > 1) {
|
||||||
throw new Error('Cannot set tag input to more than one element at once');
|
throw new Error('Cannot set tag input to more than one element at once');
|
||||||
}
|
}
|
||||||
if ($underlyingInput.attr('data-tagged')) {
|
if ($underlyingInput.attr('data-tagged')) {
|
||||||
throw new Error('Tag input was already initialized for this element');
|
throw new Error('Tag input was already initialized for this element');
|
||||||
}
|
}
|
||||||
$underlyingInput.attr('data-tagged', true);
|
$underlyingInput.attr('data-tagged', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
$underlyingInput.hide();
|
$underlyingInput.hide();
|
||||||
$wrapper.append($tagList);
|
$wrapper.append($tagList);
|
||||||
$wrapper.append($label);
|
$wrapper.append($label);
|
||||||
$wrapper.append($input);
|
$wrapper.append($input);
|
||||||
$wrapper.insertAfter($underlyingInput);
|
$wrapper.insertAfter($underlyingInput);
|
||||||
$wrapper.click(function(e) {
|
$wrapper.click(function(e) {
|
||||||
if (e.target.nodeName === 'LI') {
|
if (e.target.nodeName === 'LI') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
$input.focus();
|
$input.focus();
|
||||||
});
|
});
|
||||||
$input.attr('placeholder', $underlyingInput.attr('placeholder'));
|
$input.attr('placeholder', $underlyingInput.attr('placeholder'));
|
||||||
$siblings.insertAfter($wrapper);
|
$siblings.insertAfter($wrapper);
|
||||||
$suggestions.insertAfter($wrapper);
|
$suggestions.insertAfter($wrapper);
|
||||||
|
|
||||||
processText($underlyingInput.val(), SOURCE_INITIAL_TEXT);
|
processText($underlyingInput.val(), SOURCE_INITIAL_TEXT);
|
||||||
|
|
||||||
$underlyingInput.val('');
|
$underlyingInput.val('');
|
||||||
}
|
}
|
||||||
|
|
||||||
function initAutoComplete() {
|
function initAutoComplete() {
|
||||||
var autoComplete = new App.Controls.AutoCompleteInput($input);
|
var autoComplete = new App.Controls.AutoCompleteInput($input);
|
||||||
autoComplete.onDelete = function(text) {
|
autoComplete.onDelete = function(text) {
|
||||||
removeTag(text);
|
removeTag(text);
|
||||||
$input.val('');
|
$input.val('');
|
||||||
};
|
};
|
||||||
autoComplete.onApply = function(text) {
|
autoComplete.onApply = function(text) {
|
||||||
processText(text, SOURCE_AUTOCOMPLETION);
|
processText(text, SOURCE_AUTOCOMPLETION);
|
||||||
$input.val('');
|
$input.val('');
|
||||||
};
|
};
|
||||||
autoComplete.additionalFilter = function(results) {
|
autoComplete.additionalFilter = function(results) {
|
||||||
return _.filter(results, function(resultItem) {
|
return _.filter(results, function(resultItem) {
|
||||||
return !_.contains(getTags(), resultItem[0]);
|
return !_.contains(getTags(), resultItem[0]);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
autoComplete.onRender = function($list) {
|
autoComplete.onRender = function($list) {
|
||||||
$list.find('li').each(function() {
|
$list.find('li').each(function() {
|
||||||
var $li = jQuery(this);
|
var $li = jQuery(this);
|
||||||
if (isTaggedWith($li.attr('data-key'))) {
|
if (isTaggedWith($li.attr('data-key'))) {
|
||||||
$li.css('opacity', '0.5');
|
$li.css('opacity', '0.5');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
$input.bind('focus', function(e) {
|
$input.bind('focus', function(e) {
|
||||||
$wrapper.addClass('focused');
|
$wrapper.addClass('focused');
|
||||||
});
|
});
|
||||||
$input.bind('blur', function(e) {
|
$input.bind('blur', function(e) {
|
||||||
$wrapper.removeClass('focused');
|
$wrapper.removeClass('focused');
|
||||||
var tagName = $input.val();
|
var tagName = $input.val();
|
||||||
addTag(tagName, SOURCE_INPUT_BLUR);
|
addTag(tagName, SOURCE_INPUT_BLUR);
|
||||||
$input.val('');
|
$input.val('');
|
||||||
});
|
});
|
||||||
|
|
||||||
$input.bind('paste', function(e) {
|
$input.bind('paste', function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var pastedText;
|
var pastedText;
|
||||||
if (window.clipboardData) {
|
if (window.clipboardData) {
|
||||||
pastedText = window.clipboardData.getData('Text');
|
pastedText = window.clipboardData.getData('Text');
|
||||||
} else {
|
} else {
|
||||||
pastedText = (e.originalEvent || e).clipboardData.getData('text/plain');
|
pastedText = (e.originalEvent || e).clipboardData.getData('text/plain');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pastedText.length > 2000) {
|
if (pastedText.length > 2000) {
|
||||||
window.alert('Pasted text is too long.');
|
window.alert('Pasted text is too long.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
processTextWithoutLast(pastedText, SOURCE_PASTE);
|
processTextWithoutLast(pastedText, SOURCE_PASTE);
|
||||||
});
|
});
|
||||||
|
|
||||||
$input.bind('keydown', function(e) {
|
$input.bind('keydown', function(e) {
|
||||||
if (_.contains(inputConfirmKeys, e.which) && !$input.val()) {
|
if (_.contains(inputConfirmKeys, e.which) && !$input.val()) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (typeof(options.inputConfirmed) !== 'undefined') {
|
if (typeof(options.inputConfirmed) !== 'undefined') {
|
||||||
options.inputConfirmed();
|
options.inputConfirmed();
|
||||||
}
|
}
|
||||||
} else if (_.contains(tagConfirmKeys, e.which)) {
|
} else if (_.contains(tagConfirmKeys, e.which)) {
|
||||||
var tagName = $input.val();
|
var tagName = $input.val();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
$input.val('');
|
$input.val('');
|
||||||
addTag(tagName, SOURCE_INPUT_ENTER);
|
addTag(tagName, SOURCE_INPUT_ENTER);
|
||||||
} else if (e.which === KEY_BACKSPACE && jQuery(this).val().length === 0) {
|
} else if (e.which === KEY_BACKSPACE && jQuery(this).val().length === 0) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
removeLastTag();
|
removeLastTag();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function explodeText(text) {
|
function explodeText(text) {
|
||||||
return _.filter(text.trim().split(/\s+/), function(item) {
|
return _.filter(text.trim().split(/\s+/), function(item) {
|
||||||
return item.length > 0;
|
return item.length > 0;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function processText(text, source) {
|
function processText(text, source) {
|
||||||
var tagNamesToAdd = explodeText(text);
|
var tagNamesToAdd = explodeText(text);
|
||||||
_.map(tagNamesToAdd, function(tagName) { addTag(tagName, source); });
|
_.map(tagNamesToAdd, function(tagName) { addTag(tagName, source); });
|
||||||
}
|
}
|
||||||
|
|
||||||
function processTextWithoutLast(text, source) {
|
function processTextWithoutLast(text, source) {
|
||||||
var tagNamesToAdd = explodeText(text);
|
var tagNamesToAdd = explodeText(text);
|
||||||
var lastTagName = tagNamesToAdd.pop();
|
var lastTagName = tagNamesToAdd.pop();
|
||||||
_.map(tagNamesToAdd, function(tagName) { addTag(tagName, source); });
|
_.map(tagNamesToAdd, function(tagName) { addTag(tagName, source); });
|
||||||
$input.val(lastTagName);
|
$input.val(lastTagName);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addTag(tagName, source) {
|
function addTag(tagName, source) {
|
||||||
tagName = tagName.trim();
|
tagName = tagName.trim();
|
||||||
if (tagName.length === 0) {
|
if (tagName.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tagName.length > 64) {
|
if (tagName.length > 64) {
|
||||||
//showing alert inside keydown event leads to mysterious behaviors
|
//showing alert inside keydown event leads to mysterious behaviors
|
||||||
//in some browsers, hence the timeout
|
//in some browsers, hence the timeout
|
||||||
window.setTimeout(function() {
|
window.setTimeout(function() {
|
||||||
window.alert('Tag is too long.');
|
window.alert('Tag is too long.');
|
||||||
}, 10);
|
}, 10);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isTaggedWith(tagName)) {
|
if (isTaggedWith(tagName)) {
|
||||||
flashTagRed(tagName);
|
flashTagRed(tagName);
|
||||||
} else {
|
} else {
|
||||||
beforeTagAdded(tagName, source);
|
beforeTagAdded(tagName, source);
|
||||||
|
|
||||||
var exportedTag = getExportedTag(tagName);
|
var exportedTag = getExportedTag(tagName);
|
||||||
if (!exportedTag || !exportedTag.banned) {
|
if (!exportedTag || !exportedTag.banned) {
|
||||||
tags.push(tagName);
|
tags.push(tagName);
|
||||||
var $elem = createListElement(tagName);
|
var $elem = createListElement(tagName);
|
||||||
$tagList.append($elem);
|
$tagList.append($elem);
|
||||||
}
|
}
|
||||||
|
|
||||||
afterTagAdded(tagName, source);
|
afterTagAdded(tagName, source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function beforeTagRemoved(tagName) {
|
function beforeTagRemoved(tagName) {
|
||||||
if (typeof(options.beforeTagRemoved) === 'function') {
|
if (typeof(options.beforeTagRemoved) === 'function') {
|
||||||
options.beforeTagRemoved(tagName);
|
options.beforeTagRemoved(tagName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function afterTagRemoved(tagName) {
|
function afterTagRemoved(tagName) {
|
||||||
refreshShownSiblings();
|
refreshShownSiblings();
|
||||||
}
|
}
|
||||||
|
|
||||||
function beforeTagAdded(tagName, source) {
|
function beforeTagAdded(tagName, source) {
|
||||||
if (typeof(options.beforeTagAdded) === 'function') {
|
if (typeof(options.beforeTagAdded) === 'function') {
|
||||||
options.beforeTagAdded(tagName);
|
options.beforeTagAdded(tagName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function afterTagAdded(tagName, source) {
|
function afterTagAdded(tagName, source) {
|
||||||
if (source === SOURCE_IMPLICATIONS) {
|
if (source === SOURCE_IMPLICATIONS) {
|
||||||
flashTagYellow(tagName);
|
flashTagYellow(tagName);
|
||||||
} else if (source !== SOURCE_INITIAL_TEXT) {
|
} else if (source !== SOURCE_INITIAL_TEXT) {
|
||||||
var tag = getExportedTag(tagName);
|
var tag = getExportedTag(tagName);
|
||||||
if (tag) {
|
if (tag) {
|
||||||
_.each(tag.implications, function(impliedTagName) {
|
_.each(tag.implications, function(impliedTagName) {
|
||||||
if (!isTaggedWith(impliedTagName)) {
|
if (!isTaggedWith(impliedTagName)) {
|
||||||
addTag(impliedTagName, SOURCE_IMPLICATIONS);
|
addTag(impliedTagName, SOURCE_IMPLICATIONS);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (source !== SOURCE_IMPLICATIONS && source !== SOURCE_SUGGESTIONS) {
|
if (source !== SOURCE_IMPLICATIONS && source !== SOURCE_SUGGESTIONS) {
|
||||||
showOrHideSuggestions(tagName);
|
showOrHideSuggestions(tagName);
|
||||||
refreshShownSiblings();
|
refreshShownSiblings();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
flashTagGreen(tagName);
|
flashTagGreen(tagName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getExportedTag(tagName) {
|
function getExportedTag(tagName) {
|
||||||
return _.first(_.filter(
|
return _.first(_.filter(
|
||||||
tagList.getTags(),
|
tagList.getTags(),
|
||||||
function(t) {
|
function(t) {
|
||||||
return t.name.toLowerCase() === tagName.toLowerCase();
|
return t.name.toLowerCase() === tagName.toLowerCase();
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeTag(tagName) {
|
function removeTag(tagName) {
|
||||||
var oldTagNames = getTags();
|
var oldTagNames = getTags();
|
||||||
var newTagNames = _.without(oldTagNames, tagName);
|
var newTagNames = _.without(oldTagNames, tagName);
|
||||||
if (newTagNames.length !== oldTagNames.length) {
|
if (newTagNames.length !== oldTagNames.length) {
|
||||||
beforeTagRemoved(tagName);
|
beforeTagRemoved(tagName);
|
||||||
setTags(newTagNames);
|
setTags(newTagNames);
|
||||||
afterTagRemoved(tagName);
|
afterTagRemoved(tagName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function isTaggedWith(tagName) {
|
function isTaggedWith(tagName) {
|
||||||
var tagNames = _.map(getTags(), function(tagName) {
|
var tagNames = _.map(getTags(), function(tagName) {
|
||||||
return tagName.toLowerCase();
|
return tagName.toLowerCase();
|
||||||
});
|
});
|
||||||
return _.contains(tagNames, tagName.toLowerCase());
|
return _.contains(tagNames, tagName.toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeLastTag() {
|
function removeLastTag() {
|
||||||
removeTag(_.last(getTags()));
|
removeTag(_.last(getTags()));
|
||||||
}
|
}
|
||||||
|
|
||||||
function flashTagRed(tagName) {
|
function flashTagRed(tagName) {
|
||||||
flashTag(tagName, 'rgba(255, 200, 200, 1)');
|
flashTag(tagName, 'rgba(255, 200, 200, 1)');
|
||||||
}
|
}
|
||||||
|
|
||||||
function flashTagYellow(tagName) {
|
function flashTagYellow(tagName) {
|
||||||
flashTag(tagName, 'rgba(255, 255, 200, 1)');
|
flashTag(tagName, 'rgba(255, 255, 200, 1)');
|
||||||
}
|
}
|
||||||
|
|
||||||
function flashTagGreen(tagName) {
|
function flashTagGreen(tagName) {
|
||||||
flashTag(tagName, 'rgba(200, 255, 200, 1)');
|
flashTag(tagName, 'rgba(200, 255, 200, 1)');
|
||||||
}
|
}
|
||||||
|
|
||||||
function flashTag(tagName, color) {
|
function flashTag(tagName, color) {
|
||||||
var $elem = getListElement(tagName);
|
var $elem = getListElement(tagName);
|
||||||
$elem.css({backgroundColor: color});
|
$elem.css({backgroundColor: color});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getListElement(tagName) {
|
function getListElement(tagName) {
|
||||||
return $tagList.find('li[data-tag="' + tagName.toLowerCase() + '"]');
|
return $tagList.find('li[data-tag="' + tagName.toLowerCase() + '"]');
|
||||||
}
|
}
|
||||||
|
|
||||||
function setTags(newTagNames) {
|
function setTags(newTagNames) {
|
||||||
tags = newTagNames.slice();
|
tags = newTagNames.slice();
|
||||||
$tagList.empty();
|
$tagList.empty();
|
||||||
$underlyingInput.val(newTagNames.join(' '));
|
$underlyingInput.val(newTagNames.join(' '));
|
||||||
_.each(newTagNames, function(tagName) {
|
_.each(newTagNames, function(tagName) {
|
||||||
var $elem = createListElement(tagName);
|
var $elem = createListElement(tagName);
|
||||||
$tagList.append($elem);
|
$tagList.append($elem);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function createListElement(tagName) {
|
function createListElement(tagName) {
|
||||||
var $elem = jQuery('<li/>');
|
var $elem = jQuery('<li/>');
|
||||||
$elem.attr('data-tag', tagName.toLowerCase());
|
$elem.attr('data-tag', tagName.toLowerCase());
|
||||||
|
|
||||||
var $tagLink = jQuery('<a class="tag">');
|
var $tagLink = jQuery('<a class="tag">');
|
||||||
$tagLink.text(tagName + ' ' /* for easy copying */);
|
$tagLink.text(tagName + ' ' /* for easy copying */);
|
||||||
$tagLink.click(function(e) {
|
$tagLink.click(function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
showOrHideSiblings(tagName);
|
showOrHideSiblings(tagName);
|
||||||
showOrHideSuggestions(tagName);
|
showOrHideSuggestions(tagName);
|
||||||
});
|
});
|
||||||
$elem.append($tagLink);
|
$elem.append($tagLink);
|
||||||
|
|
||||||
var $deleteButton = jQuery('<a class="close"><i class="fa fa-remove"></i></a>');
|
var $deleteButton = jQuery('<a class="close"><i class="fa fa-remove"></i></a>');
|
||||||
$deleteButton.click(function(e) {
|
$deleteButton.click(function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
removeTag(tagName);
|
removeTag(tagName);
|
||||||
$input.focus();
|
$input.focus();
|
||||||
});
|
});
|
||||||
$elem.append($deleteButton);
|
$elem.append($deleteButton);
|
||||||
return $elem;
|
return $elem;
|
||||||
}
|
}
|
||||||
|
|
||||||
function showOrHideSuggestions(tagName) {
|
function showOrHideSuggestions(tagName) {
|
||||||
var tag = getExportedTag(tagName);
|
var tag = getExportedTag(tagName);
|
||||||
var suggestions = tag ? tag.suggestions : [];
|
var suggestions = tag ? tag.suggestions : [];
|
||||||
updateSuggestions($suggestions, suggestions);
|
updateSuggestions($suggestions, suggestions);
|
||||||
}
|
}
|
||||||
|
|
||||||
function showOrHideSiblings(tagName) {
|
function showOrHideSiblings(tagName) {
|
||||||
if ($siblings.data('lastTag') === tagName && $siblings.is(':visible')) {
|
if ($siblings.data('lastTag') === tagName && $siblings.is(':visible')) {
|
||||||
$siblings.slideUp('fast');
|
$siblings.slideUp('fast');
|
||||||
$siblings.data('lastTag', null);
|
$siblings.data('lastTag', null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
promise.wait(getSiblings(tagName), promise.make(function(resolve, reject) {
|
promise.wait(getSiblings(tagName), promise.make(function(resolve, reject) {
|
||||||
$siblings.slideUp('fast', resolve);
|
$siblings.slideUp('fast', resolve);
|
||||||
})).then(function(siblings) {
|
})).then(function(siblings) {
|
||||||
siblings = _.pluck(siblings, 'name');
|
siblings = _.pluck(siblings, 'name');
|
||||||
$siblings.data('lastTag', tagName);
|
$siblings.data('lastTag', tagName);
|
||||||
$siblings.data('siblings', siblings);
|
$siblings.data('siblings', siblings);
|
||||||
updateSuggestions($siblings, siblings);
|
updateSuggestions($siblings, siblings);
|
||||||
}).fail(function() {
|
}).fail(function() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function refreshShownSiblings() {
|
function refreshShownSiblings() {
|
||||||
updateSuggestions($siblings, $siblings.data('siblings'));
|
updateSuggestions($siblings, $siblings.data('siblings'));
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateSuggestions($target, suggestedTagNames) {
|
function updateSuggestions($target, suggestedTagNames) {
|
||||||
function filterSuggestions(sourceTagNames) {
|
function filterSuggestions(sourceTagNames) {
|
||||||
if (!sourceTagNames) {
|
if (!sourceTagNames) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
var tagNames = _.filter(sourceTagNames.slice(), function(tagName) {
|
var tagNames = _.filter(sourceTagNames.slice(), function(tagName) {
|
||||||
return !isTaggedWith(tagName);
|
return !isTaggedWith(tagName);
|
||||||
});
|
});
|
||||||
tagNames = tagNames.slice(0, 20);
|
tagNames = tagNames.slice(0, 20);
|
||||||
return tagNames;
|
return tagNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
function attachTagsToSuggestionList($list, tagNames) {
|
function attachTagsToSuggestionList($list, tagNames) {
|
||||||
$list.empty();
|
$list.empty();
|
||||||
_.each(tagNames, function(tagName) {
|
_.each(tagNames, function(tagName) {
|
||||||
var $li = jQuery('<li>');
|
var $li = jQuery('<li>');
|
||||||
var $a = jQuery('<a href="#/posts/query=' + tagName + '">');
|
var $a = jQuery('<a href="#/posts/query=' + tagName + '">');
|
||||||
$a.text(tagName);
|
$a.text(tagName);
|
||||||
$a.click(function(e) {
|
$a.click(function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
addTag(tagName, SOURCE_SUGGESTIONS);
|
addTag(tagName, SOURCE_SUGGESTIONS);
|
||||||
$li.fadeOut('fast', function() {
|
$li.fadeOut('fast', function() {
|
||||||
$li.remove();
|
$li.remove();
|
||||||
if ($list.children().length === 0) {
|
if ($list.children().length === 0) {
|
||||||
$list.parent('div').slideUp('fast');
|
$list.parent('div').slideUp('fast');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
$li.append($a);
|
$li.append($a);
|
||||||
$list.append($li);
|
$list.append($li);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var suggestions = filterSuggestions(suggestedTagNames);
|
var suggestions = filterSuggestions(suggestedTagNames);
|
||||||
if (suggestions.length > 0) {
|
if (suggestions.length > 0) {
|
||||||
attachTagsToSuggestionList($target.find('ul'), suggestions);
|
attachTagsToSuggestionList($target.find('ul'), suggestions);
|
||||||
$target.slideDown('fast');
|
$target.slideDown('fast');
|
||||||
} else {
|
} else {
|
||||||
$target.slideUp('fast');
|
$target.slideUp('fast');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSiblings(tagName) {
|
function getSiblings(tagName) {
|
||||||
return promise.make(function(resolve, reject) {
|
return promise.make(function(resolve, reject) {
|
||||||
promise.wait(api.get('/tags/' + tagName + '/siblings'))
|
promise.wait(api.get('/tags/' + tagName + '/siblings'))
|
||||||
.then(function(response) {
|
.then(function(response) {
|
||||||
resolve(response.json.data);
|
resolve(response.json.data);
|
||||||
}).fail(function() {
|
}).fail(function() {
|
||||||
reject();
|
reject();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTags() {
|
function getTags() {
|
||||||
return tags;
|
return tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
function focus() {
|
function focus() {
|
||||||
$input.focus();
|
$input.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
function hideSuggestions() {
|
function hideSuggestions() {
|
||||||
$siblings.hide();
|
$siblings.hide();
|
||||||
$suggestions.hide();
|
$suggestions.hide();
|
||||||
$siblings.data('siblings', []);
|
$siblings.data('siblings', []);
|
||||||
}
|
}
|
||||||
|
|
||||||
_.extend(options, {
|
_.extend(options, {
|
||||||
setTags: setTags,
|
setTags: setTags,
|
||||||
getTags: getTags,
|
getTags: getTags,
|
||||||
removeTag: removeTag,
|
removeTag: removeTag,
|
||||||
addTag: addTag,
|
addTag: addTag,
|
||||||
focus: focus,
|
focus: focus,
|
||||||
hideSuggestions: hideSuggestions,
|
hideSuggestions: hideSuggestions,
|
||||||
});
|
});
|
||||||
return options;
|
return options;
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,53 +2,53 @@ var App = App || {};
|
||||||
|
|
||||||
App.DI = (function() {
|
App.DI = (function() {
|
||||||
|
|
||||||
var factories = {};
|
var factories = {};
|
||||||
var instances = {};
|
var instances = {};
|
||||||
|
|
||||||
function get(key) {
|
function get(key) {
|
||||||
var instance = instances[key];
|
var instance = instances[key];
|
||||||
if (!instance) {
|
if (!instance) {
|
||||||
var factory = factories[key];
|
var factory = factories[key];
|
||||||
if (!factory) {
|
if (!factory) {
|
||||||
throw new Error('Unregistered key: ' + key);
|
throw new Error('Unregistered key: ' + key);
|
||||||
}
|
}
|
||||||
var objectInitializer = factory.initializer;
|
var objectInitializer = factory.initializer;
|
||||||
var singleton = factory.singleton;
|
var singleton = factory.singleton;
|
||||||
var deps = resolveDependencies(objectInitializer, factory.dependencies);
|
var deps = resolveDependencies(objectInitializer, factory.dependencies);
|
||||||
instance = {};
|
instance = {};
|
||||||
instance = objectInitializer.apply(instance, deps);
|
instance = objectInitializer.apply(instance, deps);
|
||||||
if (singleton) {
|
if (singleton) {
|
||||||
instances[key] = instance;
|
instances[key] = instance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveDependencies(objectIntializer, depKeys) {
|
function resolveDependencies(objectIntializer, depKeys) {
|
||||||
var deps = [];
|
var deps = [];
|
||||||
for (var i = 0; i < depKeys.length; i ++) {
|
for (var i = 0; i < depKeys.length; i ++) {
|
||||||
deps[i] = get(depKeys[i]);
|
deps[i] = get(depKeys[i]);
|
||||||
}
|
}
|
||||||
return deps;
|
return deps;
|
||||||
}
|
}
|
||||||
|
|
||||||
function register(key, dependencies, objectInitializer) {
|
function register(key, dependencies, objectInitializer) {
|
||||||
factories[key] = {initializer: objectInitializer, singleton: false, dependencies: dependencies};
|
factories[key] = {initializer: objectInitializer, singleton: false, dependencies: dependencies};
|
||||||
}
|
}
|
||||||
|
|
||||||
function registerSingleton(key, dependencies, objectInitializer) {
|
function registerSingleton(key, dependencies, objectInitializer) {
|
||||||
factories[key] = {initializer: objectInitializer, singleton: true, dependencies: dependencies};
|
factories[key] = {initializer: objectInitializer, singleton: true, dependencies: dependencies};
|
||||||
}
|
}
|
||||||
|
|
||||||
function registerManual(key, objectInitializer) {
|
function registerManual(key, objectInitializer) {
|
||||||
instances[key] = objectInitializer();
|
instances[key] = objectInitializer();
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
get: get,
|
get: get,
|
||||||
register: register,
|
register: register,
|
||||||
registerManual: registerManual,
|
registerManual: registerManual,
|
||||||
registerSingleton: registerSingleton,
|
registerSingleton: registerSingleton,
|
||||||
};
|
};
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -2,60 +2,60 @@ var App = App || {};
|
||||||
|
|
||||||
App.Keyboard = function(jQuery, mousetrap, browsingSettings) {
|
App.Keyboard = function(jQuery, mousetrap, browsingSettings) {
|
||||||
|
|
||||||
var enabled = browsingSettings.getSettings().keyboardShortcuts;
|
var enabled = browsingSettings.getSettings().keyboardShortcuts;
|
||||||
var oldStopCallback = mousetrap.stopCallback;
|
var oldStopCallback = mousetrap.stopCallback;
|
||||||
mousetrap.stopCallback = function(e, element, combo, sequence) {
|
mousetrap.stopCallback = function(e, element, combo, sequence) {
|
||||||
if (combo.indexOf('ctrl') === -1 && e.ctrlKey) {
|
if (combo.indexOf('ctrl') === -1 && e.ctrlKey) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (combo.indexOf('alt') === -1 && e.altKey) {
|
if (combo.indexOf('alt') === -1 && e.altKey) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (combo.indexOf('ctrl') !== -1) {
|
if (combo.indexOf('ctrl') !== -1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
var $focused = jQuery(':focus').eq(0);
|
var $focused = jQuery(':focus').eq(0);
|
||||||
if ($focused.length) {
|
if ($focused.length) {
|
||||||
if ($focused.prop('tagName').match(/embed|object/i)) {
|
if ($focused.prop('tagName').match(/embed|object/i)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if ($focused.prop('tagName').toLowerCase() === 'input' &&
|
if ($focused.prop('tagName').toLowerCase() === 'input' &&
|
||||||
$focused.attr('type').match(/checkbox|radio/i)) {
|
$focused.attr('type').match(/checkbox|radio/i)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return oldStopCallback.apply(mousetrap, arguments);
|
return oldStopCallback.apply(mousetrap, arguments);
|
||||||
};
|
};
|
||||||
|
|
||||||
function keyup(key, callback) {
|
function keyup(key, callback) {
|
||||||
unbind(key);
|
unbind(key);
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
mousetrap.bind(key, callback, 'keyup');
|
mousetrap.bind(key, callback, 'keyup');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function keydown(key, callback) {
|
function keydown(key, callback) {
|
||||||
unbind(key);
|
unbind(key);
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
mousetrap.bind(key, callback);
|
mousetrap.bind(key, callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function reset() {
|
function reset() {
|
||||||
mousetrap.reset();
|
mousetrap.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
function unbind(key) {
|
function unbind(key) {
|
||||||
mousetrap.unbind(key, 'keyup');
|
mousetrap.unbind(key, 'keyup');
|
||||||
mousetrap.unbind(key);
|
mousetrap.unbind(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
keydown: keydown,
|
keydown: keydown,
|
||||||
keyup: keyup,
|
keyup: keyup,
|
||||||
reset: reset,
|
reset: reset,
|
||||||
unbind: unbind,
|
unbind: unbind,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
App.DI.register('keyboard', ['jQuery', 'mousetrap', 'browsingSettings'], App.Keyboard);
|
App.DI.register('keyboard', ['jQuery', 'mousetrap', 'browsingSettings'], App.Keyboard);
|
||||||
|
|
|
@ -1,142 +1,142 @@
|
||||||
var App = App || {};
|
var App = App || {};
|
||||||
|
|
||||||
App.Pager = function(
|
App.Pager = function(
|
||||||
_,
|
_,
|
||||||
promise,
|
promise,
|
||||||
api) {
|
api) {
|
||||||
|
|
||||||
var totalPages;
|
var totalPages;
|
||||||
var pageNumber;
|
var pageNumber;
|
||||||
var searchParams;
|
var searchParams;
|
||||||
var url;
|
var url;
|
||||||
var cache = {};
|
var cache = {};
|
||||||
|
|
||||||
function init(args) {
|
function init(args) {
|
||||||
url = args.url;
|
url = args.url;
|
||||||
|
|
||||||
setSearchParams(args.searchParams);
|
setSearchParams(args.searchParams);
|
||||||
if (typeof(args.page) !== 'undefined') {
|
if (typeof(args.page) !== 'undefined') {
|
||||||
setPage(args.page);
|
setPage(args.page);
|
||||||
} else {
|
} else {
|
||||||
setPage(1);
|
setPage(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPage() {
|
function getPage() {
|
||||||
return pageNumber;
|
return pageNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTotalPages() {
|
function getTotalPages() {
|
||||||
return totalPages;
|
return totalPages;
|
||||||
}
|
}
|
||||||
|
|
||||||
function prevPage() {
|
function prevPage() {
|
||||||
if (pageNumber > 1) {
|
if (pageNumber > 1) {
|
||||||
setPage(pageNumber - 1);
|
setPage(pageNumber - 1);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function nextPage() {
|
function nextPage() {
|
||||||
if (pageNumber < totalPages) {
|
if (pageNumber < totalPages) {
|
||||||
setPage(pageNumber + 1);
|
setPage(pageNumber + 1);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setPage(newPageNumber) {
|
function setPage(newPageNumber) {
|
||||||
pageNumber = parseInt(newPageNumber);
|
pageNumber = parseInt(newPageNumber);
|
||||||
if (!pageNumber || isNaN(pageNumber)) {
|
if (!pageNumber || isNaN(pageNumber)) {
|
||||||
throw new Error('Trying to set page to a non-number (' + newPageNumber + ')');
|
throw new Error('Trying to set page to a non-number (' + newPageNumber + ')');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSearchParams() {
|
function getSearchParams() {
|
||||||
return searchParams;
|
return searchParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setSearchParams(newSearchParams) {
|
function setSearchParams(newSearchParams) {
|
||||||
setPage(1);
|
setPage(1);
|
||||||
searchParams = _.extend({}, newSearchParams);
|
searchParams = _.extend({}, newSearchParams);
|
||||||
delete searchParams.page;
|
delete searchParams.page;
|
||||||
}
|
}
|
||||||
|
|
||||||
function retrieve() {
|
function retrieve() {
|
||||||
return promise.make(function(resolve, reject) {
|
return promise.make(function(resolve, reject) {
|
||||||
promise.wait(api.get(url, _.extend({}, searchParams, {page: pageNumber})))
|
promise.wait(api.get(url, _.extend({}, searchParams, {page: pageNumber})))
|
||||||
.then(function(response) {
|
.then(function(response) {
|
||||||
var pageSize = response.json.pageSize;
|
var pageSize = response.json.pageSize;
|
||||||
var totalRecords = response.json.totalRecords;
|
var totalRecords = response.json.totalRecords;
|
||||||
totalPages = Math.ceil(totalRecords / pageSize);
|
totalPages = Math.ceil(totalRecords / pageSize);
|
||||||
|
|
||||||
resolve({
|
resolve({
|
||||||
entities: response.json.data,
|
entities: response.json.data,
|
||||||
totalRecords: totalRecords,
|
totalRecords: totalRecords,
|
||||||
totalPages: totalPages});
|
totalPages: totalPages});
|
||||||
|
|
||||||
}).fail(function(response) {
|
}).fail(function(response) {
|
||||||
reject(response);
|
reject(response);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function retrieveCached() {
|
function retrieveCached() {
|
||||||
return promise.make(function(resolve, reject) {
|
return promise.make(function(resolve, reject) {
|
||||||
var cacheKey = JSON.stringify(_.extend({}, searchParams, {url: url, page: getPage()}));
|
var cacheKey = JSON.stringify(_.extend({}, searchParams, {url: url, page: getPage()}));
|
||||||
if (cacheKey in cache) {
|
if (cacheKey in cache) {
|
||||||
resolve.apply(this, cache[cacheKey]);
|
resolve.apply(this, cache[cacheKey]);
|
||||||
} else {
|
} else {
|
||||||
promise.wait(retrieve())
|
promise.wait(retrieve())
|
||||||
.then(function() {
|
.then(function() {
|
||||||
cache[cacheKey] = arguments;
|
cache[cacheKey] = arguments;
|
||||||
resolve.apply(this, arguments);
|
resolve.apply(this, arguments);
|
||||||
}).fail(function() {
|
}).fail(function() {
|
||||||
reject.apply(this, arguments);
|
reject.apply(this, arguments);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetCache() {
|
function resetCache() {
|
||||||
cache = {};
|
cache = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
function getVisiblePages() {
|
function getVisiblePages() {
|
||||||
var pages = [1, totalPages || 1];
|
var pages = [1, totalPages || 1];
|
||||||
var pagesAroundCurrent = 2;
|
var pagesAroundCurrent = 2;
|
||||||
for (var i = -pagesAroundCurrent; i <= pagesAroundCurrent; i ++) {
|
for (var i = -pagesAroundCurrent; i <= pagesAroundCurrent; i ++) {
|
||||||
if (pageNumber + i >= 1 && pageNumber + i <= totalPages) {
|
if (pageNumber + i >= 1 && pageNumber + i <= totalPages) {
|
||||||
pages.push(pageNumber + i);
|
pages.push(pageNumber + i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (pageNumber - pagesAroundCurrent - 1 === 2) {
|
if (pageNumber - pagesAroundCurrent - 1 === 2) {
|
||||||
pages.push(2);
|
pages.push(2);
|
||||||
}
|
}
|
||||||
if (pageNumber + pagesAroundCurrent + 1 === totalPages - 1) {
|
if (pageNumber + pagesAroundCurrent + 1 === totalPages - 1) {
|
||||||
pages.push(totalPages - 1);
|
pages.push(totalPages - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return pages.sort(function(a, b) { return a - b; }).filter(function(item, pos) {
|
return pages.sort(function(a, b) { return a - b; }).filter(function(item, pos) {
|
||||||
return !pos || item !== pages[pos - 1];
|
return !pos || item !== pages[pos - 1];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
init: init,
|
init: init,
|
||||||
getPage: getPage,
|
getPage: getPage,
|
||||||
getTotalPages: getTotalPages,
|
getTotalPages: getTotalPages,
|
||||||
prevPage: prevPage,
|
prevPage: prevPage,
|
||||||
nextPage: nextPage,
|
nextPage: nextPage,
|
||||||
setPage: setPage,
|
setPage: setPage,
|
||||||
getSearchParams: getSearchParams,
|
getSearchParams: getSearchParams,
|
||||||
setSearchParams: setSearchParams,
|
setSearchParams: setSearchParams,
|
||||||
retrieve: retrieve,
|
retrieve: retrieve,
|
||||||
retrieveCached: retrieveCached,
|
retrieveCached: retrieveCached,
|
||||||
getVisiblePages: getVisiblePages,
|
getVisiblePages: getVisiblePages,
|
||||||
resetCache: resetCache,
|
resetCache: resetCache,
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,53 +2,53 @@ var App = App || {};
|
||||||
|
|
||||||
App.PresenterManager = function(jQuery, promise, topNavigationPresenter, keyboard) {
|
App.PresenterManager = function(jQuery, promise, topNavigationPresenter, keyboard) {
|
||||||
|
|
||||||
var lastContentPresenter = null;
|
var lastContentPresenter = null;
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
return promise.make(function(resolve, reject) {
|
return promise.make(function(resolve, reject) {
|
||||||
initPresenter(topNavigationPresenter, [], resolve);
|
initPresenter(topNavigationPresenter, [], resolve);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function initPresenter(presenter, args, loaded) {
|
function initPresenter(presenter, args, loaded) {
|
||||||
presenter.init.call(presenter, args, loaded);
|
presenter.init.call(presenter, args, loaded);
|
||||||
}
|
}
|
||||||
|
|
||||||
function switchContentPresenter(presenter, args) {
|
function switchContentPresenter(presenter, args) {
|
||||||
if (lastContentPresenter === null || lastContentPresenter.name !== presenter.name) {
|
if (lastContentPresenter === null || lastContentPresenter.name !== presenter.name) {
|
||||||
if (lastContentPresenter !== null && lastContentPresenter.deinit) {
|
if (lastContentPresenter !== null && lastContentPresenter.deinit) {
|
||||||
lastContentPresenter.deinit();
|
lastContentPresenter.deinit();
|
||||||
}
|
}
|
||||||
keyboard.reset();
|
keyboard.reset();
|
||||||
topNavigationPresenter.changeTitle(null);
|
topNavigationPresenter.changeTitle(null);
|
||||||
topNavigationPresenter.focus();
|
topNavigationPresenter.focus();
|
||||||
presenter.init.call(presenter, args, function() {});
|
presenter.init.call(presenter, args, function() {});
|
||||||
lastContentPresenter = presenter;
|
lastContentPresenter = presenter;
|
||||||
} else if (lastContentPresenter.reinit) {
|
} else if (lastContentPresenter.reinit) {
|
||||||
lastContentPresenter.reinit.call(lastContentPresenter, args, function() {});
|
lastContentPresenter.reinit.call(lastContentPresenter, args, function() {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function initPresenters(options, loaded) {
|
function initPresenters(options, loaded) {
|
||||||
var count = 0;
|
var count = 0;
|
||||||
var subPresenterLoaded = function() {
|
var subPresenterLoaded = function() {
|
||||||
count ++;
|
count ++;
|
||||||
if (count === options.length) {
|
if (count === options.length) {
|
||||||
loaded();
|
loaded();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
for (var i = 0; i < options.length; i ++) {
|
for (var i = 0; i < options.length; i ++) {
|
||||||
initPresenter(options[i][0], options[i][1], subPresenterLoaded);
|
initPresenter(options[i][0], options[i][1], subPresenterLoaded);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
init: init,
|
init: init,
|
||||||
initPresenter: initPresenter,
|
initPresenter: initPresenter,
|
||||||
initPresenters: initPresenters,
|
initPresenters: initPresenters,
|
||||||
switchContentPresenter: switchContentPresenter,
|
switchContentPresenter: switchContentPresenter,
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,230 +2,230 @@ var App = App || {};
|
||||||
App.Presenters = App.Presenters || {};
|
App.Presenters = App.Presenters || {};
|
||||||
|
|
||||||
App.Presenters.CommentListPresenter = function(
|
App.Presenters.CommentListPresenter = function(
|
||||||
_,
|
_,
|
||||||
jQuery,
|
jQuery,
|
||||||
util,
|
util,
|
||||||
promise,
|
promise,
|
||||||
api,
|
api,
|
||||||
auth,
|
auth,
|
||||||
topNavigationPresenter,
|
topNavigationPresenter,
|
||||||
messagePresenter) {
|
messagePresenter) {
|
||||||
|
|
||||||
var $el;
|
var $el;
|
||||||
var privileges;
|
var privileges;
|
||||||
var templates = {};
|
var templates = {};
|
||||||
|
|
||||||
var post;
|
var post;
|
||||||
var comments = [];
|
var comments = [];
|
||||||
|
|
||||||
function init(params, loaded) {
|
function init(params, loaded) {
|
||||||
$el = params.$target;
|
$el = params.$target;
|
||||||
post = params.post;
|
post = params.post;
|
||||||
comments = params.comments || [];
|
comments = params.comments || [];
|
||||||
|
|
||||||
privileges = {
|
privileges = {
|
||||||
canListComments: auth.hasPrivilege(auth.privileges.listComments),
|
canListComments: auth.hasPrivilege(auth.privileges.listComments),
|
||||||
canAddComments: auth.hasPrivilege(auth.privileges.addComments),
|
canAddComments: auth.hasPrivilege(auth.privileges.addComments),
|
||||||
canEditOwnComments: auth.hasPrivilege(auth.privileges.editOwnComments),
|
canEditOwnComments: auth.hasPrivilege(auth.privileges.editOwnComments),
|
||||||
canEditAllComments: auth.hasPrivilege(auth.privileges.editAllComments),
|
canEditAllComments: auth.hasPrivilege(auth.privileges.editAllComments),
|
||||||
canDeleteOwnComments: auth.hasPrivilege(auth.privileges.deleteOwnComments),
|
canDeleteOwnComments: auth.hasPrivilege(auth.privileges.deleteOwnComments),
|
||||||
canDeleteAllComments: auth.hasPrivilege(auth.privileges.deleteAllComments),
|
canDeleteAllComments: auth.hasPrivilege(auth.privileges.deleteAllComments),
|
||||||
canViewUsers: auth.hasPrivilege(auth.privileges.viewUsers),
|
canViewUsers: auth.hasPrivilege(auth.privileges.viewUsers),
|
||||||
canViewPosts: auth.hasPrivilege(auth.privileges.viewPosts),
|
canViewPosts: auth.hasPrivilege(auth.privileges.viewPosts),
|
||||||
};
|
};
|
||||||
|
|
||||||
promise.wait(
|
promise.wait(
|
||||||
util.promiseTemplate('comment-list'),
|
util.promiseTemplate('comment-list'),
|
||||||
util.promiseTemplate('comment-list-item'),
|
util.promiseTemplate('comment-list-item'),
|
||||||
util.promiseTemplate('comment-form'))
|
util.promiseTemplate('comment-form'))
|
||||||
.then(function(
|
.then(function(
|
||||||
commentListTemplate,
|
commentListTemplate,
|
||||||
commentListItemTemplate,
|
commentListItemTemplate,
|
||||||
commentFormTemplate)
|
commentFormTemplate)
|
||||||
{
|
{
|
||||||
templates.commentList = commentListTemplate;
|
templates.commentList = commentListTemplate;
|
||||||
templates.commentListItem = commentListItemTemplate;
|
templates.commentListItem = commentListItemTemplate;
|
||||||
templates.commentForm = commentFormTemplate;
|
templates.commentForm = commentFormTemplate;
|
||||||
|
|
||||||
render();
|
render();
|
||||||
loaded();
|
loaded();
|
||||||
|
|
||||||
if (comments.length === 0) {
|
if (comments.length === 0) {
|
||||||
promise.wait(api.get('/comments/' + params.post.id))
|
promise.wait(api.get('/comments/' + params.post.id))
|
||||||
.then(function(response) {
|
.then(function(response) {
|
||||||
comments = response.json.data;
|
comments = response.json.data;
|
||||||
render();
|
render();
|
||||||
}).fail(function() {
|
}).fail(function() {
|
||||||
console.log(arguments);
|
console.log(arguments);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.fail(function() {
|
.fail(function() {
|
||||||
console.log(arguments);
|
console.log(arguments);
|
||||||
loaded();
|
loaded();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
$el.html(templates.commentList(
|
$el.html(templates.commentList(
|
||||||
_.extend(
|
_.extend(
|
||||||
{
|
{
|
||||||
commentListItemTemplate: templates.commentListItem,
|
commentListItemTemplate: templates.commentListItem,
|
||||||
commentFormTemplate: templates.commentForm,
|
commentFormTemplate: templates.commentForm,
|
||||||
util: util,
|
util: util,
|
||||||
comments: comments,
|
comments: comments,
|
||||||
post: post,
|
post: post,
|
||||||
},
|
},
|
||||||
privileges)));
|
privileges)));
|
||||||
|
|
||||||
$el.find('.comment-add form button[type=submit]').click(function(e) { commentFormSubmitted(e, null); });
|
$el.find('.comment-add form button[type=submit]').click(function(e) { commentFormSubmitted(e, null); });
|
||||||
renderComments(comments);
|
renderComments(comments);
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderComments(comments) {
|
function renderComments(comments) {
|
||||||
var $target = $el.find('.comments');
|
var $target = $el.find('.comments');
|
||||||
var $targetList = $el.find('ul');
|
var $targetList = $el.find('ul');
|
||||||
|
|
||||||
if (comments.length > 0) {
|
if (comments.length > 0) {
|
||||||
$target.show();
|
$target.show();
|
||||||
} else {
|
} else {
|
||||||
$target.hide();
|
$target.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
$targetList.empty();
|
$targetList.empty();
|
||||||
_.each(comments, function(comment) {
|
_.each(comments, function(comment) {
|
||||||
renderComment($targetList, comment);
|
renderComment($targetList, comment);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderComment($targetList, comment) {
|
function renderComment($targetList, comment) {
|
||||||
var $item = jQuery('<li>' + templates.commentListItem({
|
var $item = jQuery('<li>' + templates.commentListItem({
|
||||||
comment: comment,
|
comment: comment,
|
||||||
util: util,
|
util: util,
|
||||||
canVote: auth.isLoggedIn(),
|
canVote: auth.isLoggedIn(),
|
||||||
canEditComment: auth.isLoggedIn(comment.user.name) ? privileges.canEditOwnComments : privileges.canEditAllComments,
|
canEditComment: auth.isLoggedIn(comment.user.name) ? privileges.canEditOwnComments : privileges.canEditAllComments,
|
||||||
canDeleteComment: auth.isLoggedIn(comment.user.name) ? privileges.canDeleteOwnComments : privileges.canDeleteAllComments,
|
canDeleteComment: auth.isLoggedIn(comment.user.name) ? privileges.canDeleteOwnComments : privileges.canDeleteAllComments,
|
||||||
canViewUsers: privileges.canViewUsers,
|
canViewUsers: privileges.canViewUsers,
|
||||||
canViewPosts: privileges.canViewPosts,
|
canViewPosts: privileges.canViewPosts,
|
||||||
}) + '</li>');
|
}) + '</li>');
|
||||||
util.loadImagesNicely($item.find('img'));
|
util.loadImagesNicely($item.find('img'));
|
||||||
$targetList.append($item);
|
$targetList.append($item);
|
||||||
|
|
||||||
$item.find('a.edit').click(function(e) {
|
$item.find('a.edit').click(function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
editCommentStart($item, comment);
|
editCommentStart($item, comment);
|
||||||
});
|
});
|
||||||
|
|
||||||
$item.find('a.delete').click(function(e) {
|
$item.find('a.delete').click(function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
deleteComment(comment);
|
deleteComment(comment);
|
||||||
});
|
});
|
||||||
|
|
||||||
$item.find('a.score-up').click(function(e) {
|
$item.find('a.score-up').click(function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
score(comment, jQuery(this).hasClass('active') ? 0 : 1);
|
score(comment, jQuery(this).hasClass('active') ? 0 : 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
$item.find('a.score-down').click(function(e) {
|
$item.find('a.score-down').click(function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
score(comment, jQuery(this).hasClass('active') ? 0 : -1);
|
score(comment, jQuery(this).hasClass('active') ? 0 : -1);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function commentFormSubmitted(e, comment) {
|
function commentFormSubmitted(e, comment) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var $button = jQuery(e.target);
|
var $button = jQuery(e.target);
|
||||||
var $form = $button.parents('form');
|
var $form = $button.parents('form');
|
||||||
var sender = $button.val();
|
var sender = $button.val();
|
||||||
if (sender === 'preview') {
|
if (sender === 'preview') {
|
||||||
previewComment($form);
|
previewComment($form);
|
||||||
} else {
|
} else {
|
||||||
submitComment($form, comment);
|
submitComment($form, comment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function previewComment($form) {
|
function previewComment($form) {
|
||||||
var $preview = $form.find('.preview');
|
var $preview = $form.find('.preview');
|
||||||
$preview.slideUp('fast', function() {
|
$preview.slideUp('fast', function() {
|
||||||
$preview.html(util.formatMarkdown($form.find('textarea').val()));
|
$preview.html(util.formatMarkdown($form.find('textarea').val()));
|
||||||
$preview.slideDown('fast');
|
$preview.slideDown('fast');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateComment(comment) {
|
function updateComment(comment) {
|
||||||
comments = _.map(comments, function(c) { return c.id === comment.id ? comment : c; });
|
comments = _.map(comments, function(c) { return c.id === comment.id ? comment : c; });
|
||||||
render();
|
render();
|
||||||
}
|
}
|
||||||
|
|
||||||
function addComment(comment) {
|
function addComment(comment) {
|
||||||
comments.push(comment);
|
comments.push(comment);
|
||||||
render();
|
render();
|
||||||
}
|
}
|
||||||
|
|
||||||
function submitComment($form, commentToEdit) {
|
function submitComment($form, commentToEdit) {
|
||||||
$form.find('.preview').slideUp();
|
$form.find('.preview').slideUp();
|
||||||
var $textarea = $form.find('textarea');
|
var $textarea = $form.find('textarea');
|
||||||
|
|
||||||
var data = {text: $textarea.val()};
|
var data = {text: $textarea.val()};
|
||||||
var p;
|
var p;
|
||||||
if (commentToEdit) {
|
if (commentToEdit) {
|
||||||
p = promise.wait(api.put('/comments/' + commentToEdit.id, data));
|
p = promise.wait(api.put('/comments/' + commentToEdit.id, data));
|
||||||
} else {
|
} else {
|
||||||
p = promise.wait(api.post('/comments/' + post.id, data));
|
p = promise.wait(api.post('/comments/' + post.id, data));
|
||||||
}
|
}
|
||||||
|
|
||||||
p.then(function(response) {
|
p.then(function(response) {
|
||||||
$textarea.val('');
|
$textarea.val('');
|
||||||
var comment = response.json;
|
var comment = response.json;
|
||||||
|
|
||||||
if (commentToEdit) {
|
if (commentToEdit) {
|
||||||
$form.slideUp(function() {
|
$form.slideUp(function() {
|
||||||
$form.remove();
|
$form.remove();
|
||||||
});
|
});
|
||||||
updateComment(comment);
|
updateComment(comment);
|
||||||
} else {
|
} else {
|
||||||
addComment(comment);
|
addComment(comment);
|
||||||
}
|
}
|
||||||
}).fail(showGenericError);
|
}).fail(showGenericError);
|
||||||
}
|
}
|
||||||
|
|
||||||
function editCommentStart($item, comment) {
|
function editCommentStart($item, comment) {
|
||||||
if ($item.find('.comment-form').length > 0) {
|
if ($item.find('.comment-form').length > 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var $form = jQuery(templates.commentForm({title: 'Edit comment', text: comment.text}));
|
var $form = jQuery(templates.commentForm({title: 'Edit comment', text: comment.text}));
|
||||||
$item.find('.body').append($form);
|
$item.find('.body').append($form);
|
||||||
$item.find('form button[type=submit]').click(function(e) { commentFormSubmitted(e, comment); });
|
$item.find('form button[type=submit]').click(function(e) { commentFormSubmitted(e, comment); });
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteComment(comment) {
|
function deleteComment(comment) {
|
||||||
if (!window.confirm('Are you sure you want to delete this comment?')) {
|
if (!window.confirm('Are you sure you want to delete this comment?')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
promise.wait(api.delete('/comments/' + comment.id))
|
promise.wait(api.delete('/comments/' + comment.id))
|
||||||
.then(function(response) {
|
.then(function(response) {
|
||||||
comments = _.filter(comments, function(c) { return c.id !== comment.id; });
|
comments = _.filter(comments, function(c) { return c.id !== comment.id; });
|
||||||
renderComments(comments);
|
renderComments(comments);
|
||||||
}).fail(showGenericError);
|
}).fail(showGenericError);
|
||||||
}
|
}
|
||||||
|
|
||||||
function score(comment, scoreValue) {
|
function score(comment, scoreValue) {
|
||||||
promise.wait(api.post('/comments/' + comment.id + '/score', {score: scoreValue}))
|
promise.wait(api.post('/comments/' + comment.id + '/score', {score: scoreValue}))
|
||||||
.then(function(response) {
|
.then(function(response) {
|
||||||
comment.score = parseInt(response.json.score);
|
comment.score = parseInt(response.json.score);
|
||||||
comment.ownScore = parseInt(response.json.ownScore);
|
comment.ownScore = parseInt(response.json.ownScore);
|
||||||
updateComment(comment);
|
updateComment(comment);
|
||||||
}).fail(showGenericError);
|
}).fail(showGenericError);
|
||||||
}
|
}
|
||||||
|
|
||||||
function showGenericError(response) {
|
function showGenericError(response) {
|
||||||
window.alert(response.json && response.json.error || response);
|
window.alert(response.json && response.json.error || response);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
init: init,
|
init: init,
|
||||||
render: render,
|
render: render,
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,103 +2,103 @@ var App = App || {};
|
||||||
App.Presenters = App.Presenters || {};
|
App.Presenters = App.Presenters || {};
|
||||||
|
|
||||||
App.Presenters.GlobalCommentListPresenter = function(
|
App.Presenters.GlobalCommentListPresenter = function(
|
||||||
_,
|
_,
|
||||||
jQuery,
|
jQuery,
|
||||||
util,
|
util,
|
||||||
auth,
|
auth,
|
||||||
promise,
|
promise,
|
||||||
pagerPresenter,
|
pagerPresenter,
|
||||||
topNavigationPresenter) {
|
topNavigationPresenter) {
|
||||||
|
|
||||||
var $el;
|
var $el;
|
||||||
var privileges;
|
var privileges;
|
||||||
var templates = {};
|
var templates = {};
|
||||||
|
|
||||||
function init(params, loaded) {
|
function init(params, loaded) {
|
||||||
$el = jQuery('#content');
|
$el = jQuery('#content');
|
||||||
topNavigationPresenter.select('comments');
|
topNavigationPresenter.select('comments');
|
||||||
|
|
||||||
privileges = {
|
privileges = {
|
||||||
canViewPosts: auth.hasPrivilege(auth.privileges.viewPosts),
|
canViewPosts: auth.hasPrivilege(auth.privileges.viewPosts),
|
||||||
};
|
};
|
||||||
|
|
||||||
promise.wait(
|
promise.wait(
|
||||||
util.promiseTemplate('global-comment-list'),
|
util.promiseTemplate('global-comment-list'),
|
||||||
util.promiseTemplate('global-comment-list-item'),
|
util.promiseTemplate('global-comment-list-item'),
|
||||||
util.promiseTemplate('post-list-item'))
|
util.promiseTemplate('post-list-item'))
|
||||||
.then(function(listTemplate, listItemTemplate, postTemplate) {
|
.then(function(listTemplate, listItemTemplate, postTemplate) {
|
||||||
templates.list = listTemplate;
|
templates.list = listTemplate;
|
||||||
templates.listItem = listItemTemplate;
|
templates.listItem = listItemTemplate;
|
||||||
templates.post = postTemplate;
|
templates.post = postTemplate;
|
||||||
|
|
||||||
render();
|
render();
|
||||||
loaded();
|
loaded();
|
||||||
|
|
||||||
pagerPresenter.init({
|
pagerPresenter.init({
|
||||||
baseUri: '#/comments',
|
baseUri: '#/comments',
|
||||||
backendUri: '/comments',
|
backendUri: '/comments',
|
||||||
$target: $el.find('.pagination-target'),
|
$target: $el.find('.pagination-target'),
|
||||||
updateCallback: function($page, data) {
|
updateCallback: function($page, data) {
|
||||||
renderComments($page, data.entities);
|
renderComments($page, data.entities);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
function() {
|
function() {
|
||||||
reinit(params, function() {});
|
reinit(params, function() {});
|
||||||
});
|
});
|
||||||
}).fail(function() {
|
}).fail(function() {
|
||||||
console.log(arguments);
|
console.log(arguments);
|
||||||
loaded();
|
loaded();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function reinit(params, loaded) {
|
function reinit(params, loaded) {
|
||||||
pagerPresenter.reinit({query: params.query || {}});
|
pagerPresenter.reinit({query: params.query || {}});
|
||||||
loaded();
|
loaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
function deinit() {
|
function deinit() {
|
||||||
pagerPresenter.deinit();
|
pagerPresenter.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
$el.html(templates.list());
|
$el.html(templates.list());
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderComments($page, data) {
|
function renderComments($page, data) {
|
||||||
var $target = $page.find('.posts');
|
var $target = $page.find('.posts');
|
||||||
_.each(data, function(data) {
|
_.each(data, function(data) {
|
||||||
var post = data.post;
|
var post = data.post;
|
||||||
var comments = data.comments;
|
var comments = data.comments;
|
||||||
|
|
||||||
var $post = jQuery('<li>' + templates.listItem({
|
var $post = jQuery('<li>' + templates.listItem({
|
||||||
util: util,
|
util: util,
|
||||||
post: post,
|
post: post,
|
||||||
postTemplate: templates.post,
|
postTemplate: templates.post,
|
||||||
canViewPosts: privileges.canViewPosts,
|
canViewPosts: privileges.canViewPosts,
|
||||||
}) + '</li>');
|
}) + '</li>');
|
||||||
|
|
||||||
util.loadImagesNicely($post.find('img'));
|
util.loadImagesNicely($post.find('img'));
|
||||||
var presenter = App.DI.get('commentListPresenter');
|
var presenter = App.DI.get('commentListPresenter');
|
||||||
|
|
||||||
presenter.init({
|
presenter.init({
|
||||||
post: post,
|
post: post,
|
||||||
comments: comments,
|
comments: comments,
|
||||||
$target: $post.find('.post-comments-target'),
|
$target: $post.find('.post-comments-target'),
|
||||||
}, function() {
|
}, function() {
|
||||||
presenter.render();
|
presenter.render();
|
||||||
});
|
});
|
||||||
|
|
||||||
$target.append($post);
|
$target.append($post);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
init: init,
|
init: init,
|
||||||
reinit: reinit,
|
reinit: reinit,
|
||||||
deinit: deinit,
|
deinit: deinit,
|
||||||
render: render,
|
render: render,
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,48 +2,48 @@ var App = App || {};
|
||||||
App.Presenters = App.Presenters || {};
|
App.Presenters = App.Presenters || {};
|
||||||
|
|
||||||
App.Presenters.HelpPresenter = function(
|
App.Presenters.HelpPresenter = function(
|
||||||
jQuery,
|
jQuery,
|
||||||
promise,
|
promise,
|
||||||
util,
|
util,
|
||||||
topNavigationPresenter) {
|
topNavigationPresenter) {
|
||||||
|
|
||||||
var $el = jQuery('#content');
|
var $el = jQuery('#content');
|
||||||
var templates = {};
|
var templates = {};
|
||||||
var activeTab;
|
var activeTab;
|
||||||
|
|
||||||
function init(params, loaded) {
|
function init(params, loaded) {
|
||||||
topNavigationPresenter.select('help');
|
topNavigationPresenter.select('help');
|
||||||
topNavigationPresenter.changeTitle('Help');
|
topNavigationPresenter.changeTitle('Help');
|
||||||
|
|
||||||
promise.wait(util.promiseTemplate('help'))
|
promise.wait(util.promiseTemplate('help'))
|
||||||
.then(function(template) {
|
.then(function(template) {
|
||||||
templates.help = template;
|
templates.help = template;
|
||||||
reinit(params, loaded);
|
reinit(params, loaded);
|
||||||
}).fail(function() {
|
}).fail(function() {
|
||||||
console.log(arguments);
|
console.log(arguments);
|
||||||
loaded();
|
loaded();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function reinit(params, loaded) {
|
function reinit(params, loaded) {
|
||||||
activeTab = params.tab || 'about';
|
activeTab = params.tab || 'about';
|
||||||
render();
|
render();
|
||||||
loaded();
|
loaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
$el.html(templates.help({title: topNavigationPresenter.getBaseTitle() }));
|
$el.html(templates.help({title: topNavigationPresenter.getBaseTitle() }));
|
||||||
$el.find('.big-button').removeClass('active');
|
$el.find('.big-button').removeClass('active');
|
||||||
$el.find('.big-button[href*="' + activeTab + '"]').addClass('active');
|
$el.find('.big-button[href*="' + activeTab + '"]').addClass('active');
|
||||||
$el.find('div[data-tab]').hide();
|
$el.find('div[data-tab]').hide();
|
||||||
$el.find('div[data-tab*="' + activeTab + '"]').show();
|
$el.find('div[data-tab*="' + activeTab + '"]').show();
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
init: init,
|
init: init,
|
||||||
reinit: reinit,
|
reinit: reinit,
|
||||||
render: render,
|
render: render,
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,76 +2,76 @@ var App = App || {};
|
||||||
App.Presenters = App.Presenters || {};
|
App.Presenters = App.Presenters || {};
|
||||||
|
|
||||||
App.Presenters.HistoryPresenter = function(
|
App.Presenters.HistoryPresenter = function(
|
||||||
_,
|
_,
|
||||||
jQuery,
|
jQuery,
|
||||||
util,
|
util,
|
||||||
promise,
|
promise,
|
||||||
auth,
|
auth,
|
||||||
pagerPresenter,
|
pagerPresenter,
|
||||||
topNavigationPresenter) {
|
topNavigationPresenter) {
|
||||||
|
|
||||||
var $el = jQuery('#content');
|
var $el = jQuery('#content');
|
||||||
var templates = {};
|
var templates = {};
|
||||||
var params;
|
var params;
|
||||||
|
|
||||||
function init(params, loaded) {
|
function init(params, loaded) {
|
||||||
topNavigationPresenter.changeTitle('History');
|
topNavigationPresenter.changeTitle('History');
|
||||||
|
|
||||||
promise.wait(
|
promise.wait(
|
||||||
util.promiseTemplate('global-history'),
|
util.promiseTemplate('global-history'),
|
||||||
util.promiseTemplate('history'))
|
util.promiseTemplate('history'))
|
||||||
.then(function(historyWrapperTemplate, historyTemplate) {
|
.then(function(historyWrapperTemplate, historyTemplate) {
|
||||||
templates.historyWrapper = historyWrapperTemplate;
|
templates.historyWrapper = historyWrapperTemplate;
|
||||||
templates.history = historyTemplate;
|
templates.history = historyTemplate;
|
||||||
|
|
||||||
render();
|
render();
|
||||||
loaded();
|
loaded();
|
||||||
|
|
||||||
pagerPresenter.init({
|
pagerPresenter.init({
|
||||||
baseUri: '#/history',
|
baseUri: '#/history',
|
||||||
backendUri: '/history',
|
backendUri: '/history',
|
||||||
$target: $el.find('.pagination-target'),
|
$target: $el.find('.pagination-target'),
|
||||||
updateCallback: function($page, data) {
|
updateCallback: function($page, data) {
|
||||||
renderHistory($page, data.entities);
|
renderHistory($page, data.entities);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
function() {
|
function() {
|
||||||
reinit(params, function() {});
|
reinit(params, function() {});
|
||||||
});
|
});
|
||||||
}).fail(function() {
|
}).fail(function() {
|
||||||
console.log(arguments);
|
console.log(arguments);
|
||||||
loaded();
|
loaded();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function reinit(_params, loaded) {
|
function reinit(_params, loaded) {
|
||||||
params = _params;
|
params = _params;
|
||||||
params.query = params.query || {};
|
params.query = params.query || {};
|
||||||
|
|
||||||
pagerPresenter.reinit({query: params.query});
|
pagerPresenter.reinit({query: params.query});
|
||||||
loaded();
|
loaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
function deinit() {
|
function deinit() {
|
||||||
pagerPresenter.deinit();
|
pagerPresenter.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
$el.html(templates.historyWrapper());
|
$el.html(templates.historyWrapper());
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderHistory($page, historyItems) {
|
function renderHistory($page, historyItems) {
|
||||||
$page.append(templates.history({
|
$page.append(templates.history({
|
||||||
util: util,
|
util: util,
|
||||||
history: historyItems}));
|
history: historyItems}));
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
init: init,
|
init: init,
|
||||||
reinit: reinit,
|
reinit: reinit,
|
||||||
deinit: deinit,
|
deinit: deinit,
|
||||||
render: render,
|
render: render,
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,90 +2,90 @@ var App = App || {};
|
||||||
App.Presenters = App.Presenters || {};
|
App.Presenters = App.Presenters || {};
|
||||||
|
|
||||||
App.Presenters.HomePresenter = function(
|
App.Presenters.HomePresenter = function(
|
||||||
jQuery,
|
jQuery,
|
||||||
util,
|
util,
|
||||||
promise,
|
promise,
|
||||||
api,
|
api,
|
||||||
auth,
|
auth,
|
||||||
presenterManager,
|
presenterManager,
|
||||||
postContentPresenter,
|
postContentPresenter,
|
||||||
topNavigationPresenter,
|
topNavigationPresenter,
|
||||||
messagePresenter) {
|
messagePresenter) {
|
||||||
|
|
||||||
var $el = jQuery('#content');
|
var $el = jQuery('#content');
|
||||||
var templates = {};
|
var templates = {};
|
||||||
var globals;
|
var globals;
|
||||||
var post;
|
var post;
|
||||||
var user;
|
var user;
|
||||||
|
|
||||||
function init(params, loaded) {
|
function init(params, loaded) {
|
||||||
topNavigationPresenter.select('home');
|
topNavigationPresenter.select('home');
|
||||||
topNavigationPresenter.changeTitle('Home');
|
topNavigationPresenter.changeTitle('Home');
|
||||||
|
|
||||||
promise.wait(
|
promise.wait(
|
||||||
util.promiseTemplate('home'),
|
util.promiseTemplate('home'),
|
||||||
api.get('/globals'),
|
api.get('/globals'),
|
||||||
api.get('/posts/featured'))
|
api.get('/posts/featured'))
|
||||||
.then(function(
|
.then(function(
|
||||||
homeTemplate,
|
homeTemplate,
|
||||||
globalsResponse,
|
globalsResponse,
|
||||||
featuredPostResponse) {
|
featuredPostResponse) {
|
||||||
templates.home = homeTemplate;
|
templates.home = homeTemplate;
|
||||||
|
|
||||||
globals = globalsResponse.json;
|
globals = globalsResponse.json;
|
||||||
post = featuredPostResponse.json.post;
|
post = featuredPostResponse.json.post;
|
||||||
user = featuredPostResponse.json.user;
|
user = featuredPostResponse.json.user;
|
||||||
render();
|
render();
|
||||||
loaded();
|
loaded();
|
||||||
|
|
||||||
if ($el.find('#post-content-target').length > 0) {
|
if ($el.find('#post-content-target').length > 0) {
|
||||||
presenterManager.initPresenters([
|
presenterManager.initPresenters([
|
||||||
[postContentPresenter, {post: post, $target: $el.find('#post-content-target')}]],
|
[postContentPresenter, {post: post, $target: $el.find('#post-content-target')}]],
|
||||||
function() {
|
function() {
|
||||||
var $wrapper = $el.find('.object-wrapper');
|
var $wrapper = $el.find('.object-wrapper');
|
||||||
$wrapper.css({
|
$wrapper.css({
|
||||||
maxWidth: $wrapper.attr('data-width') + 'px',
|
maxWidth: $wrapper.attr('data-width') + 'px',
|
||||||
width: 'auto',
|
width: 'auto',
|
||||||
margin: '0 auto'});
|
margin: '0 auto'});
|
||||||
postContentPresenter.updatePostNotesSize();
|
postContentPresenter.updatePostNotesSize();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}).fail(function(response) {
|
}).fail(function(response) {
|
||||||
messagePresenter.showError($el, response.json && response.json.error || response);
|
messagePresenter.showError($el, response.json && response.json.error || response);
|
||||||
loaded();
|
loaded();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
$el.html(templates.home({
|
$el.html(templates.home({
|
||||||
post: post,
|
post: post,
|
||||||
user: user,
|
user: user,
|
||||||
globals: globals,
|
globals: globals,
|
||||||
title: topNavigationPresenter.getBaseTitle(),
|
title: topNavigationPresenter.getBaseTitle(),
|
||||||
canViewUsers: auth.hasPrivilege(auth.privileges.viewUsers),
|
canViewUsers: auth.hasPrivilege(auth.privileges.viewUsers),
|
||||||
canViewPosts: auth.hasPrivilege(auth.privileges.viewPosts),
|
canViewPosts: auth.hasPrivilege(auth.privileges.viewPosts),
|
||||||
util: util,
|
util: util,
|
||||||
version: jQuery('head').attr('data-version'),
|
version: jQuery('head').attr('data-version'),
|
||||||
buildTime: jQuery('head').attr('data-build-time'),
|
buildTime: jQuery('head').attr('data-build-time'),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
init: init,
|
init: init,
|
||||||
render: render,
|
render: render,
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
App.DI.register('homePresenter', [
|
App.DI.register('homePresenter', [
|
||||||
'jQuery',
|
'jQuery',
|
||||||
'util',
|
'util',
|
||||||
'promise',
|
'promise',
|
||||||
'api',
|
'api',
|
||||||
'auth',
|
'auth',
|
||||||
'presenterManager',
|
'presenterManager',
|
||||||
'postContentPresenter',
|
'postContentPresenter',
|
||||||
'topNavigationPresenter',
|
'topNavigationPresenter',
|
||||||
'messagePresenter'],
|
'messagePresenter'],
|
||||||
App.Presenters.HomePresenter);
|
App.Presenters.HomePresenter);
|
||||||
|
|
|
@ -2,46 +2,46 @@ var App = App || {};
|
||||||
App.Presenters = App.Presenters || {};
|
App.Presenters = App.Presenters || {};
|
||||||
|
|
||||||
App.Presenters.HttpErrorPresenter = function(
|
App.Presenters.HttpErrorPresenter = function(
|
||||||
jQuery,
|
jQuery,
|
||||||
promise,
|
promise,
|
||||||
util,
|
util,
|
||||||
topNavigationPresenter) {
|
topNavigationPresenter) {
|
||||||
|
|
||||||
var $el = jQuery('#content');
|
var $el = jQuery('#content');
|
||||||
var templates = {};
|
var templates = {};
|
||||||
|
|
||||||
function init(params, loaded) {
|
function init(params, loaded) {
|
||||||
topNavigationPresenter.changeTitle('Error ' + params.error);
|
topNavigationPresenter.changeTitle('Error ' + params.error);
|
||||||
|
|
||||||
if (params.error === 404) {
|
if (params.error === 404) {
|
||||||
promise.wait(util.promiseTemplate('404'))
|
promise.wait(util.promiseTemplate('404'))
|
||||||
.then(function(template) {
|
.then(function(template) {
|
||||||
templates.errorPage = template;
|
templates.errorPage = template;
|
||||||
reinit(params, loaded);
|
reinit(params, loaded);
|
||||||
}).fail(function() {
|
}).fail(function() {
|
||||||
console.log(arguments);
|
console.log(arguments);
|
||||||
loaded();
|
loaded();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
console.log('Not supported.');
|
console.log('Not supported.');
|
||||||
loaded();
|
loaded();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function reinit(params, loaded) {
|
function reinit(params, loaded) {
|
||||||
render();
|
render();
|
||||||
loaded();
|
loaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
$el.html(templates.errorPage());
|
$el.html(templates.errorPage());
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
init: init,
|
init: init,
|
||||||
reinit: reinit,
|
reinit: reinit,
|
||||||
render: render,
|
render: render,
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,84 +2,84 @@ var App = App || {};
|
||||||
App.Presenters = App.Presenters || {};
|
App.Presenters = App.Presenters || {};
|
||||||
|
|
||||||
App.Presenters.LoginPresenter = function(
|
App.Presenters.LoginPresenter = function(
|
||||||
jQuery,
|
jQuery,
|
||||||
util,
|
util,
|
||||||
promise,
|
promise,
|
||||||
router,
|
router,
|
||||||
auth,
|
auth,
|
||||||
topNavigationPresenter,
|
topNavigationPresenter,
|
||||||
messagePresenter) {
|
messagePresenter) {
|
||||||
|
|
||||||
var $el = jQuery('#content');
|
var $el = jQuery('#content');
|
||||||
var $messages;
|
var $messages;
|
||||||
var templates = {};
|
var templates = {};
|
||||||
var previousLocation;
|
var previousLocation;
|
||||||
|
|
||||||
function init(params, loaded) {
|
function init(params, loaded) {
|
||||||
topNavigationPresenter.select('login');
|
topNavigationPresenter.select('login');
|
||||||
topNavigationPresenter.changeTitle('Login');
|
topNavigationPresenter.changeTitle('Login');
|
||||||
previousLocation = params.previousLocation;
|
previousLocation = params.previousLocation;
|
||||||
promise.wait(util.promiseTemplate('login-form'))
|
promise.wait(util.promiseTemplate('login-form'))
|
||||||
.then(function(template) {
|
.then(function(template) {
|
||||||
templates.login = template;
|
templates.login = template;
|
||||||
if (auth.isLoggedIn()) {
|
if (auth.isLoggedIn()) {
|
||||||
finishLogin();
|
finishLogin();
|
||||||
} else {
|
} else {
|
||||||
render();
|
render();
|
||||||
$el.find('input:eq(0)').focus();
|
$el.find('input:eq(0)').focus();
|
||||||
}
|
}
|
||||||
loaded();
|
loaded();
|
||||||
}).fail(function() {
|
}).fail(function() {
|
||||||
console.log(arguments);
|
console.log(arguments);
|
||||||
loaded();
|
loaded();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
$el.html(templates.login());
|
$el.html(templates.login());
|
||||||
$el.find('form').submit(loginFormSubmitted);
|
$el.find('form').submit(loginFormSubmitted);
|
||||||
$messages = $el.find('.messages');
|
$messages = $el.find('.messages');
|
||||||
$messages.width($el.find('form').width());
|
$messages.width($el.find('form').width());
|
||||||
}
|
}
|
||||||
|
|
||||||
function loginFormSubmitted(e) {
|
function loginFormSubmitted(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
messagePresenter.hideMessages($messages);
|
messagePresenter.hideMessages($messages);
|
||||||
|
|
||||||
var userNameOrEmail = $el.find('[name=user]').val();
|
var userNameOrEmail = $el.find('[name=user]').val();
|
||||||
var password = $el.find('[name=password]').val();
|
var password = $el.find('[name=password]').val();
|
||||||
var remember = $el.find('[name=remember]').is(':checked');
|
var remember = $el.find('[name=remember]').is(':checked');
|
||||||
|
|
||||||
if (userNameOrEmail.length === 0) {
|
if (userNameOrEmail.length === 0) {
|
||||||
messagePresenter.showError($messages, 'User name cannot be empty.');
|
messagePresenter.showError($messages, 'User name cannot be empty.');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (password.length === 0) {
|
if (password.length === 0) {
|
||||||
messagePresenter.showError($messages, 'Password cannot be empty.');
|
messagePresenter.showError($messages, 'Password cannot be empty.');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
promise.wait(auth.loginFromCredentials(userNameOrEmail, password, remember))
|
promise.wait(auth.loginFromCredentials(userNameOrEmail, password, remember))
|
||||||
.then(function(response) {
|
.then(function(response) {
|
||||||
finishLogin();
|
finishLogin();
|
||||||
}).fail(function(response) {
|
}).fail(function(response) {
|
||||||
messagePresenter.showError($messages, response.json && response.json.error || response);
|
messagePresenter.showError($messages, response.json && response.json.error || response);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function finishLogin() {
|
function finishLogin() {
|
||||||
if (previousLocation && !previousLocation.match(/logout|password-reset|activate|register/)) {
|
if (previousLocation && !previousLocation.match(/logout|password-reset|activate|register/)) {
|
||||||
router.navigate(previousLocation);
|
router.navigate(previousLocation);
|
||||||
} else {
|
} else {
|
||||||
router.navigateToMainPage();
|
router.navigateToMainPage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
init: init,
|
init: init,
|
||||||
render: render,
|
render: render,
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,38 +2,38 @@ var App = App || {};
|
||||||
App.Presenters = App.Presenters || {};
|
App.Presenters = App.Presenters || {};
|
||||||
|
|
||||||
App.Presenters.LogoutPresenter = function(
|
App.Presenters.LogoutPresenter = function(
|
||||||
jQuery,
|
jQuery,
|
||||||
promise,
|
promise,
|
||||||
router,
|
router,
|
||||||
auth,
|
auth,
|
||||||
topNavigationPresenter,
|
topNavigationPresenter,
|
||||||
messagePresenter) {
|
messagePresenter) {
|
||||||
|
|
||||||
var $messages = jQuery('#content');
|
var $messages = jQuery('#content');
|
||||||
|
|
||||||
function init(params, loaded) {
|
function init(params, loaded) {
|
||||||
topNavigationPresenter.select('logout');
|
topNavigationPresenter.select('logout');
|
||||||
topNavigationPresenter.changeTitle('Logout');
|
topNavigationPresenter.changeTitle('Logout');
|
||||||
promise.wait(auth.logout())
|
promise.wait(auth.logout())
|
||||||
.then(function() {
|
.then(function() {
|
||||||
loaded();
|
loaded();
|
||||||
$messages.empty();
|
$messages.empty();
|
||||||
var $messageDiv = messagePresenter.showInfo($messages, 'Logged out. <a href="">Back to main page</a>');
|
var $messageDiv = messagePresenter.showInfo($messages, 'Logged out. <a href="">Back to main page</a>');
|
||||||
$messageDiv.find('a').click(mainPageLinkClicked);
|
$messageDiv.find('a').click(mainPageLinkClicked);
|
||||||
}).fail(function(response) {
|
}).fail(function(response) {
|
||||||
messagePresenter.showError(($messages, response.json && response.json.error || response) + '<br/>Reload the page to continue.');
|
messagePresenter.showError(($messages, response.json && response.json.error || response) + '<br/>Reload the page to continue.');
|
||||||
loaded();
|
loaded();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function mainPageLinkClicked(e) {
|
function mainPageLinkClicked(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
router.navigateToMainPage();
|
router.navigateToMainPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
init: init
|
init: init
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -3,51 +3,51 @@ App.Presenters = App.Presenters || {};
|
||||||
|
|
||||||
App.Presenters.MessagePresenter = function(_, jQuery) {
|
App.Presenters.MessagePresenter = function(_, jQuery) {
|
||||||
|
|
||||||
var options = {
|
var options = {
|
||||||
instant: false
|
instant: false
|
||||||
};
|
};
|
||||||
|
|
||||||
function showInfo($el, message) {
|
function showInfo($el, message) {
|
||||||
return showMessage($el, 'info', message);
|
return showMessage($el, 'info', message);
|
||||||
}
|
}
|
||||||
|
|
||||||
function showError($el, message) {
|
function showError($el, message) {
|
||||||
return showMessage($el, 'error', message);
|
return showMessage($el, 'error', message);
|
||||||
}
|
}
|
||||||
|
|
||||||
function hideMessages($el) {
|
function hideMessages($el) {
|
||||||
var $messages = $el.children('.message');
|
var $messages = $el.children('.message');
|
||||||
if (options.instant) {
|
if (options.instant) {
|
||||||
$messages.each(function() {
|
$messages.each(function() {
|
||||||
jQuery(this).slideUp('fast', function() {
|
jQuery(this).slideUp('fast', function() {
|
||||||
jQuery(this).remove();
|
jQuery(this).remove();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
$messages.remove();
|
$messages.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function showMessage($el, className, message) {
|
function showMessage($el, className, message) {
|
||||||
var $messageDiv = jQuery('<div>');
|
var $messageDiv = jQuery('<div>');
|
||||||
$messageDiv.addClass('message');
|
$messageDiv.addClass('message');
|
||||||
$messageDiv.addClass(className);
|
$messageDiv.addClass(className);
|
||||||
$messageDiv.html(message);
|
$messageDiv.html(message);
|
||||||
if (!options.instant) {
|
if (!options.instant) {
|
||||||
$messageDiv.hide();
|
$messageDiv.hide();
|
||||||
}
|
}
|
||||||
$el.append($messageDiv);
|
$el.append($messageDiv);
|
||||||
if (!options.instant) {
|
if (!options.instant) {
|
||||||
$messageDiv.slideDown('fast');
|
$messageDiv.slideDown('fast');
|
||||||
}
|
}
|
||||||
return $messageDiv;
|
return $messageDiv;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _.extend(options, {
|
return _.extend(options, {
|
||||||
showInfo: showInfo,
|
showInfo: showInfo,
|
||||||
showError: showError,
|
showError: showError,
|
||||||
hideMessages: hideMessages,
|
hideMessages: hideMessages,
|
||||||
});
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,267 +2,267 @@ var App = App || {};
|
||||||
App.Presenters = App.Presenters || {};
|
App.Presenters = App.Presenters || {};
|
||||||
|
|
||||||
App.Presenters.PagerPresenter = function(
|
App.Presenters.PagerPresenter = function(
|
||||||
_,
|
_,
|
||||||
jQuery,
|
jQuery,
|
||||||
util,
|
util,
|
||||||
promise,
|
promise,
|
||||||
keyboard,
|
keyboard,
|
||||||
router,
|
router,
|
||||||
pager,
|
pager,
|
||||||
messagePresenter,
|
messagePresenter,
|
||||||
browsingSettings,
|
browsingSettings,
|
||||||
progress) {
|
progress) {
|
||||||
|
|
||||||
var $target;
|
var $target;
|
||||||
var $pageList;
|
var $pageList;
|
||||||
var $messages;
|
var $messages;
|
||||||
var targetContent;
|
var targetContent;
|
||||||
var endlessScroll = browsingSettings.getSettings().endlessScroll;
|
var endlessScroll = browsingSettings.getSettings().endlessScroll;
|
||||||
var scrollInterval;
|
var scrollInterval;
|
||||||
var templates = {};
|
var templates = {};
|
||||||
var forceClear = !endlessScroll;
|
var forceClear = !endlessScroll;
|
||||||
|
|
||||||
var baseUri;
|
var baseUri;
|
||||||
var updateCallback;
|
var updateCallback;
|
||||||
|
|
||||||
function init(params, loaded) {
|
function init(params, loaded) {
|
||||||
baseUri = params.baseUri;
|
baseUri = params.baseUri;
|
||||||
updateCallback = params.updateCallback;
|
updateCallback = params.updateCallback;
|
||||||
|
|
||||||
messagePresenter.instant = true;
|
messagePresenter.instant = true;
|
||||||
|
|
||||||
$target = params.$target;
|
$target = params.$target;
|
||||||
targetContent = jQuery(params.$target).html();
|
targetContent = jQuery(params.$target).html();
|
||||||
|
|
||||||
pager.init({url: params.backendUri});
|
pager.init({url: params.backendUri});
|
||||||
setQuery(params.query);
|
setQuery(params.query);
|
||||||
if (forceClear) {
|
if (forceClear) {
|
||||||
clearContent();
|
clearContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
promise.wait(util.promiseTemplate('pager'))
|
promise.wait(util.promiseTemplate('pager'))
|
||||||
.then(function(template) {
|
.then(function(template) {
|
||||||
templates.pager = template;
|
templates.pager = template;
|
||||||
render();
|
render();
|
||||||
loaded();
|
loaded();
|
||||||
}).fail(function() {
|
}).fail(function() {
|
||||||
console.log(arguments);
|
console.log(arguments);
|
||||||
loaded();
|
loaded();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function reinit(params, loaded) {
|
function reinit(params, loaded) {
|
||||||
setQuery(params.query);
|
setQuery(params.query);
|
||||||
if (forceClear) {
|
if (forceClear) {
|
||||||
clearContent();
|
clearContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
promise.wait(retrieve())
|
promise.wait(retrieve())
|
||||||
.then(loaded)
|
.then(loaded)
|
||||||
.fail(loaded);
|
.fail(loaded);
|
||||||
|
|
||||||
if (!endlessScroll) {
|
if (!endlessScroll) {
|
||||||
keyboard.keydown('a', navigateToPrevPage);
|
keyboard.keydown('a', navigateToPrevPage);
|
||||||
keyboard.keydown('d', navigateToNextPage);
|
keyboard.keydown('d', navigateToNextPage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function deinit() {
|
function deinit() {
|
||||||
detachNextPageLoader();
|
detachNextPageLoader();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getUrl(options) {
|
function getUrl(options) {
|
||||||
return util.appendComplexRouteParam(
|
return util.appendComplexRouteParam(
|
||||||
baseUri,
|
baseUri,
|
||||||
util.simplifySearchQuery(
|
util.simplifySearchQuery(
|
||||||
_.extend(
|
_.extend(
|
||||||
{},
|
{},
|
||||||
pager.getSearchParams(),
|
pager.getSearchParams(),
|
||||||
{page: pager.getPage()},
|
{page: pager.getPage()},
|
||||||
options)));
|
options)));
|
||||||
}
|
}
|
||||||
|
|
||||||
function syncUrl(options) {
|
function syncUrl(options) {
|
||||||
router.navigate(getUrl(options));
|
router.navigate(getUrl(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
function syncUrlInplace(options) {
|
function syncUrlInplace(options) {
|
||||||
router.navigateInplace(getUrl(options));
|
router.navigateInplace(getUrl(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
function retrieve() {
|
function retrieve() {
|
||||||
messagePresenter.hideMessages($messages);
|
messagePresenter.hideMessages($messages);
|
||||||
progress.start();
|
progress.start();
|
||||||
|
|
||||||
return promise.make(function(resolve, reject) {
|
return promise.make(function(resolve, reject) {
|
||||||
hidePageList();
|
hidePageList();
|
||||||
|
|
||||||
promise.wait(pager.retrieve())
|
promise.wait(pager.retrieve())
|
||||||
.then(function(response) {
|
.then(function(response) {
|
||||||
progress.done();
|
progress.done();
|
||||||
|
|
||||||
if (forceClear) {
|
if (forceClear) {
|
||||||
clearContent();
|
clearContent();
|
||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
}
|
}
|
||||||
var $page = jQuery('<div class="page">');
|
var $page = jQuery('<div class="page">');
|
||||||
if (endlessScroll && pager.getTotalPages() > 1) {
|
if (endlessScroll && pager.getTotalPages() > 1) {
|
||||||
$page.append('<p>Page ' + pager.getPage() + ' of ' + pager.getTotalPages() + '</p>');
|
$page.append('<p>Page ' + pager.getPage() + ' of ' + pager.getTotalPages() + '</p>');
|
||||||
}
|
}
|
||||||
$page.append(targetContent);
|
$page.append(targetContent);
|
||||||
$target.find('.pagination-content').append($page);
|
$target.find('.pagination-content').append($page);
|
||||||
updateCallback($page, response);
|
updateCallback($page, response);
|
||||||
|
|
||||||
refreshPageList();
|
refreshPageList();
|
||||||
if (!response.entities.length) {
|
if (!response.entities.length) {
|
||||||
messagePresenter.showInfo($messages, 'No data to show');
|
messagePresenter.showInfo($messages, 'No data to show');
|
||||||
if (pager.getVisiblePages().length === 1) {
|
if (pager.getVisiblePages().length === 1) {
|
||||||
hidePageList();
|
hidePageList();
|
||||||
} else {
|
} else {
|
||||||
showPageList();
|
showPageList();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
showPageList();
|
showPageList();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pager.getPage() < response.totalPages) {
|
if (pager.getPage() < response.totalPages) {
|
||||||
attachNextPageLoader();
|
attachNextPageLoader();
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve();
|
resolve();
|
||||||
}).fail(function(response) {
|
}).fail(function(response) {
|
||||||
progress.done();
|
progress.done();
|
||||||
clearContent();
|
clearContent();
|
||||||
hidePageList();
|
hidePageList();
|
||||||
messagePresenter.showError($messages, response.json && response.json.error || response);
|
messagePresenter.showError($messages, response.json && response.json.error || response);
|
||||||
|
|
||||||
reject();
|
reject();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearContent() {
|
function clearContent() {
|
||||||
detachNextPageLoader();
|
detachNextPageLoader();
|
||||||
$target.find('.pagination-content').empty();
|
$target.find('.pagination-content').empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
function attachNextPageLoader() {
|
function attachNextPageLoader() {
|
||||||
if (!endlessScroll) {
|
if (!endlessScroll) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
detachNextPageLoader();
|
detachNextPageLoader();
|
||||||
scrollInterval = window.setInterval(function() {
|
scrollInterval = window.setInterval(function() {
|
||||||
var myScrollInterval = scrollInterval;
|
var myScrollInterval = scrollInterval;
|
||||||
var baseLine = $target.offset().top + $target.innerHeight();
|
var baseLine = $target.offset().top + $target.innerHeight();
|
||||||
var scrollY = jQuery(window).scrollTop() + jQuery(window).height();
|
var scrollY = jQuery(window).scrollTop() + jQuery(window).height();
|
||||||
if (scrollY > baseLine) {
|
if (scrollY > baseLine) {
|
||||||
syncUrlInplace({page: pager.getPage() + 1});
|
syncUrlInplace({page: pager.getPage() + 1});
|
||||||
window.clearInterval(myScrollInterval);
|
window.clearInterval(myScrollInterval);
|
||||||
}
|
}
|
||||||
}, 100);
|
}, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
function detachNextPageLoader() {
|
function detachNextPageLoader() {
|
||||||
window.clearInterval(scrollInterval);
|
window.clearInterval(scrollInterval);
|
||||||
}
|
}
|
||||||
|
|
||||||
function showPageList() {
|
function showPageList() {
|
||||||
$pageList.show();
|
$pageList.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
function hidePageList() {
|
function hidePageList() {
|
||||||
$pageList.hide();
|
$pageList.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
function navigateToPrevPage() {
|
function navigateToPrevPage() {
|
||||||
console.log('!');
|
console.log('!');
|
||||||
if (pager.prevPage()) {
|
if (pager.prevPage()) {
|
||||||
syncUrl({page: pager.getPage()});
|
syncUrl({page: pager.getPage()});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function navigateToNextPage() {
|
function navigateToNextPage() {
|
||||||
if (pager.nextPage()) {
|
if (pager.nextPage()) {
|
||||||
syncUrl({page: pager.getPage()});
|
syncUrl({page: pager.getPage()});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function refreshPageList() {
|
function refreshPageList() {
|
||||||
var $lastItem = $pageList.find('li:last-child');
|
var $lastItem = $pageList.find('li:last-child');
|
||||||
var currentPage = pager.getPage();
|
var currentPage = pager.getPage();
|
||||||
var pages = pager.getVisiblePages();
|
var pages = pager.getVisiblePages();
|
||||||
$pageList.find('li.page').remove();
|
$pageList.find('li.page').remove();
|
||||||
var lastPage = 0;
|
var lastPage = 0;
|
||||||
_.each(pages, function(page) {
|
_.each(pages, function(page) {
|
||||||
if (page - lastPage > 1) {
|
if (page - lastPage > 1) {
|
||||||
jQuery('<li class="page ellipsis"><a>…</a></li>').insertBefore($lastItem);
|
jQuery('<li class="page ellipsis"><a>…</a></li>').insertBefore($lastItem);
|
||||||
}
|
}
|
||||||
lastPage = page;
|
lastPage = page;
|
||||||
|
|
||||||
var $a = jQuery('<a href="#"/>');
|
var $a = jQuery('<a href="#"/>');
|
||||||
$a.click(function(e) {
|
$a.click(function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
syncUrl({page: page});
|
syncUrl({page: page});
|
||||||
});
|
});
|
||||||
$a.addClass('big-button');
|
$a.addClass('big-button');
|
||||||
$a.text(page);
|
$a.text(page);
|
||||||
if (page === currentPage) {
|
if (page === currentPage) {
|
||||||
$a.addClass('active');
|
$a.addClass('active');
|
||||||
}
|
}
|
||||||
jQuery('<li class="page"/>').append($a).insertBefore($lastItem);
|
jQuery('<li class="page"/>').append($a).insertBefore($lastItem);
|
||||||
});
|
});
|
||||||
|
|
||||||
$pageList.find('li.next a').unbind('click').bind('click', function(e) {
|
$pageList.find('li.next a').unbind('click').bind('click', function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
navigateToNextPage();
|
navigateToNextPage();
|
||||||
});
|
});
|
||||||
$pageList.find('li.prev a').unbind('click').bind('click', function(e) {
|
$pageList.find('li.prev a').unbind('click').bind('click', function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
navigateToPrevPage();
|
navigateToPrevPage();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
$target.html(templates.pager());
|
$target.html(templates.pager());
|
||||||
$messages = $target.find('.pagination-content');
|
$messages = $target.find('.pagination-content');
|
||||||
$pageList = $target.find('.page-list');
|
$pageList = $target.find('.page-list');
|
||||||
if (endlessScroll) {
|
if (endlessScroll) {
|
||||||
$pageList.remove();
|
$pageList.remove();
|
||||||
} else {
|
} else {
|
||||||
refreshPageList();
|
refreshPageList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setQuery(query) {
|
function setQuery(query) {
|
||||||
if (!query) {
|
if (!query) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
query.page = parseInt(query.page) || 1;
|
query.page = parseInt(query.page) || 1;
|
||||||
var page = query.page;
|
var page = query.page;
|
||||||
query = _.extend({}, query);
|
query = _.extend({}, query);
|
||||||
delete query.page;
|
delete query.page;
|
||||||
forceClear =
|
forceClear =
|
||||||
query.query !== pager.getSearchParams().query ||
|
query.query !== pager.getSearchParams().query ||
|
||||||
query.order !== pager.getSearchParams().order ||
|
query.order !== pager.getSearchParams().order ||
|
||||||
parseInt(page) !== pager.getPage() + 1 ||
|
parseInt(page) !== pager.getPage() + 1 ||
|
||||||
!endlessScroll;
|
!endlessScroll;
|
||||||
pager.setSearchParams(query);
|
pager.setSearchParams(query);
|
||||||
pager.setPage(page);
|
pager.setPage(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setQueryAndSyncUrl(query) {
|
function setQueryAndSyncUrl(query) {
|
||||||
setQuery(query);
|
setQuery(query);
|
||||||
syncUrl();
|
syncUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
init: init,
|
init: init,
|
||||||
reinit: reinit,
|
reinit: reinit,
|
||||||
deinit: deinit,
|
deinit: deinit,
|
||||||
syncUrl: syncUrl,
|
syncUrl: syncUrl,
|
||||||
setQuery: setQueryAndSyncUrl,
|
setQuery: setQueryAndSyncUrl,
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,76 +2,76 @@ var App = App || {};
|
||||||
App.Presenters = App.Presenters || {};
|
App.Presenters = App.Presenters || {};
|
||||||
|
|
||||||
App.Presenters.PostContentPresenter = function(
|
App.Presenters.PostContentPresenter = function(
|
||||||
jQuery,
|
jQuery,
|
||||||
util,
|
util,
|
||||||
promise,
|
promise,
|
||||||
presenterManager,
|
presenterManager,
|
||||||
postNotesPresenter) {
|
postNotesPresenter) {
|
||||||
|
|
||||||
var post;
|
var post;
|
||||||
var templates = {};
|
var templates = {};
|
||||||
var $target;
|
var $target;
|
||||||
|
|
||||||
function init(params, loaded) {
|
function init(params, loaded) {
|
||||||
$target = params.$target;
|
$target = params.$target;
|
||||||
post = params.post;
|
post = params.post;
|
||||||
|
|
||||||
promise.wait(util.promiseTemplate('post-content'))
|
promise.wait(util.promiseTemplate('post-content'))
|
||||||
.then(function(postContentTemplate) {
|
.then(function(postContentTemplate) {
|
||||||
templates.postContent = postContentTemplate;
|
templates.postContent = postContentTemplate;
|
||||||
render();
|
render();
|
||||||
loaded();
|
loaded();
|
||||||
}).fail(function() {
|
}).fail(function() {
|
||||||
console.log(arguments);
|
console.log(arguments);
|
||||||
loaded();
|
loaded();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
$target.html(templates.postContent({post: post}));
|
$target.html(templates.postContent({post: post}));
|
||||||
|
|
||||||
if (post.contentType === 'image') {
|
if (post.contentType === 'image') {
|
||||||
loadPostNotes();
|
loadPostNotes();
|
||||||
updatePostNotesSize();
|
updatePostNotesSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
jQuery(window).resize(updatePostNotesSize);
|
jQuery(window).resize(updatePostNotesSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadPostNotes() {
|
function loadPostNotes() {
|
||||||
presenterManager.initPresenters([
|
presenterManager.initPresenters([
|
||||||
[postNotesPresenter, {post: post, notes: post.notes, $target: $target.find('.post-notes-target')}]],
|
[postNotesPresenter, {post: post, notes: post.notes, $target: $target.find('.post-notes-target')}]],
|
||||||
function() {});
|
function() {});
|
||||||
}
|
}
|
||||||
|
|
||||||
function updatePostNotesSize() {
|
function updatePostNotesSize() {
|
||||||
var $postNotes = $target.find('.post-notes-target');
|
var $postNotes = $target.find('.post-notes-target');
|
||||||
var $objectWrapper = $target.find('.object-wrapper');
|
var $objectWrapper = $target.find('.object-wrapper');
|
||||||
$postNotes.css({
|
$postNotes.css({
|
||||||
width: $objectWrapper.outerWidth() + 'px',
|
width: $objectWrapper.outerWidth() + 'px',
|
||||||
height: $objectWrapper.outerHeight() + 'px',
|
height: $objectWrapper.outerHeight() + 'px',
|
||||||
left: ($objectWrapper.offset().left - $objectWrapper.parent().offset().left) + 'px',
|
left: ($objectWrapper.offset().left - $objectWrapper.parent().offset().left) + 'px',
|
||||||
top: ($objectWrapper.offset().top - $objectWrapper.parent().offset().top) + 'px',
|
top: ($objectWrapper.offset().top - $objectWrapper.parent().offset().top) + 'px',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function addNewPostNote() {
|
function addNewPostNote() {
|
||||||
postNotesPresenter.addNewPostNote();
|
postNotesPresenter.addNewPostNote();
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
init: init,
|
init: init,
|
||||||
render: render,
|
render: render,
|
||||||
addNewPostNote: addNewPostNote,
|
addNewPostNote: addNewPostNote,
|
||||||
updatePostNotesSize: updatePostNotesSize,
|
updatePostNotesSize: updatePostNotesSize,
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
App.DI.register('postContentPresenter', [
|
App.DI.register('postContentPresenter', [
|
||||||
'jQuery',
|
'jQuery',
|
||||||
'util',
|
'util',
|
||||||
'promise',
|
'promise',
|
||||||
'presenterManager',
|
'presenterManager',
|
||||||
'postNotesPresenter'],
|
'postNotesPresenter'],
|
||||||
App.Presenters.PostContentPresenter);
|
App.Presenters.PostContentPresenter);
|
||||||
|
|
|
@ -2,154 +2,154 @@ var App = App || {};
|
||||||
App.Presenters = App.Presenters || {};
|
App.Presenters = App.Presenters || {};
|
||||||
|
|
||||||
App.Presenters.PostEditPresenter = function(
|
App.Presenters.PostEditPresenter = function(
|
||||||
jQuery,
|
jQuery,
|
||||||
util,
|
util,
|
||||||
promise,
|
promise,
|
||||||
api,
|
api,
|
||||||
auth,
|
auth,
|
||||||
tagList) {
|
tagList) {
|
||||||
|
|
||||||
var $target;
|
var $target;
|
||||||
var post;
|
var post;
|
||||||
var updateCallback;
|
var updateCallback;
|
||||||
var privileges = {};
|
var privileges = {};
|
||||||
var templates = {};
|
var templates = {};
|
||||||
|
|
||||||
var tagInput;
|
var tagInput;
|
||||||
var postContentFileDropper;
|
var postContentFileDropper;
|
||||||
var postThumbnailFileDropper;
|
var postThumbnailFileDropper;
|
||||||
var postContent;
|
var postContent;
|
||||||
var postThumbnail;
|
var postThumbnail;
|
||||||
|
|
||||||
privileges.canChangeSafety = auth.hasPrivilege(auth.privileges.changePostSafety);
|
privileges.canChangeSafety = auth.hasPrivilege(auth.privileges.changePostSafety);
|
||||||
privileges.canChangeSource = auth.hasPrivilege(auth.privileges.changePostSource);
|
privileges.canChangeSource = auth.hasPrivilege(auth.privileges.changePostSource);
|
||||||
privileges.canChangeTags = auth.hasPrivilege(auth.privileges.changePostTags);
|
privileges.canChangeTags = auth.hasPrivilege(auth.privileges.changePostTags);
|
||||||
privileges.canChangeContent = auth.hasPrivilege(auth.privileges.changePostContent);
|
privileges.canChangeContent = auth.hasPrivilege(auth.privileges.changePostContent);
|
||||||
privileges.canChangeThumbnail = auth.hasPrivilege(auth.privileges.changePostThumbnail);
|
privileges.canChangeThumbnail = auth.hasPrivilege(auth.privileges.changePostThumbnail);
|
||||||
privileges.canChangeRelations = auth.hasPrivilege(auth.privileges.changePostRelations);
|
privileges.canChangeRelations = auth.hasPrivilege(auth.privileges.changePostRelations);
|
||||||
privileges.canChangeFlags = auth.hasPrivilege(auth.privileges.changePostFlags);
|
privileges.canChangeFlags = auth.hasPrivilege(auth.privileges.changePostFlags);
|
||||||
|
|
||||||
function init(params, loaded) {
|
function init(params, loaded) {
|
||||||
post = params.post;
|
post = params.post;
|
||||||
|
|
||||||
updateCallback = params.updateCallback;
|
updateCallback = params.updateCallback;
|
||||||
$target = params.$target;
|
$target = params.$target;
|
||||||
|
|
||||||
promise.wait(util.promiseTemplate('post-edit'))
|
promise.wait(util.promiseTemplate('post-edit'))
|
||||||
.then(function(postEditTemplate) {
|
.then(function(postEditTemplate) {
|
||||||
templates.postEdit = postEditTemplate;
|
templates.postEdit = postEditTemplate;
|
||||||
render();
|
render();
|
||||||
loaded();
|
loaded();
|
||||||
}).fail(function() {
|
}).fail(function() {
|
||||||
console.log(arguments);
|
console.log(arguments);
|
||||||
loaded();
|
loaded();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
$target.html(templates.postEdit({post: post, privileges: privileges}));
|
$target.html(templates.postEdit({post: post, privileges: privileges}));
|
||||||
|
|
||||||
postContentFileDropper = new App.Controls.FileDropper($target.find('form [name=content]'));
|
postContentFileDropper = new App.Controls.FileDropper($target.find('form [name=content]'));
|
||||||
postContentFileDropper.onChange = postContentChanged;
|
postContentFileDropper.onChange = postContentChanged;
|
||||||
postContentFileDropper.setNames = true;
|
postContentFileDropper.setNames = true;
|
||||||
postThumbnailFileDropper = new App.Controls.FileDropper($target.find('form [name=thumbnail]'));
|
postThumbnailFileDropper = new App.Controls.FileDropper($target.find('form [name=thumbnail]'));
|
||||||
postThumbnailFileDropper.onChange = postThumbnailChanged;
|
postThumbnailFileDropper.onChange = postThumbnailChanged;
|
||||||
postThumbnailFileDropper.setNames = true;
|
postThumbnailFileDropper.setNames = true;
|
||||||
|
|
||||||
if (privileges.canChangeTags) {
|
if (privileges.canChangeTags) {
|
||||||
tagInput = new App.Controls.TagInput($target.find('form [name=tags]'));
|
tagInput = new App.Controls.TagInput($target.find('form [name=tags]'));
|
||||||
tagInput.inputConfirmed = editPost;
|
tagInput.inputConfirmed = editPost;
|
||||||
}
|
}
|
||||||
|
|
||||||
$target.find('form').submit(editFormSubmitted);
|
$target.find('form').submit(editFormSubmitted);
|
||||||
}
|
}
|
||||||
|
|
||||||
function focus() {
|
function focus() {
|
||||||
if (tagInput) {
|
if (tagInput) {
|
||||||
tagInput.focus();
|
tagInput.focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function editFormSubmitted(e) {
|
function editFormSubmitted(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
editPost();
|
editPost();
|
||||||
}
|
}
|
||||||
|
|
||||||
function postContentChanged(files) {
|
function postContentChanged(files) {
|
||||||
postContent = files[0];
|
postContent = files[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
function postThumbnailChanged(files) {
|
function postThumbnailChanged(files) {
|
||||||
postThumbnail = files[0];
|
postThumbnail = files[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPrivileges() {
|
function getPrivileges() {
|
||||||
return privileges;
|
return privileges;
|
||||||
}
|
}
|
||||||
|
|
||||||
function editPost() {
|
function editPost() {
|
||||||
var $form = $target.find('form');
|
var $form = $target.find('form');
|
||||||
var formData = new FormData();
|
var formData = new FormData();
|
||||||
formData.append('seenEditTime', post.lastEditTime);
|
formData.append('seenEditTime', post.lastEditTime);
|
||||||
|
|
||||||
if (privileges.canChangeContent && postContent) {
|
if (privileges.canChangeContent && postContent) {
|
||||||
formData.append('content', postContent);
|
formData.append('content', postContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (privileges.canChangeThumbnail && postThumbnail) {
|
if (privileges.canChangeThumbnail && postThumbnail) {
|
||||||
formData.append('thumbnail', postThumbnail);
|
formData.append('thumbnail', postThumbnail);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (privileges.canChangeSource) {
|
if (privileges.canChangeSource) {
|
||||||
formData.append('source', $form.find('[name=source]').val());
|
formData.append('source', $form.find('[name=source]').val());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (privileges.canChangeSafety) {
|
if (privileges.canChangeSafety) {
|
||||||
formData.append('safety', $form.find('[name=safety]:checked').val());
|
formData.append('safety', $form.find('[name=safety]:checked').val());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (privileges.canChangeTags) {
|
if (privileges.canChangeTags) {
|
||||||
formData.append('tags', tagInput.getTags().join(' '));
|
formData.append('tags', tagInput.getTags().join(' '));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (privileges.canChangeRelations) {
|
if (privileges.canChangeRelations) {
|
||||||
formData.append('relations', $form.find('[name=relations]').val());
|
formData.append('relations', $form.find('[name=relations]').val());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (privileges.canChangeFlags) {
|
if (privileges.canChangeFlags) {
|
||||||
if (post.contentType === 'video') {
|
if (post.contentType === 'video') {
|
||||||
formData.append('loop', $form.find('[name=loop]').is(':checked') ? 1 : 0);
|
formData.append('loop', $form.find('[name=loop]').is(':checked') ? 1 : 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (post.tags.length === 0) {
|
if (post.tags.length === 0) {
|
||||||
showEditError('No tags set.');
|
showEditError('No tags set.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
jQuery(document.activeElement).blur();
|
jQuery(document.activeElement).blur();
|
||||||
|
|
||||||
promise.wait(api.post('/posts/' + post.id, formData))
|
promise.wait(api.post('/posts/' + post.id, formData))
|
||||||
.then(function(response) {
|
.then(function(response) {
|
||||||
tagList.refreshTags();
|
tagList.refreshTags();
|
||||||
if (typeof(updateCallback) !== 'undefined') {
|
if (typeof(updateCallback) !== 'undefined') {
|
||||||
updateCallback(post = response.json);
|
updateCallback(post = response.json);
|
||||||
}
|
}
|
||||||
}).fail(function(response) {
|
}).fail(function(response) {
|
||||||
showEditError(response);
|
showEditError(response);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function showEditError(response) {
|
function showEditError(response) {
|
||||||
window.alert(response.json && response.json.error || response);
|
window.alert(response.json && response.json.error || response);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
init: init,
|
init: init,
|
||||||
render: render,
|
render: render,
|
||||||
getPrivileges: getPrivileges,
|
getPrivileges: getPrivileges,
|
||||||
focus: focus,
|
focus: focus,
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,264 +2,264 @@ var App = App || {};
|
||||||
App.Presenters = App.Presenters || {};
|
App.Presenters = App.Presenters || {};
|
||||||
|
|
||||||
App.Presenters.PostListPresenter = function(
|
App.Presenters.PostListPresenter = function(
|
||||||
_,
|
_,
|
||||||
jQuery,
|
jQuery,
|
||||||
util,
|
util,
|
||||||
promise,
|
promise,
|
||||||
auth,
|
auth,
|
||||||
api,
|
api,
|
||||||
keyboard,
|
keyboard,
|
||||||
pagerPresenter,
|
pagerPresenter,
|
||||||
browsingSettings,
|
browsingSettings,
|
||||||
topNavigationPresenter) {
|
topNavigationPresenter) {
|
||||||
|
|
||||||
var KEY_RETURN = 13;
|
var KEY_RETURN = 13;
|
||||||
|
|
||||||
var templates = {};
|
var templates = {};
|
||||||
var $el = jQuery('#content');
|
var $el = jQuery('#content');
|
||||||
var $searchInput;
|
var $searchInput;
|
||||||
var privileges = {};
|
var privileges = {};
|
||||||
|
|
||||||
var params;
|
var params;
|
||||||
|
|
||||||
function init(_params, loaded) {
|
function init(_params, loaded) {
|
||||||
topNavigationPresenter.select('posts');
|
topNavigationPresenter.select('posts');
|
||||||
topNavigationPresenter.changeTitle('Posts');
|
topNavigationPresenter.changeTitle('Posts');
|
||||||
params = _params;
|
params = _params;
|
||||||
params.query = params.query || {};
|
params.query = params.query || {};
|
||||||
|
|
||||||
privileges.canMassTag = auth.hasPrivilege(auth.privileges.massTag);
|
privileges.canMassTag = auth.hasPrivilege(auth.privileges.massTag);
|
||||||
privileges.canViewPosts = auth.hasPrivilege(auth.privileges.viewPosts);
|
privileges.canViewPosts = auth.hasPrivilege(auth.privileges.viewPosts);
|
||||||
|
|
||||||
promise.wait(
|
promise.wait(
|
||||||
util.promiseTemplate('post-list'),
|
util.promiseTemplate('post-list'),
|
||||||
util.promiseTemplate('post-list-item'))
|
util.promiseTemplate('post-list-item'))
|
||||||
.then(function(listTemplate, listItemTemplate) {
|
.then(function(listTemplate, listItemTemplate) {
|
||||||
templates.list = listTemplate;
|
templates.list = listTemplate;
|
||||||
templates.listItem = listItemTemplate;
|
templates.listItem = listItemTemplate;
|
||||||
|
|
||||||
render();
|
render();
|
||||||
loaded();
|
loaded();
|
||||||
|
|
||||||
pagerPresenter.init({
|
pagerPresenter.init({
|
||||||
baseUri: '#/posts',
|
baseUri: '#/posts',
|
||||||
backendUri: '/posts',
|
backendUri: '/posts',
|
||||||
$target: $el.find('.pagination-target'),
|
$target: $el.find('.pagination-target'),
|
||||||
updateCallback: function($page, data) {
|
updateCallback: function($page, data) {
|
||||||
renderPosts($page, data.entities);
|
renderPosts($page, data.entities);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
function() {
|
function() {
|
||||||
reinit(params, function() {});
|
reinit(params, function() {});
|
||||||
});
|
});
|
||||||
}).fail(function() {
|
}).fail(function() {
|
||||||
console.log(arguments);
|
console.log(arguments);
|
||||||
loaded();
|
loaded();
|
||||||
});
|
});
|
||||||
|
|
||||||
jQuery(window).on('resize', windowResized);
|
jQuery(window).on('resize', windowResized);
|
||||||
}
|
}
|
||||||
|
|
||||||
function reinit(_params, loaded) {
|
function reinit(_params, loaded) {
|
||||||
params = _params;
|
params = _params;
|
||||||
params.query = params.query || {};
|
params.query = params.query || {};
|
||||||
pagerPresenter.reinit({query: params.query});
|
pagerPresenter.reinit({query: params.query});
|
||||||
loaded();
|
loaded();
|
||||||
softRender();
|
softRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
function deinit() {
|
function deinit() {
|
||||||
pagerPresenter.deinit();
|
pagerPresenter.deinit();
|
||||||
jQuery(window).off('resize', windowResized);
|
jQuery(window).off('resize', windowResized);
|
||||||
}
|
}
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
$el.html(templates.list({
|
$el.html(templates.list({
|
||||||
massTag: params.query.massTag,
|
massTag: params.query.massTag,
|
||||||
privileges: privileges,
|
privileges: privileges,
|
||||||
browsingSettings: browsingSettings.getSettings()}));
|
browsingSettings: browsingSettings.getSettings()}));
|
||||||
$searchInput = $el.find('input[name=query]');
|
$searchInput = $el.find('input[name=query]');
|
||||||
App.Controls.AutoCompleteInput($searchInput);
|
App.Controls.AutoCompleteInput($searchInput);
|
||||||
|
|
||||||
$searchInput.val(params.query.query);
|
$searchInput.val(params.query.query);
|
||||||
$searchInput.keydown(searchInputKeyPressed);
|
$searchInput.keydown(searchInputKeyPressed);
|
||||||
$el.find('form').submit(searchFormSubmitted);
|
$el.find('form').submit(searchFormSubmitted);
|
||||||
$el.find('[name=mass-tag]').click(massTagButtonClicked);
|
$el.find('[name=mass-tag]').click(massTagButtonClicked);
|
||||||
$el.find('.safety button').click(safetyButtonClicked);
|
$el.find('.safety button').click(safetyButtonClicked);
|
||||||
|
|
||||||
keyboard.keyup('p', function() {
|
keyboard.keyup('p', function() {
|
||||||
$el.find('.posts li a').eq(0).focus();
|
$el.find('.posts li a').eq(0).focus();
|
||||||
});
|
});
|
||||||
|
|
||||||
keyboard.keyup('q', function() {
|
keyboard.keyup('q', function() {
|
||||||
$searchInput.eq(0).focus().select();
|
$searchInput.eq(0).focus().select();
|
||||||
});
|
});
|
||||||
|
|
||||||
windowResized();
|
windowResized();
|
||||||
}
|
}
|
||||||
|
|
||||||
function safetyButtonClicked(e) {
|
function safetyButtonClicked(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var settings = browsingSettings.getSettings();
|
var settings = browsingSettings.getSettings();
|
||||||
var buttonClass = jQuery(e.currentTarget).attr('class').split(' ')[0];
|
var buttonClass = jQuery(e.currentTarget).attr('class').split(' ')[0];
|
||||||
var enabled = jQuery(e.currentTarget).hasClass('disabled');
|
var enabled = jQuery(e.currentTarget).hasClass('disabled');
|
||||||
jQuery(e.currentTarget).toggleClass('disabled');
|
jQuery(e.currentTarget).toggleClass('disabled');
|
||||||
if (buttonClass === 'safety-unsafe') {
|
if (buttonClass === 'safety-unsafe') {
|
||||||
settings.listPosts.unsafe = enabled;
|
settings.listPosts.unsafe = enabled;
|
||||||
} else if (buttonClass === 'safety-sketchy') {
|
} else if (buttonClass === 'safety-sketchy') {
|
||||||
settings.listPosts.sketchy = enabled;
|
settings.listPosts.sketchy = enabled;
|
||||||
} else if (buttonClass === 'safety-safe') {
|
} else if (buttonClass === 'safety-safe') {
|
||||||
settings.listPosts.safe = enabled;
|
settings.listPosts.safe = enabled;
|
||||||
}
|
}
|
||||||
promise.wait(browsingSettings.setSettings(settings))
|
promise.wait(browsingSettings.setSettings(settings))
|
||||||
.then(function() {
|
.then(function() {
|
||||||
reinit(params, function() {});
|
reinit(params, function() {});
|
||||||
}).fail(function() {
|
}).fail(function() {
|
||||||
console.log(arguments);
|
console.log(arguments);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function softRender() {
|
function softRender() {
|
||||||
$searchInput.val(params.query.query);
|
$searchInput.val(params.query.query);
|
||||||
|
|
||||||
var $massTagInfo = $el.find('.mass-tag-info');
|
var $massTagInfo = $el.find('.mass-tag-info');
|
||||||
if (params.query.massTag) {
|
if (params.query.massTag) {
|
||||||
$massTagInfo.show();
|
$massTagInfo.show();
|
||||||
$massTagInfo.find('span').text(params.query.massTag);
|
$massTagInfo.find('span').text(params.query.massTag);
|
||||||
} else {
|
} else {
|
||||||
$massTagInfo.hide();
|
$massTagInfo.hide();
|
||||||
}
|
}
|
||||||
_.map($el.find('.posts .post-small'), function(postNode) { softRenderPost(jQuery(postNode).parents('li')); });
|
_.map($el.find('.posts .post-small'), function(postNode) { softRenderPost(jQuery(postNode).parents('li')); });
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderPosts($page, posts) {
|
function renderPosts($page, posts) {
|
||||||
var $target = $page.find('.posts');
|
var $target = $page.find('.posts');
|
||||||
_.each(posts, function(post) {
|
_.each(posts, function(post) {
|
||||||
if (!shouldSkipPost(post)) {
|
if (!shouldSkipPost(post)) {
|
||||||
var $post = renderPost(post);
|
var $post = renderPost(post);
|
||||||
softRenderPost($post);
|
softRenderPost($post);
|
||||||
$target.append($post);
|
$target.append($post);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
windowResized();
|
windowResized();
|
||||||
}
|
}
|
||||||
|
|
||||||
function shouldSkipPost(post) {
|
function shouldSkipPost(post) {
|
||||||
var settings = browsingSettings.getSettings();
|
var settings = browsingSettings.getSettings();
|
||||||
if (post.ownScore < 0 && settings.hideDownvoted) {
|
if (post.ownScore < 0 && settings.hideDownvoted) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (settings.listPosts) {
|
if (settings.listPosts) {
|
||||||
if (post.safety === 'safe' && !settings.listPosts.safe) {
|
if (post.safety === 'safe' && !settings.listPosts.safe) {
|
||||||
return true;
|
return true;
|
||||||
} else if (post.safety === 'sketchy' && !settings.listPosts.sketchy) {
|
} else if (post.safety === 'sketchy' && !settings.listPosts.sketchy) {
|
||||||
return true;
|
return true;
|
||||||
} else if (post.safety === 'unsafe' && !settings.listPosts.unsafe) {
|
} else if (post.safety === 'unsafe' && !settings.listPosts.unsafe) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderPost(post) {
|
function renderPost(post) {
|
||||||
var $post = jQuery('<li>' + templates.listItem({
|
var $post = jQuery('<li>' + templates.listItem({
|
||||||
util: util,
|
util: util,
|
||||||
query: params.query,
|
query: params.query,
|
||||||
post: post,
|
post: post,
|
||||||
canViewPosts: privileges.canViewPosts,
|
canViewPosts: privileges.canViewPosts,
|
||||||
}) + '</li>');
|
}) + '</li>');
|
||||||
$post.data('post', post);
|
$post.data('post', post);
|
||||||
util.loadImagesNicely($post.find('img'));
|
util.loadImagesNicely($post.find('img'));
|
||||||
return $post;
|
return $post;
|
||||||
}
|
}
|
||||||
|
|
||||||
function softRenderPost($post) {
|
function softRenderPost($post) {
|
||||||
var classes = [];
|
var classes = [];
|
||||||
if (params.query.massTag) {
|
if (params.query.massTag) {
|
||||||
var post = $post.data('post');
|
var post = $post.data('post');
|
||||||
if (_.contains(_.map(post.tags, function(tag) { return tag.name.toLowerCase(); }), params.query.massTag.toLowerCase())) {
|
if (_.contains(_.map(post.tags, function(tag) { return tag.name.toLowerCase(); }), params.query.massTag.toLowerCase())) {
|
||||||
classes.push('tagged');
|
classes.push('tagged');
|
||||||
} else {
|
} else {
|
||||||
classes.push('untagged');
|
classes.push('untagged');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$post.toggleClass('tagged', _.contains(classes, 'tagged'));
|
$post.toggleClass('tagged', _.contains(classes, 'tagged'));
|
||||||
$post.toggleClass('untagged', _.contains(classes, 'untagged'));
|
$post.toggleClass('untagged', _.contains(classes, 'untagged'));
|
||||||
$post.find('.action').toggle(_.any(classes));
|
$post.find('.action').toggle(_.any(classes));
|
||||||
$post.find('.action button').text(_.contains(classes, 'tagged') ? 'Tagged' : 'Untagged').unbind('click').click(postTagButtonClicked);
|
$post.find('.action button').text(_.contains(classes, 'tagged') ? 'Tagged' : 'Untagged').unbind('click').click(postTagButtonClicked);
|
||||||
}
|
}
|
||||||
|
|
||||||
function windowResized() {
|
function windowResized() {
|
||||||
var $list = $el.find('ul.posts');
|
var $list = $el.find('ul.posts');
|
||||||
var $posts = $list.find('.post-small');
|
var $posts = $list.find('.post-small');
|
||||||
var $firstPost = $posts.eq(0);
|
var $firstPost = $posts.eq(0);
|
||||||
var $lastPost = $firstPost;
|
var $lastPost = $firstPost;
|
||||||
for (var i = 1; i < $posts.length; i ++) {
|
for (var i = 1; i < $posts.length; i ++) {
|
||||||
$lastPost = $posts.eq(i-1);
|
$lastPost = $posts.eq(i-1);
|
||||||
if ($posts.eq(i).offset().left < $lastPost.offset().left) {
|
if ($posts.eq(i).offset().left < $lastPost.offset().left) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($firstPost.length === 0) {
|
if ($firstPost.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$el.find('.search').width($lastPost.offset().left + $lastPost.width() - $firstPost.offset().left);
|
$el.find('.search').width($lastPost.offset().left + $lastPost.width() - $firstPost.offset().left);
|
||||||
}
|
}
|
||||||
|
|
||||||
function postTagButtonClicked(e) {
|
function postTagButtonClicked(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var $post = jQuery(e.target).parents('li');
|
var $post = jQuery(e.target).parents('li');
|
||||||
var post = $post.data('post');
|
var post = $post.data('post');
|
||||||
var tags = _.pluck(post.tags, 'name');
|
var tags = _.pluck(post.tags, 'name');
|
||||||
if (_.contains(_.map(tags, function(tag) { return tag.toLowerCase(); }), params.query.massTag.toLowerCase())) {
|
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(); });
|
tags = _.filter(tags, function(tag) { return tag.toLowerCase() !== params.query.massTag.toLowerCase(); });
|
||||||
} else {
|
} else {
|
||||||
tags.push(params.query.massTag);
|
tags.push(params.query.massTag);
|
||||||
}
|
}
|
||||||
var formData = {};
|
var formData = {};
|
||||||
formData.seenEditTime = post.lastEditTime;
|
formData.seenEditTime = post.lastEditTime;
|
||||||
formData.tags = tags.join(' ');
|
formData.tags = tags.join(' ');
|
||||||
promise.wait(api.post('/posts/' + post.id, formData))
|
promise.wait(api.post('/posts/' + post.id, formData))
|
||||||
.then(function(response) {
|
.then(function(response) {
|
||||||
post = response.json;
|
post = response.json;
|
||||||
$post.data('post', post);
|
$post.data('post', post);
|
||||||
softRenderPost($post);
|
softRenderPost($post);
|
||||||
}).fail(function(response) {
|
}).fail(function(response) {
|
||||||
window.alert(response.json && response.json.error || response);
|
window.alert(response.json && response.json.error || response);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function searchInputKeyPressed(e) {
|
function searchInputKeyPressed(e) {
|
||||||
if (e.which !== KEY_RETURN) {
|
if (e.which !== KEY_RETURN) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
updateSearch();
|
updateSearch();
|
||||||
}
|
}
|
||||||
|
|
||||||
function massTagButtonClicked(e) {
|
function massTagButtonClicked(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
params.query.massTag = window.prompt('Enter tag to tag with:');
|
params.query.massTag = window.prompt('Enter tag to tag with:');
|
||||||
pagerPresenter.setQuery(params.query);
|
pagerPresenter.setQuery(params.query);
|
||||||
}
|
}
|
||||||
|
|
||||||
function searchFormSubmitted(e) {
|
function searchFormSubmitted(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
updateSearch();
|
updateSearch();
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateSearch() {
|
function updateSearch() {
|
||||||
$searchInput.blur();
|
$searchInput.blur();
|
||||||
params.query.query = $searchInput.val().trim();
|
params.query.query = $searchInput.val().trim();
|
||||||
params.query.page = 1;
|
params.query.page = 1;
|
||||||
pagerPresenter.setQuery(params.query);
|
pagerPresenter.setQuery(params.query);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
init: init,
|
init: init,
|
||||||
reinit: reinit,
|
reinit: reinit,
|
||||||
deinit: deinit,
|
deinit: deinit,
|
||||||
render: render,
|
render: render,
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,192 +2,192 @@ var App = App || {};
|
||||||
App.Presenters = App.Presenters || {};
|
App.Presenters = App.Presenters || {};
|
||||||
|
|
||||||
App.Presenters.PostNotesPresenter = function(
|
App.Presenters.PostNotesPresenter = function(
|
||||||
jQuery,
|
jQuery,
|
||||||
util,
|
util,
|
||||||
promise,
|
promise,
|
||||||
api,
|
api,
|
||||||
auth,
|
auth,
|
||||||
draggable,
|
draggable,
|
||||||
resizable) {
|
resizable) {
|
||||||
|
|
||||||
var post;
|
var post;
|
||||||
var notes;
|
var notes;
|
||||||
var templates = {};
|
var templates = {};
|
||||||
var $target;
|
var $target;
|
||||||
var $form;
|
var $form;
|
||||||
var privileges = {};
|
var privileges = {};
|
||||||
|
|
||||||
function init(params, loaded) {
|
function init(params, loaded) {
|
||||||
$target = params.$target;
|
$target = params.$target;
|
||||||
post = params.post;
|
post = params.post;
|
||||||
notes = params.notes || [];
|
notes = params.notes || [];
|
||||||
|
|
||||||
privileges.canDeletePostNotes = auth.hasPrivilege(auth.privileges.deletePostNotes);
|
privileges.canDeletePostNotes = auth.hasPrivilege(auth.privileges.deletePostNotes);
|
||||||
privileges.canEditPostNotes = auth.hasPrivilege(auth.privileges.editPostNotes);
|
privileges.canEditPostNotes = auth.hasPrivilege(auth.privileges.editPostNotes);
|
||||||
|
|
||||||
promise.wait(util.promiseTemplate('post-notes'))
|
promise.wait(util.promiseTemplate('post-notes'))
|
||||||
.then(function(postNotesTemplate) {
|
.then(function(postNotesTemplate) {
|
||||||
templates.postNotes = postNotesTemplate;
|
templates.postNotes = postNotesTemplate;
|
||||||
render();
|
render();
|
||||||
loaded();
|
loaded();
|
||||||
}).fail(function() {
|
}).fail(function() {
|
||||||
console.log(arguments);
|
console.log(arguments);
|
||||||
loaded();
|
loaded();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function addNewPostNote() {
|
function addNewPostNote() {
|
||||||
notes.push({left: 10.0, top: 10.0, width: 10.0, height: 10.0, text: '…'});
|
notes.push({left: 10.0, top: 10.0, width: 10.0, height: 10.0, text: '…'});
|
||||||
}
|
}
|
||||||
|
|
||||||
function addNewPostNoteAndRender() {
|
function addNewPostNoteAndRender() {
|
||||||
addNewPostNote();
|
addNewPostNote();
|
||||||
render();
|
render();
|
||||||
}
|
}
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
$target.html(templates.postNotes({
|
$target.html(templates.postNotes({
|
||||||
privileges: privileges,
|
privileges: privileges,
|
||||||
post: post,
|
post: post,
|
||||||
notes: notes,
|
notes: notes,
|
||||||
util: util}));
|
util: util}));
|
||||||
|
|
||||||
$form = $target.find('.post-note-edit');
|
$form = $target.find('.post-note-edit');
|
||||||
var $postNotes = $target.find('.post-note');
|
var $postNotes = $target.find('.post-note');
|
||||||
|
|
||||||
$postNotes.each(function(i) {
|
$postNotes.each(function(i) {
|
||||||
var postNote = notes[i];
|
var postNote = notes[i];
|
||||||
var $postNote = jQuery(this);
|
var $postNote = jQuery(this);
|
||||||
$postNote.data('postNote', postNote);
|
$postNote.data('postNote', postNote);
|
||||||
$postNote.find('.text-wrapper').click(postNoteClicked);
|
$postNote.find('.text-wrapper').click(postNoteClicked);
|
||||||
postNote.$element = $postNote;
|
postNote.$element = $postNote;
|
||||||
draggable.makeDraggable($postNote, draggable.relativeDragStrategy, true);
|
draggable.makeDraggable($postNote, draggable.relativeDragStrategy, true);
|
||||||
resizable.makeResizable($postNote, true);
|
resizable.makeResizable($postNote, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
$form.find('button').click(formSubmitted);
|
$form.find('button').click(formSubmitted);
|
||||||
}
|
}
|
||||||
|
|
||||||
function formSubmitted(e) {
|
function formSubmitted(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var $button = jQuery(e.target);
|
var $button = jQuery(e.target);
|
||||||
var sender = $button.val();
|
var sender = $button.val();
|
||||||
|
|
||||||
var postNote = $form.data('postNote');
|
var postNote = $form.data('postNote');
|
||||||
postNote.left = (postNote.$element.offset().left - $target.offset().left) * 100.0 / $target.outerWidth();
|
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.top = (postNote.$element.offset().top - $target.offset().top) * 100.0 / $target.outerHeight();
|
||||||
postNote.width = postNote.$element.width() * 100.0 / $target.outerWidth();
|
postNote.width = postNote.$element.width() * 100.0 / $target.outerWidth();
|
||||||
postNote.height = postNote.$element.height() * 100.0 / $target.outerHeight();
|
postNote.height = postNote.$element.height() * 100.0 / $target.outerHeight();
|
||||||
postNote.text = $form.find('textarea').val();
|
postNote.text = $form.find('textarea').val();
|
||||||
|
|
||||||
if (sender === 'cancel') {
|
if (sender === 'cancel') {
|
||||||
hideForm();
|
hideForm();
|
||||||
} else if (sender === 'remove') {
|
} else if (sender === 'remove') {
|
||||||
removePostNote(postNote);
|
removePostNote(postNote);
|
||||||
} else if (sender === 'save') {
|
} else if (sender === 'save') {
|
||||||
savePostNote(postNote);
|
savePostNote(postNote);
|
||||||
} else if (sender === 'preview') {
|
} else if (sender === 'preview') {
|
||||||
previewPostNote(postNote);
|
previewPostNote(postNote);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function removePostNote(postNote) {
|
function removePostNote(postNote) {
|
||||||
if (postNote.id) {
|
if (postNote.id) {
|
||||||
if (window.confirm('Are you sure you want to delete this note?')) {
|
if (window.confirm('Are you sure you want to delete this note?')) {
|
||||||
promise.wait(api.delete('/notes/' + postNote.id))
|
promise.wait(api.delete('/notes/' + postNote.id))
|
||||||
.then(function() {
|
.then(function() {
|
||||||
hideForm();
|
hideForm();
|
||||||
postNote.$element.remove();
|
postNote.$element.remove();
|
||||||
}).fail(function(response) {
|
}).fail(function(response) {
|
||||||
window.alert(response.json && response.json.error || response);
|
window.alert(response.json && response.json.error || response);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
postNote.$element.remove();
|
postNote.$element.remove();
|
||||||
hideForm();
|
hideForm();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function savePostNote(postNote) {
|
function savePostNote(postNote) {
|
||||||
if (window.confirm('Are you sure you want to save this note?')) {
|
if (window.confirm('Are you sure you want to save this note?')) {
|
||||||
var formData = {
|
var formData = {
|
||||||
left: postNote.left,
|
left: postNote.left,
|
||||||
top: postNote.top,
|
top: postNote.top,
|
||||||
width: postNote.width,
|
width: postNote.width,
|
||||||
height: postNote.height,
|
height: postNote.height,
|
||||||
text: postNote.text,
|
text: postNote.text,
|
||||||
};
|
};
|
||||||
|
|
||||||
var p = postNote.id ?
|
var p = postNote.id ?
|
||||||
api.put('/notes/' + postNote.id, formData) :
|
api.put('/notes/' + postNote.id, formData) :
|
||||||
api.post('/notes/' + post.id, formData);
|
api.post('/notes/' + post.id, formData);
|
||||||
|
|
||||||
promise.wait(p)
|
promise.wait(p)
|
||||||
.then(function(response) {
|
.then(function(response) {
|
||||||
hideForm();
|
hideForm();
|
||||||
postNote.id = response.json.id;
|
postNote.id = response.json.id;
|
||||||
postNote.$element.data('postNote', postNote);
|
postNote.$element.data('postNote', postNote);
|
||||||
render();
|
render();
|
||||||
}).fail(function(response) {
|
}).fail(function(response) {
|
||||||
window.alert(response.json && response.json.error || response);
|
window.alert(response.json && response.json.error || response);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function previewPostNote(postNote) {
|
function previewPostNote(postNote) {
|
||||||
var previewText = $form.find('textarea').val();
|
var previewText = $form.find('textarea').val();
|
||||||
postNote.$element.find('.text').html(util.formatMarkdown(previewText));
|
postNote.$element.find('.text').html(util.formatMarkdown(previewText));
|
||||||
showPostNoteText(postNote);
|
showPostNoteText(postNote);
|
||||||
}
|
}
|
||||||
|
|
||||||
function showPostNoteText(postNote) {
|
function showPostNoteText(postNote) {
|
||||||
postNote.$element.find('.text-wrapper').show();
|
postNote.$element.find('.text-wrapper').show();
|
||||||
}
|
}
|
||||||
|
|
||||||
function hidePostNoteText(postNote) {
|
function hidePostNoteText(postNote) {
|
||||||
postNote.$element.find('.text-wrapper').css('display', '');
|
postNote.$element.find('.text-wrapper').css('display', '');
|
||||||
}
|
}
|
||||||
|
|
||||||
function postNoteClicked(e) {
|
function postNoteClicked(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var $postNote = jQuery(e.currentTarget).parents('.post-note');
|
var $postNote = jQuery(e.currentTarget).parents('.post-note');
|
||||||
if ($postNote.hasClass('resizing') || $postNote.hasClass('dragging')) {
|
if ($postNote.hasClass('resizing') || $postNote.hasClass('dragging')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
showFormForPostNote($postNote);
|
showFormForPostNote($postNote);
|
||||||
}
|
}
|
||||||
|
|
||||||
function showFormForPostNote($postNote) {
|
function showFormForPostNote($postNote) {
|
||||||
hideForm();
|
hideForm();
|
||||||
var postNote = $postNote.data('postNote');
|
var postNote = $postNote.data('postNote');
|
||||||
$form.data('postNote', postNote);
|
$form.data('postNote', postNote);
|
||||||
$form.find('textarea').val(postNote.text);
|
$form.find('textarea').val(postNote.text);
|
||||||
$form.show();
|
$form.show();
|
||||||
draggable.makeDraggable($form, draggable.absoluteDragStrategy, false);
|
draggable.makeDraggable($form, draggable.absoluteDragStrategy, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
function hideForm() {
|
function hideForm() {
|
||||||
var previousPostNote = $form.data('post-note');
|
var previousPostNote = $form.data('post-note');
|
||||||
if (previousPostNote) {
|
if (previousPostNote) {
|
||||||
hidePostNoteText(previousPostNote);
|
hidePostNoteText(previousPostNote);
|
||||||
}
|
}
|
||||||
$form.hide();
|
$form.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
init: init,
|
init: init,
|
||||||
render: render,
|
render: render,
|
||||||
addNewPostNote: addNewPostNoteAndRender,
|
addNewPostNote: addNewPostNoteAndRender,
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
App.DI.register('postNotesPresenter', [
|
App.DI.register('postNotesPresenter', [
|
||||||
'jQuery',
|
'jQuery',
|
||||||
'util',
|
'util',
|
||||||
'promise',
|
'promise',
|
||||||
'api',
|
'api',
|
||||||
'auth',
|
'auth',
|
||||||
'draggable',
|
'draggable',
|
||||||
'resizable'],
|
'resizable'],
|
||||||
App.Presenters.PostNotesPresenter);
|
App.Presenters.PostNotesPresenter);
|
||||||
|
|
|
@ -2,349 +2,349 @@ var App = App || {};
|
||||||
App.Presenters = App.Presenters || {};
|
App.Presenters = App.Presenters || {};
|
||||||
|
|
||||||
App.Presenters.PostPresenter = function(
|
App.Presenters.PostPresenter = function(
|
||||||
_,
|
_,
|
||||||
jQuery,
|
jQuery,
|
||||||
util,
|
util,
|
||||||
promise,
|
promise,
|
||||||
api,
|
api,
|
||||||
auth,
|
auth,
|
||||||
router,
|
router,
|
||||||
keyboard,
|
keyboard,
|
||||||
presenterManager,
|
presenterManager,
|
||||||
postsAroundCalculator,
|
postsAroundCalculator,
|
||||||
postEditPresenter,
|
postEditPresenter,
|
||||||
postContentPresenter,
|
postContentPresenter,
|
||||||
commentListPresenter,
|
commentListPresenter,
|
||||||
topNavigationPresenter,
|
topNavigationPresenter,
|
||||||
messagePresenter) {
|
messagePresenter) {
|
||||||
|
|
||||||
var $el = jQuery('#content');
|
var $el = jQuery('#content');
|
||||||
var $messages = $el;
|
var $messages = $el;
|
||||||
|
|
||||||
var templates = {};
|
var templates = {};
|
||||||
var params;
|
var params;
|
||||||
|
|
||||||
var postNameOrId;
|
var postNameOrId;
|
||||||
var post;
|
var post;
|
||||||
|
|
||||||
var privileges = {};
|
var privileges = {};
|
||||||
|
|
||||||
function init(params, loaded) {
|
function init(params, loaded) {
|
||||||
topNavigationPresenter.select('posts');
|
topNavigationPresenter.select('posts');
|
||||||
postsAroundCalculator.resetCache();
|
postsAroundCalculator.resetCache();
|
||||||
|
|
||||||
privileges.canDeletePosts = auth.hasPrivilege(auth.privileges.deletePosts);
|
privileges.canDeletePosts = auth.hasPrivilege(auth.privileges.deletePosts);
|
||||||
privileges.canFeaturePosts = auth.hasPrivilege(auth.privileges.featurePosts);
|
privileges.canFeaturePosts = auth.hasPrivilege(auth.privileges.featurePosts);
|
||||||
privileges.canViewHistory = auth.hasPrivilege(auth.privileges.viewHistory);
|
privileges.canViewHistory = auth.hasPrivilege(auth.privileges.viewHistory);
|
||||||
privileges.canAddPostNotes = auth.hasPrivilege(auth.privileges.addPostNotes);
|
privileges.canAddPostNotes = auth.hasPrivilege(auth.privileges.addPostNotes);
|
||||||
|
|
||||||
promise.wait(
|
promise.wait(
|
||||||
util.promiseTemplate('post'),
|
util.promiseTemplate('post'),
|
||||||
util.promiseTemplate('history'))
|
util.promiseTemplate('history'))
|
||||||
.then(function(
|
.then(function(
|
||||||
postTemplate,
|
postTemplate,
|
||||||
historyTemplate) {
|
historyTemplate) {
|
||||||
templates.post = postTemplate;
|
templates.post = postTemplate;
|
||||||
templates.history = historyTemplate;
|
templates.history = historyTemplate;
|
||||||
|
|
||||||
reinit(params, loaded);
|
reinit(params, loaded);
|
||||||
}).fail(function(response) {
|
}).fail(function(response) {
|
||||||
showGenericError(response);
|
showGenericError(response);
|
||||||
loaded();
|
loaded();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function reinit(_params, loaded) {
|
function reinit(_params, loaded) {
|
||||||
params = _params;
|
params = _params;
|
||||||
params.query = params.query || {};
|
params.query = params.query || {};
|
||||||
params.query.page = parseInt(params.query.page) || 1;
|
params.query.page = parseInt(params.query.page) || 1;
|
||||||
|
|
||||||
postNameOrId = params.postNameOrId;
|
postNameOrId = params.postNameOrId;
|
||||||
|
|
||||||
promise.wait(refreshPost())
|
promise.wait(refreshPost())
|
||||||
.then(function() {
|
.then(function() {
|
||||||
topNavigationPresenter.changeTitle('@' + post.id);
|
topNavigationPresenter.changeTitle('@' + post.id);
|
||||||
render();
|
render();
|
||||||
loaded();
|
loaded();
|
||||||
|
|
||||||
presenterManager.initPresenters([
|
presenterManager.initPresenters([
|
||||||
[postContentPresenter, {post: post, $target: $el.find('#post-content-target')}],
|
[postContentPresenter, {post: post, $target: $el.find('#post-content-target')}],
|
||||||
[postEditPresenter, {post: post, $target: $el.find('#post-edit-target'), updateCallback: postEdited}],
|
[postEditPresenter, {post: post, $target: $el.find('#post-edit-target'), updateCallback: postEdited}],
|
||||||
[commentListPresenter, {post: post, $target: $el.find('#post-comments-target')}]],
|
[commentListPresenter, {post: post, $target: $el.find('#post-comments-target')}]],
|
||||||
function() { });
|
function() { });
|
||||||
|
|
||||||
}).fail(function() {
|
}).fail(function() {
|
||||||
console.log(arguments);
|
console.log(arguments);
|
||||||
loaded();
|
loaded();
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function attachLinksToPostsAround() {
|
function attachLinksToPostsAround() {
|
||||||
promise.wait(postsAroundCalculator.getLinksToPostsAround(params.query, post.id))
|
promise.wait(postsAroundCalculator.getLinksToPostsAround(params.query, post.id))
|
||||||
.then(function(nextPostUrl, prevPostUrl) {
|
.then(function(nextPostUrl, prevPostUrl) {
|
||||||
var $prevPost = $el.find('#post-current-search .right a');
|
var $prevPost = $el.find('#post-current-search .right a');
|
||||||
var $nextPost = $el.find('#post-current-search .left a');
|
var $nextPost = $el.find('#post-current-search .left a');
|
||||||
|
|
||||||
if (nextPostUrl) {
|
if (nextPostUrl) {
|
||||||
$nextPost.addClass('enabled');
|
$nextPost.addClass('enabled');
|
||||||
$nextPost.attr('href', nextPostUrl);
|
$nextPost.attr('href', nextPostUrl);
|
||||||
keyboard.keyup('a', function() {
|
keyboard.keyup('a', function() {
|
||||||
router.navigate(nextPostUrl);
|
router.navigate(nextPostUrl);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
$nextPost.removeClass('enabled');
|
$nextPost.removeClass('enabled');
|
||||||
$nextPost.removeAttr('href');
|
$nextPost.removeAttr('href');
|
||||||
keyboard.unbind('a');
|
keyboard.unbind('a');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prevPostUrl) {
|
if (prevPostUrl) {
|
||||||
$prevPost.addClass('enabled');
|
$prevPost.addClass('enabled');
|
||||||
$prevPost.attr('href', prevPostUrl);
|
$prevPost.attr('href', prevPostUrl);
|
||||||
keyboard.keyup('d', function() {
|
keyboard.keyup('d', function() {
|
||||||
router.navigate(prevPostUrl);
|
router.navigate(prevPostUrl);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
$prevPost.removeClass('enabled');
|
$prevPost.removeClass('enabled');
|
||||||
$prevPost.removeAttr('href');
|
$prevPost.removeAttr('href');
|
||||||
keyboard.unbind('d');
|
keyboard.unbind('d');
|
||||||
}
|
}
|
||||||
}).fail(function() {
|
}).fail(function() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function refreshPost() {
|
function refreshPost() {
|
||||||
return promise.make(function(resolve, reject) {
|
return promise.make(function(resolve, reject) {
|
||||||
promise.wait(api.get('/posts/' + postNameOrId))
|
promise.wait(api.get('/posts/' + postNameOrId))
|
||||||
.then(function(postResponse) {
|
.then(function(postResponse) {
|
||||||
post = postResponse.json;
|
post = postResponse.json;
|
||||||
resolve();
|
resolve();
|
||||||
}).fail(function(response) {
|
}).fail(function(response) {
|
||||||
showGenericError(response);
|
showGenericError(response);
|
||||||
reject();
|
reject();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
$el.html(renderPostTemplate());
|
$el.html(renderPostTemplate());
|
||||||
$messages = $el.find('.messages');
|
$messages = $el.find('.messages');
|
||||||
|
|
||||||
keyboard.keyup('e', function() {
|
keyboard.keyup('e', function() {
|
||||||
editButtonClicked(null);
|
editButtonClicked(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
keyboard.keyup('f', function() {
|
keyboard.keyup('f', function() {
|
||||||
var $wrapper = $el.find('.object-wrapper');
|
var $wrapper = $el.find('.object-wrapper');
|
||||||
if ($wrapper.data('full')) {
|
if ($wrapper.data('full')) {
|
||||||
$wrapper.css({maxWidth: $wrapper.attr('data-width') + 'px', width: 'auto'});
|
$wrapper.css({maxWidth: $wrapper.attr('data-width') + 'px', width: 'auto'});
|
||||||
$wrapper.data('full', false);
|
$wrapper.data('full', false);
|
||||||
} else {
|
} else {
|
||||||
$wrapper.css({maxWidth: null, width: $wrapper.attr('data-width')});
|
$wrapper.css({maxWidth: null, width: $wrapper.attr('data-width')});
|
||||||
$wrapper.data('full', true);
|
$wrapper.data('full', true);
|
||||||
}
|
}
|
||||||
postContentPresenter.updatePostNotesSize();
|
postContentPresenter.updatePostNotesSize();
|
||||||
});
|
});
|
||||||
|
|
||||||
attachSidebarEvents();
|
attachSidebarEvents();
|
||||||
|
|
||||||
attachLinksToPostsAround();
|
attachLinksToPostsAround();
|
||||||
}
|
}
|
||||||
|
|
||||||
function postEdited(newPost) {
|
function postEdited(newPost) {
|
||||||
post = newPost;
|
post = newPost;
|
||||||
hideEditForm();
|
hideEditForm();
|
||||||
softRender();
|
softRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
function softRender() {
|
function softRender() {
|
||||||
renderSidebar();
|
renderSidebar();
|
||||||
$el.find('video').prop('loop', post.flags.loop);
|
$el.find('video').prop('loop', post.flags.loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderSidebar() {
|
function renderSidebar() {
|
||||||
$el.find('#sidebar').html(jQuery(renderPostTemplate()).find('#sidebar').html());
|
$el.find('#sidebar').html(jQuery(renderPostTemplate()).find('#sidebar').html());
|
||||||
attachSidebarEvents();
|
attachSidebarEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderPostTemplate() {
|
function renderPostTemplate() {
|
||||||
return templates.post({
|
return templates.post({
|
||||||
query: params.query,
|
query: params.query,
|
||||||
post: post,
|
post: post,
|
||||||
ownScore: post.ownScore,
|
ownScore: post.ownScore,
|
||||||
postFavorites: post.favorites,
|
postFavorites: post.favorites,
|
||||||
postHistory: post.history,
|
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; }),
|
hasFav: _.any(post.favorites, function(favUser) { return favUser.id === auth.getCurrentUser().id; }),
|
||||||
isLoggedIn: auth.isLoggedIn(),
|
isLoggedIn: auth.isLoggedIn(),
|
||||||
privileges: privileges,
|
privileges: privileges,
|
||||||
editPrivileges: postEditPresenter.getPrivileges(),
|
editPrivileges: postEditPresenter.getPrivileges(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function attachSidebarEvents() {
|
function attachSidebarEvents() {
|
||||||
$el.find('#sidebar .delete').click(deleteButtonClicked);
|
$el.find('#sidebar .delete').click(deleteButtonClicked);
|
||||||
$el.find('#sidebar .feature').click(featureButtonClicked);
|
$el.find('#sidebar .feature').click(featureButtonClicked);
|
||||||
$el.find('#sidebar .edit').click(editButtonClicked);
|
$el.find('#sidebar .edit').click(editButtonClicked);
|
||||||
$el.find('#sidebar .history').click(historyButtonClicked);
|
$el.find('#sidebar .history').click(historyButtonClicked);
|
||||||
$el.find('#sidebar .add-favorite').click(addFavoriteButtonClicked);
|
$el.find('#sidebar .add-favorite').click(addFavoriteButtonClicked);
|
||||||
$el.find('#sidebar .delete-favorite').click(deleteFavoriteButtonClicked);
|
$el.find('#sidebar .delete-favorite').click(deleteFavoriteButtonClicked);
|
||||||
$el.find('#sidebar .score-up').click(scoreUpButtonClicked);
|
$el.find('#sidebar .score-up').click(scoreUpButtonClicked);
|
||||||
$el.find('#sidebar .score-down').click(scoreDownButtonClicked);
|
$el.find('#sidebar .score-down').click(scoreDownButtonClicked);
|
||||||
$el.find('#sidebar .add-note').click(addNoteButtonClicked);
|
$el.find('#sidebar .add-note').click(addNoteButtonClicked);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addNoteButtonClicked(e) {
|
function addNoteButtonClicked(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
postContentPresenter.addNewPostNote();
|
postContentPresenter.addNewPostNote();
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteButtonClicked(e) {
|
function deleteButtonClicked(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
messagePresenter.hideMessages($messages);
|
messagePresenter.hideMessages($messages);
|
||||||
if (window.confirm('Do you really want to delete this post?')) {
|
if (window.confirm('Do you really want to delete this post?')) {
|
||||||
deletePost();
|
deletePost();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function deletePost() {
|
function deletePost() {
|
||||||
promise.wait(api.delete('/posts/' + post.id))
|
promise.wait(api.delete('/posts/' + post.id))
|
||||||
.then(function(response) {
|
.then(function(response) {
|
||||||
router.navigate('#/posts');
|
router.navigate('#/posts');
|
||||||
}).fail(showGenericError);
|
}).fail(showGenericError);
|
||||||
}
|
}
|
||||||
|
|
||||||
function featureButtonClicked(e) {
|
function featureButtonClicked(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
messagePresenter.hideMessages($messages);
|
messagePresenter.hideMessages($messages);
|
||||||
if (window.confirm('Do you want to feature this post on the front page?')) {
|
if (window.confirm('Do you want to feature this post on the front page?')) {
|
||||||
featurePost();
|
featurePost();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function featurePost() {
|
function featurePost() {
|
||||||
promise.wait(api.post('/posts/' + post.id + '/feature'))
|
promise.wait(api.post('/posts/' + post.id + '/feature'))
|
||||||
.then(function(response) {
|
.then(function(response) {
|
||||||
router.navigate('#/home');
|
router.navigate('#/home');
|
||||||
}).fail(showGenericError);
|
}).fail(showGenericError);
|
||||||
}
|
}
|
||||||
|
|
||||||
function editButtonClicked(e) {
|
function editButtonClicked(e) {
|
||||||
if (e) {
|
if (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
messagePresenter.hideMessages($messages);
|
messagePresenter.hideMessages($messages);
|
||||||
if ($el.find('#post-edit-target').is(':visible')) {
|
if ($el.find('#post-edit-target').is(':visible')) {
|
||||||
hideEditForm();
|
hideEditForm();
|
||||||
} else {
|
} else {
|
||||||
showEditForm();
|
showEditForm();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function showEditForm() {
|
function showEditForm() {
|
||||||
$el.find('#post-edit-target').slideDown('fast');
|
$el.find('#post-edit-target').slideDown('fast');
|
||||||
util.enableExitConfirmation();
|
util.enableExitConfirmation();
|
||||||
postEditPresenter.focus();
|
postEditPresenter.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
function hideEditForm() {
|
function hideEditForm() {
|
||||||
$el.find('#post-edit-target').slideUp('fast');
|
$el.find('#post-edit-target').slideUp('fast');
|
||||||
util.disableExitConfirmation();
|
util.disableExitConfirmation();
|
||||||
}
|
}
|
||||||
|
|
||||||
function historyButtonClicked(e) {
|
function historyButtonClicked(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if ($el.find('.post-history-wrapper').is(':visible')) {
|
if ($el.find('.post-history-wrapper').is(':visible')) {
|
||||||
hideHistory();
|
hideHistory();
|
||||||
} else {
|
} else {
|
||||||
showHistory();
|
showHistory();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function hideHistory() {
|
function hideHistory() {
|
||||||
$el.find('.post-history-wrapper').slideUp('slow');
|
$el.find('.post-history-wrapper').slideUp('slow');
|
||||||
}
|
}
|
||||||
|
|
||||||
function showHistory() {
|
function showHistory() {
|
||||||
$el.find('.post-history-wrapper').slideDown('slow');
|
$el.find('.post-history-wrapper').slideDown('slow');
|
||||||
}
|
}
|
||||||
|
|
||||||
function addFavoriteButtonClicked(e) {
|
function addFavoriteButtonClicked(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
addFavorite();
|
addFavorite();
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteFavoriteButtonClicked(e) {
|
function deleteFavoriteButtonClicked(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
deleteFavorite();
|
deleteFavorite();
|
||||||
}
|
}
|
||||||
|
|
||||||
function addFavorite() {
|
function addFavorite() {
|
||||||
promise.wait(api.post('/posts/' + post.id + '/favorites'))
|
promise.wait(api.post('/posts/' + post.id + '/favorites'))
|
||||||
.then(function(response) {
|
.then(function(response) {
|
||||||
promise.wait(refreshPost()).then(softRender);
|
promise.wait(refreshPost()).then(softRender);
|
||||||
}).fail(showGenericError);
|
}).fail(showGenericError);
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteFavorite() {
|
function deleteFavorite() {
|
||||||
promise.wait(api.delete('/posts/' + post.id + '/favorites'))
|
promise.wait(api.delete('/posts/' + post.id + '/favorites'))
|
||||||
.then(function(response) {
|
.then(function(response) {
|
||||||
promise.wait(refreshPost()).then(softRender);
|
promise.wait(refreshPost()).then(softRender);
|
||||||
}).fail(showGenericError);
|
}).fail(showGenericError);
|
||||||
}
|
}
|
||||||
|
|
||||||
function scoreUpButtonClicked(e) {
|
function scoreUpButtonClicked(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var $target = jQuery(this);
|
var $target = jQuery(this);
|
||||||
score($target.hasClass('active') ? 0 : 1);
|
score($target.hasClass('active') ? 0 : 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
function scoreDownButtonClicked(e) {
|
function scoreDownButtonClicked(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var $target = jQuery(this);
|
var $target = jQuery(this);
|
||||||
score($target.hasClass('active') ? 0 : -1);
|
score($target.hasClass('active') ? 0 : -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
function score(scoreValue) {
|
function score(scoreValue) {
|
||||||
promise.wait(api.post('/posts/' + post.id + '/score', {score: scoreValue}))
|
promise.wait(api.post('/posts/' + post.id + '/score', {score: scoreValue}))
|
||||||
.then(function() {
|
.then(function() {
|
||||||
promise.wait(refreshPost()).then(softRender);
|
promise.wait(refreshPost()).then(softRender);
|
||||||
}).fail(showGenericError);
|
}).fail(showGenericError);
|
||||||
}
|
}
|
||||||
|
|
||||||
function showGenericError(response) {
|
function showGenericError(response) {
|
||||||
if ($messages === $el) {
|
if ($messages === $el) {
|
||||||
$el.empty();
|
$el.empty();
|
||||||
}
|
}
|
||||||
messagePresenter.showError($messages, response.json && response.json.error || response);
|
messagePresenter.showError($messages, response.json && response.json.error || response);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
init: init,
|
init: init,
|
||||||
reinit: reinit,
|
reinit: reinit,
|
||||||
render: render
|
render: render
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
App.DI.register('postPresenter', [
|
App.DI.register('postPresenter', [
|
||||||
'_',
|
'_',
|
||||||
'jQuery',
|
'jQuery',
|
||||||
'util',
|
'util',
|
||||||
'promise',
|
'promise',
|
||||||
'api',
|
'api',
|
||||||
'auth',
|
'auth',
|
||||||
'router',
|
'router',
|
||||||
'keyboard',
|
'keyboard',
|
||||||
'presenterManager',
|
'presenterManager',
|
||||||
'postsAroundCalculator',
|
'postsAroundCalculator',
|
||||||
'postEditPresenter',
|
'postEditPresenter',
|
||||||
'postContentPresenter',
|
'postContentPresenter',
|
||||||
'commentListPresenter',
|
'commentListPresenter',
|
||||||
'topNavigationPresenter',
|
'topNavigationPresenter',
|
||||||
'messagePresenter'],
|
'messagePresenter'],
|
||||||
App.Presenters.PostPresenter);
|
App.Presenters.PostPresenter);
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -2,43 +2,43 @@ var App = App || {};
|
||||||
App.Controls = App.Controls || {};
|
App.Controls = App.Controls || {};
|
||||||
|
|
||||||
App.Presenters.ProgressPresenter = function(nprogress) {
|
App.Presenters.ProgressPresenter = function(nprogress) {
|
||||||
var nesting = 0;
|
var nesting = 0;
|
||||||
|
|
||||||
function start() {
|
function start() {
|
||||||
nesting ++;
|
nesting ++;
|
||||||
|
|
||||||
if (nesting === 1) {
|
if (nesting === 1) {
|
||||||
nprogress.start();
|
nprogress.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function reset() {
|
function reset() {
|
||||||
nesting = 0;
|
nesting = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function done() {
|
function done() {
|
||||||
if (nesting) {
|
if (nesting) {
|
||||||
nesting --;
|
nesting --;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nesting <= 0) {
|
if (nesting <= 0) {
|
||||||
nprogress.done();
|
nprogress.done();
|
||||||
} else {
|
} else {
|
||||||
nprogress.inc();
|
nprogress.inc();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.setInterval(function() {
|
window.setInterval(function() {
|
||||||
if (nesting <= 0) {
|
if (nesting <= 0) {
|
||||||
nprogress.done();
|
nprogress.done();
|
||||||
}
|
}
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
start: start,
|
start: start,
|
||||||
done: done,
|
done: done,
|
||||||
reset: reset,
|
reset: reset,
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,100 +2,100 @@ var App = App || {};
|
||||||
App.Presenters = App.Presenters || {};
|
App.Presenters = App.Presenters || {};
|
||||||
|
|
||||||
App.Presenters.RegistrationPresenter = function(
|
App.Presenters.RegistrationPresenter = function(
|
||||||
jQuery,
|
jQuery,
|
||||||
util,
|
util,
|
||||||
promise,
|
promise,
|
||||||
api,
|
api,
|
||||||
topNavigationPresenter,
|
topNavigationPresenter,
|
||||||
messagePresenter) {
|
messagePresenter) {
|
||||||
|
|
||||||
var $el = jQuery('#content');
|
var $el = jQuery('#content');
|
||||||
var templates = {};
|
var templates = {};
|
||||||
var $messages;
|
var $messages;
|
||||||
|
|
||||||
function init(params, loaded) {
|
function init(params, loaded) {
|
||||||
topNavigationPresenter.select('register');
|
topNavigationPresenter.select('register');
|
||||||
topNavigationPresenter.changeTitle('Registration');
|
topNavigationPresenter.changeTitle('Registration');
|
||||||
promise.wait(util.promiseTemplate('registration-form'))
|
promise.wait(util.promiseTemplate('registration-form'))
|
||||||
.then(function(template) {
|
.then(function(template) {
|
||||||
templates.registration = template;
|
templates.registration = template;
|
||||||
render();
|
render();
|
||||||
loaded();
|
loaded();
|
||||||
}).fail(function() {
|
}).fail(function() {
|
||||||
console.log(arguments);
|
console.log(arguments);
|
||||||
loaded();
|
loaded();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
$el.html(templates.registration());
|
$el.html(templates.registration());
|
||||||
$el.find('form').submit(registrationFormSubmitted);
|
$el.find('form').submit(registrationFormSubmitted);
|
||||||
$messages = $el.find('.messages');
|
$messages = $el.find('.messages');
|
||||||
$messages.width($el.find('form').width());
|
$messages.width($el.find('form').width());
|
||||||
}
|
}
|
||||||
|
|
||||||
function registrationFormSubmitted(e) {
|
function registrationFormSubmitted(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
messagePresenter.hideMessages($messages);
|
messagePresenter.hideMessages($messages);
|
||||||
|
|
||||||
var formData = {
|
var formData = {
|
||||||
userName: $el.find('[name=userName]').val(),
|
userName: $el.find('[name=userName]').val(),
|
||||||
password: $el.find('[name=password]').val(),
|
password: $el.find('[name=password]').val(),
|
||||||
passwordConfirmation: $el.find('[name=passwordConfirmation]').val(),
|
passwordConfirmation: $el.find('[name=passwordConfirmation]').val(),
|
||||||
email: $el.find('[name=email]').val(),
|
email: $el.find('[name=email]').val(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!validateRegistrationFormData(formData)) {
|
if (!validateRegistrationFormData(formData)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
promise.wait(api.post('/users', formData))
|
promise.wait(api.post('/users', formData))
|
||||||
.then(function(response) {
|
.then(function(response) {
|
||||||
registrationSuccess(response);
|
registrationSuccess(response);
|
||||||
}).fail(function(response) {
|
}).fail(function(response) {
|
||||||
registrationFailure(response);
|
registrationFailure(response);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function registrationSuccess(apiResponse) {
|
function registrationSuccess(apiResponse) {
|
||||||
$el.find('form').slideUp(function() {
|
$el.find('form').slideUp(function() {
|
||||||
var message = 'Registration complete! ';
|
var message = 'Registration complete! ';
|
||||||
if (!apiResponse.json.confirmed) {
|
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.';
|
message += '<br/>Check your inbox for activation e-mail.<br/>If e-mail doesn\'t show up, check your spam folder.';
|
||||||
} else {
|
} else {
|
||||||
message += '<a href="#/login">Click here</a> to login.';
|
message += '<a href="#/login">Click here</a> to login.';
|
||||||
}
|
}
|
||||||
messagePresenter.showInfo($messages, message);
|
messagePresenter.showInfo($messages, message);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function registrationFailure(apiResponse) {
|
function registrationFailure(apiResponse) {
|
||||||
messagePresenter.showError($messages, apiResponse.json && apiResponse.json.error || apiResponse);
|
messagePresenter.showError($messages, apiResponse.json && apiResponse.json.error || apiResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateRegistrationFormData(formData) {
|
function validateRegistrationFormData(formData) {
|
||||||
if (formData.userName.length === 0) {
|
if (formData.userName.length === 0) {
|
||||||
messagePresenter.showError($messages, 'User name cannot be empty.');
|
messagePresenter.showError($messages, 'User name cannot be empty.');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (formData.password.length === 0) {
|
if (formData.password.length === 0) {
|
||||||
messagePresenter.showError($messages, 'Password cannot be empty.');
|
messagePresenter.showError($messages, 'Password cannot be empty.');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (formData.password !== formData.passwordConfirmation) {
|
if (formData.password !== formData.passwordConfirmation) {
|
||||||
messagePresenter.showError($messages, 'Passwords must be the same.');
|
messagePresenter.showError($messages, 'Passwords must be the same.');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
init: init,
|
init: init,
|
||||||
render: render,
|
render: render,
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,124 +2,124 @@ var App = App || {};
|
||||||
App.Presenters = App.Presenters || {};
|
App.Presenters = App.Presenters || {};
|
||||||
|
|
||||||
App.Presenters.TagListPresenter = function(
|
App.Presenters.TagListPresenter = function(
|
||||||
_,
|
_,
|
||||||
jQuery,
|
jQuery,
|
||||||
util,
|
util,
|
||||||
promise,
|
promise,
|
||||||
keyboard,
|
keyboard,
|
||||||
pagerPresenter,
|
pagerPresenter,
|
||||||
topNavigationPresenter) {
|
topNavigationPresenter) {
|
||||||
|
|
||||||
var $el = jQuery('#content');
|
var $el = jQuery('#content');
|
||||||
var $searchInput;
|
var $searchInput;
|
||||||
var templates = {};
|
var templates = {};
|
||||||
|
|
||||||
var params;
|
var params;
|
||||||
|
|
||||||
function init(_params, loaded) {
|
function init(_params, loaded) {
|
||||||
topNavigationPresenter.select('tags');
|
topNavigationPresenter.select('tags');
|
||||||
topNavigationPresenter.changeTitle('Tags');
|
topNavigationPresenter.changeTitle('Tags');
|
||||||
params = _params;
|
params = _params;
|
||||||
params.query = params.query || {};
|
params.query = params.query || {};
|
||||||
|
|
||||||
promise.wait(
|
promise.wait(
|
||||||
util.promiseTemplate('tag-list'),
|
util.promiseTemplate('tag-list'),
|
||||||
util.promiseTemplate('tag-list-item'))
|
util.promiseTemplate('tag-list-item'))
|
||||||
.then(function(listTemplate, listItemTemplate) {
|
.then(function(listTemplate, listItemTemplate) {
|
||||||
templates.list = listTemplate;
|
templates.list = listTemplate;
|
||||||
templates.listItem = listItemTemplate;
|
templates.listItem = listItemTemplate;
|
||||||
|
|
||||||
render();
|
render();
|
||||||
loaded();
|
loaded();
|
||||||
|
|
||||||
pagerPresenter.init({
|
pagerPresenter.init({
|
||||||
baseUri: '#/tags',
|
baseUri: '#/tags',
|
||||||
backendUri: '/tags',
|
backendUri: '/tags',
|
||||||
$target: $el.find('.pagination-target'),
|
$target: $el.find('.pagination-target'),
|
||||||
updateCallback: function($page, data) {
|
updateCallback: function($page, data) {
|
||||||
renderTags($page, data.entities);
|
renderTags($page, data.entities);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
function() {
|
function() {
|
||||||
reinit(params, function() {});
|
reinit(params, function() {});
|
||||||
});
|
});
|
||||||
}).fail(function() {
|
}).fail(function() {
|
||||||
console.log(arguments);
|
console.log(arguments);
|
||||||
loaded();
|
loaded();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function reinit(_params, loaded) {
|
function reinit(_params, loaded) {
|
||||||
params = _params;
|
params = _params;
|
||||||
params.query = params.query || {};
|
params.query = params.query || {};
|
||||||
params.query.order = params.query.order || 'name,asc';
|
params.query.order = params.query.order || 'name,asc';
|
||||||
updateActiveOrder(params.query.order);
|
updateActiveOrder(params.query.order);
|
||||||
|
|
||||||
pagerPresenter.reinit({query: params.query});
|
pagerPresenter.reinit({query: params.query});
|
||||||
|
|
||||||
keyboard.keyup('p', function() {
|
keyboard.keyup('p', function() {
|
||||||
$el.find('table a').eq(0).focus();
|
$el.find('table a').eq(0).focus();
|
||||||
});
|
});
|
||||||
|
|
||||||
keyboard.keyup('q', function() {
|
keyboard.keyup('q', function() {
|
||||||
$searchInput.eq(0).focus().select();
|
$searchInput.eq(0).focus().select();
|
||||||
});
|
});
|
||||||
|
|
||||||
loaded();
|
loaded();
|
||||||
softRender();
|
softRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
function deinit() {
|
function deinit() {
|
||||||
pagerPresenter.deinit();
|
pagerPresenter.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
$el.html(templates.list());
|
$el.html(templates.list());
|
||||||
$searchInput = $el.find('input[name=query]');
|
$searchInput = $el.find('input[name=query]');
|
||||||
$el.find('form').submit(searchFormSubmitted);
|
$el.find('form').submit(searchFormSubmitted);
|
||||||
App.Controls.AutoCompleteInput($searchInput);
|
App.Controls.AutoCompleteInput($searchInput);
|
||||||
softRender();
|
softRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
function softRender() {
|
function softRender() {
|
||||||
$searchInput.val(params.query.query);
|
$searchInput.val(params.query.query);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function searchFormSubmitted(e) {
|
function searchFormSubmitted(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
updateSearch();
|
updateSearch();
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateSearch() {
|
function updateSearch() {
|
||||||
$searchInput.blur();
|
$searchInput.blur();
|
||||||
params.query.query = $searchInput.val().trim();
|
params.query.query = $searchInput.val().trim();
|
||||||
params.query.page = 1;
|
params.query.page = 1;
|
||||||
pagerPresenter.setQuery(params.query);
|
pagerPresenter.setQuery(params.query);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateActiveOrder(activeOrder) {
|
function updateActiveOrder(activeOrder) {
|
||||||
$el.find('.order li a.active').removeClass('active');
|
$el.find('.order li a.active').removeClass('active');
|
||||||
$el.find('.order [href*="' + activeOrder + '"]').addClass('active');
|
$el.find('.order [href*="' + activeOrder + '"]').addClass('active');
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderTags($page, tags) {
|
function renderTags($page, tags) {
|
||||||
var $target = $page.find('tbody');
|
var $target = $page.find('tbody');
|
||||||
_.each(tags, function(tag) {
|
_.each(tags, function(tag) {
|
||||||
var $item = jQuery(templates.listItem({
|
var $item = jQuery(templates.listItem({
|
||||||
tag: tag,
|
tag: tag,
|
||||||
util: util,
|
util: util,
|
||||||
}));
|
}));
|
||||||
$target.append($item);
|
$target.append($item);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
init: init,
|
init: init,
|
||||||
reinit: reinit,
|
reinit: reinit,
|
||||||
deinit: deinit,
|
deinit: deinit,
|
||||||
render: render,
|
render: render,
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,199 +2,199 @@ var App = App || {};
|
||||||
App.Presenters = App.Presenters || {};
|
App.Presenters = App.Presenters || {};
|
||||||
|
|
||||||
App.Presenters.TagPresenter = function(
|
App.Presenters.TagPresenter = function(
|
||||||
_,
|
_,
|
||||||
jQuery,
|
jQuery,
|
||||||
util,
|
util,
|
||||||
promise,
|
promise,
|
||||||
auth,
|
auth,
|
||||||
api,
|
api,
|
||||||
tagList,
|
tagList,
|
||||||
router,
|
router,
|
||||||
keyboard,
|
keyboard,
|
||||||
topNavigationPresenter,
|
topNavigationPresenter,
|
||||||
messagePresenter) {
|
messagePresenter) {
|
||||||
|
|
||||||
var $el = jQuery('#content');
|
var $el = jQuery('#content');
|
||||||
var $messages = $el;
|
var $messages = $el;
|
||||||
var templates = {};
|
var templates = {};
|
||||||
var implicationsTagInput;
|
var implicationsTagInput;
|
||||||
var suggestionsTagInput;
|
var suggestionsTagInput;
|
||||||
|
|
||||||
var tag;
|
var tag;
|
||||||
var posts;
|
var posts;
|
||||||
var siblings;
|
var siblings;
|
||||||
|
|
||||||
var privileges = {};
|
var privileges = {};
|
||||||
|
|
||||||
function init(params, loaded) {
|
function init(params, loaded) {
|
||||||
topNavigationPresenter.select('tags');
|
topNavigationPresenter.select('tags');
|
||||||
topNavigationPresenter.changeTitle('Tags');
|
topNavigationPresenter.changeTitle('Tags');
|
||||||
|
|
||||||
privileges.canChangeName = auth.hasPrivilege(auth.privileges.changeTagName);
|
privileges.canChangeName = auth.hasPrivilege(auth.privileges.changeTagName);
|
||||||
privileges.canChangeCategory = auth.hasPrivilege(auth.privileges.changeTagCategory);
|
privileges.canChangeCategory = auth.hasPrivilege(auth.privileges.changeTagCategory);
|
||||||
privileges.canChangeImplications = auth.hasPrivilege(auth.privileges.changeTagImplications);
|
privileges.canChangeImplications = auth.hasPrivilege(auth.privileges.changeTagImplications);
|
||||||
privileges.canChangeSuggestions = auth.hasPrivilege(auth.privileges.changeTagSuggestions);
|
privileges.canChangeSuggestions = auth.hasPrivilege(auth.privileges.changeTagSuggestions);
|
||||||
privileges.canBan = auth.hasPrivilege(auth.privileges.banTags);
|
privileges.canBan = auth.hasPrivilege(auth.privileges.banTags);
|
||||||
privileges.canViewHistory = auth.hasPrivilege(auth.privileges.viewHistory);
|
privileges.canViewHistory = auth.hasPrivilege(auth.privileges.viewHistory);
|
||||||
privileges.canDelete = auth.hasPrivilege(auth.privileges.deleteTags);
|
privileges.canDelete = auth.hasPrivilege(auth.privileges.deleteTags);
|
||||||
privileges.canMerge = auth.hasPrivilege(auth.privileges.mergeTags);
|
privileges.canMerge = auth.hasPrivilege(auth.privileges.mergeTags);
|
||||||
privileges.canViewPosts = auth.hasPrivilege(auth.privileges.viewPosts);
|
privileges.canViewPosts = auth.hasPrivilege(auth.privileges.viewPosts);
|
||||||
|
|
||||||
promise.wait(
|
promise.wait(
|
||||||
util.promiseTemplate('tag'),
|
util.promiseTemplate('tag'),
|
||||||
util.promiseTemplate('post-list-item'),
|
util.promiseTemplate('post-list-item'),
|
||||||
util.promiseTemplate('history'))
|
util.promiseTemplate('history'))
|
||||||
.then(function(tagTemplate, postListItemTemplate, historyTemplate) {
|
.then(function(tagTemplate, postListItemTemplate, historyTemplate) {
|
||||||
templates.tag = tagTemplate;
|
templates.tag = tagTemplate;
|
||||||
templates.postListItem = postListItemTemplate;
|
templates.postListItem = postListItemTemplate;
|
||||||
templates.history = historyTemplate;
|
templates.history = historyTemplate;
|
||||||
|
|
||||||
reinit(params, loaded);
|
reinit(params, loaded);
|
||||||
}).fail(function() {
|
}).fail(function() {
|
||||||
console.log(arguments);
|
console.log(arguments);
|
||||||
loaded();
|
loaded();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function reinit(params, loaded) {
|
function reinit(params, loaded) {
|
||||||
var tagName = params.tagName;
|
var tagName = params.tagName;
|
||||||
|
|
||||||
messagePresenter.hideMessages($messages);
|
messagePresenter.hideMessages($messages);
|
||||||
|
|
||||||
promise.wait(
|
promise.wait(
|
||||||
api.get('tags/' + tagName),
|
api.get('tags/' + tagName),
|
||||||
api.get('tags/' + tagName + '/siblings'),
|
api.get('tags/' + tagName + '/siblings'),
|
||||||
api.get('posts', {query: tagName}))
|
api.get('posts', {query: tagName}))
|
||||||
.then(function(tagResponse, siblingsResponse, postsResponse) {
|
.then(function(tagResponse, siblingsResponse, postsResponse) {
|
||||||
tag = tagResponse.json;
|
tag = tagResponse.json;
|
||||||
siblings = siblingsResponse.json.data;
|
siblings = siblingsResponse.json.data;
|
||||||
posts = postsResponse.json.data;
|
posts = postsResponse.json.data;
|
||||||
posts = posts.slice(0, 8);
|
posts = posts.slice(0, 8);
|
||||||
|
|
||||||
render();
|
render();
|
||||||
loaded();
|
loaded();
|
||||||
|
|
||||||
renderPosts(posts);
|
renderPosts(posts);
|
||||||
}).fail(function(tagResponse, siblingsResponse, postsResponse) {
|
}).fail(function(tagResponse, siblingsResponse, postsResponse) {
|
||||||
messagePresenter.showError($messages, tagResponse.json.error || siblingsResponse.json.error || postsResponse.json.error);
|
messagePresenter.showError($messages, tagResponse.json.error || siblingsResponse.json.error || postsResponse.json.error);
|
||||||
loaded();
|
loaded();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
$el.html(templates.tag({
|
$el.html(templates.tag({
|
||||||
privileges: privileges,
|
privileges: privileges,
|
||||||
tag: tag,
|
tag: tag,
|
||||||
siblings: siblings,
|
siblings: siblings,
|
||||||
tagCategories: JSON.parse(jQuery('head').attr('data-tag-categories')),
|
tagCategories: JSON.parse(jQuery('head').attr('data-tag-categories')),
|
||||||
util: util,
|
util: util,
|
||||||
historyTemplate: templates.history,
|
historyTemplate: templates.history,
|
||||||
}));
|
}));
|
||||||
$el.find('.post-list').hide();
|
$el.find('.post-list').hide();
|
||||||
$el.find('form').submit(function(e) { e.preventDefault(); });
|
$el.find('form').submit(function(e) { e.preventDefault(); });
|
||||||
$el.find('form button[name=update]').click(updateButtonClicked);
|
$el.find('form button[name=update]').click(updateButtonClicked);
|
||||||
$el.find('form button[name=delete]').click(deleteButtonClicked);
|
$el.find('form button[name=delete]').click(deleteButtonClicked);
|
||||||
$el.find('form button[name=merge]').click(mergeButtonClicked);
|
$el.find('form button[name=merge]').click(mergeButtonClicked);
|
||||||
implicationsTagInput = App.Controls.TagInput($el.find('[name=implications]'));
|
implicationsTagInput = App.Controls.TagInput($el.find('[name=implications]'));
|
||||||
suggestionsTagInput = App.Controls.TagInput($el.find('[name=suggestions]'));
|
suggestionsTagInput = App.Controls.TagInput($el.find('[name=suggestions]'));
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateButtonClicked(e) {
|
function updateButtonClicked(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var $form = $el.find('form');
|
var $form = $el.find('form');
|
||||||
var formData = {};
|
var formData = {};
|
||||||
|
|
||||||
if (privileges.canChangeName) {
|
if (privileges.canChangeName) {
|
||||||
formData.name = $form.find('[name=name]').val();
|
formData.name = $form.find('[name=name]').val();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (privileges.canChangeCategory) {
|
if (privileges.canChangeCategory) {
|
||||||
formData.category = $form.find('[name=category]:checked').val();
|
formData.category = $form.find('[name=category]:checked').val();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (privileges.canBan) {
|
if (privileges.canBan) {
|
||||||
formData.banned = $form.find('[name=ban]').is(':checked') ? 1 : 0;
|
formData.banned = $form.find('[name=ban]').is(':checked') ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (privileges.canChangeImplications) {
|
if (privileges.canChangeImplications) {
|
||||||
formData.implications = implicationsTagInput.getTags().join(' ');
|
formData.implications = implicationsTagInput.getTags().join(' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (privileges.canChangeSuggestions) {
|
if (privileges.canChangeSuggestions) {
|
||||||
formData.suggestions = suggestionsTagInput.getTags().join(' ');
|
formData.suggestions = suggestionsTagInput.getTags().join(' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
promise.wait(api.put('/tags/' + tag.name, formData))
|
promise.wait(api.put('/tags/' + tag.name, formData))
|
||||||
.then(function(response) {
|
.then(function(response) {
|
||||||
router.navigateInplace('#/tag/' + response.json.name);
|
router.navigateInplace('#/tag/' + response.json.name);
|
||||||
tagList.refreshTags();
|
tagList.refreshTags();
|
||||||
}).fail(function(response) {
|
}).fail(function(response) {
|
||||||
window.alert(response.json && response.json.error || 'An error occured.');
|
window.alert(response.json && response.json.error || 'An error occured.');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteButtonClicked(e) {
|
function deleteButtonClicked(e) {
|
||||||
if (!window.confirm('Are you sure you want to delete this tag?')) {
|
if (!window.confirm('Are you sure you want to delete this tag?')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
promise.wait(api.delete('/tags/' + tag.name))
|
promise.wait(api.delete('/tags/' + tag.name))
|
||||||
.then(function(response) {
|
.then(function(response) {
|
||||||
router.navigate('#/tags');
|
router.navigate('#/tags');
|
||||||
tagList.refreshTags();
|
tagList.refreshTags();
|
||||||
}).fail(function(response) {
|
}).fail(function(response) {
|
||||||
window.alert(response.json && response.json.error || 'An error occured.');
|
window.alert(response.json && response.json.error || 'An error occured.');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function mergeButtonClicked(e) {
|
function mergeButtonClicked(e) {
|
||||||
var targetTag = window.prompt('What tag should this be merged to?');
|
var targetTag = window.prompt('What tag should this be merged to?');
|
||||||
if (targetTag) {
|
if (targetTag) {
|
||||||
promise.wait(api.put('/tags/' + tag.name + '/merge', {targetTag: targetTag}))
|
promise.wait(api.put('/tags/' + tag.name + '/merge', {targetTag: targetTag}))
|
||||||
.then(function(response) {
|
.then(function(response) {
|
||||||
router.navigate('#/tags');
|
router.navigate('#/tags');
|
||||||
tagList.refreshTags();
|
tagList.refreshTags();
|
||||||
}).fail(function(response) {
|
}).fail(function(response) {
|
||||||
window.alert(response.json && response.json.error || 'An error occured.');
|
window.alert(response.json && response.json.error || 'An error occured.');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderPosts(posts) {
|
function renderPosts(posts) {
|
||||||
var $target = $el.find('.post-list ul');
|
var $target = $el.find('.post-list ul');
|
||||||
_.each(posts, function(post) {
|
_.each(posts, function(post) {
|
||||||
var $post = jQuery('<li>' + templates.postListItem({
|
var $post = jQuery('<li>' + templates.postListItem({
|
||||||
util: util,
|
util: util,
|
||||||
post: post,
|
post: post,
|
||||||
query: {query: tag.name},
|
query: {query: tag.name},
|
||||||
canViewPosts: privileges.canViewPosts,
|
canViewPosts: privileges.canViewPosts,
|
||||||
}) + '</li>');
|
}) + '</li>');
|
||||||
$target.append($post);
|
$target.append($post);
|
||||||
});
|
});
|
||||||
if (posts.length > 0) {
|
if (posts.length > 0) {
|
||||||
$el.find('.post-list').fadeIn();
|
$el.find('.post-list').fadeIn();
|
||||||
keyboard.keyup('p', function() {
|
keyboard.keyup('p', function() {
|
||||||
$el.find('.post-list a').eq(0).focus();
|
$el.find('.post-list a').eq(0).focus();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
init: init,
|
init: init,
|
||||||
reinit: reinit,
|
reinit: reinit,
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
App.DI.register('tagPresenter', [
|
App.DI.register('tagPresenter', [
|
||||||
'_',
|
'_',
|
||||||
'jQuery',
|
'jQuery',
|
||||||
'util',
|
'util',
|
||||||
'promise',
|
'promise',
|
||||||
'auth',
|
'auth',
|
||||||
'api',
|
'api',
|
||||||
'tagList',
|
'tagList',
|
||||||
'router',
|
'router',
|
||||||
'keyboard',
|
'keyboard',
|
||||||
'topNavigationPresenter',
|
'topNavigationPresenter',
|
||||||
'messagePresenter'],
|
'messagePresenter'],
|
||||||
App.Presenters.TagPresenter);
|
App.Presenters.TagPresenter);
|
||||||
|
|
|
@ -2,78 +2,78 @@ var App = App || {};
|
||||||
App.Presenters = App.Presenters || {};
|
App.Presenters = App.Presenters || {};
|
||||||
|
|
||||||
App.Presenters.TopNavigationPresenter = function(
|
App.Presenters.TopNavigationPresenter = function(
|
||||||
jQuery,
|
jQuery,
|
||||||
util,
|
util,
|
||||||
promise,
|
promise,
|
||||||
auth) {
|
auth) {
|
||||||
|
|
||||||
var selectedElement = null;
|
var selectedElement = null;
|
||||||
var $el = jQuery('#top-navigation');
|
var $el = jQuery('#top-navigation');
|
||||||
var templates = {};
|
var templates = {};
|
||||||
var baseTitle = document.title;
|
var baseTitle = document.title;
|
||||||
|
|
||||||
function init(params, loaded) {
|
function init(params, loaded) {
|
||||||
promise.wait(util.promiseTemplate('top-navigation'))
|
promise.wait(util.promiseTemplate('top-navigation'))
|
||||||
.then(function(template) {
|
.then(function(template) {
|
||||||
templates.topNavigation = template;
|
templates.topNavigation = template;
|
||||||
render();
|
render();
|
||||||
loaded();
|
loaded();
|
||||||
auth.startObservingLoginChanges('top-navigation', loginStateChanged);
|
auth.startObservingLoginChanges('top-navigation', loginStateChanged);
|
||||||
}).fail(function() {
|
}).fail(function() {
|
||||||
loaded();
|
loaded();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function select(newSelectedElement) {
|
function select(newSelectedElement) {
|
||||||
selectedElement = newSelectedElement;
|
selectedElement = newSelectedElement;
|
||||||
$el.find('li a').removeClass('active');
|
$el.find('li a').removeClass('active');
|
||||||
$el.find('li.' + selectedElement).find('a').addClass('active');
|
$el.find('li.' + selectedElement).find('a').addClass('active');
|
||||||
}
|
}
|
||||||
|
|
||||||
function loginStateChanged() {
|
function loginStateChanged() {
|
||||||
render();
|
render();
|
||||||
}
|
}
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
$el.html(templates.topNavigation({
|
$el.html(templates.topNavigation({
|
||||||
loggedIn: auth.isLoggedIn(),
|
loggedIn: auth.isLoggedIn(),
|
||||||
user: auth.getCurrentUser(),
|
user: auth.getCurrentUser(),
|
||||||
canListUsers: auth.hasPrivilege(auth.privileges.listUsers),
|
canListUsers: auth.hasPrivilege(auth.privileges.listUsers),
|
||||||
canListPosts: auth.hasPrivilege(auth.privileges.listPosts),
|
canListPosts: auth.hasPrivilege(auth.privileges.listPosts),
|
||||||
canListComments: auth.hasPrivilege(auth.privileges.listComments),
|
canListComments: auth.hasPrivilege(auth.privileges.listComments),
|
||||||
canListTags: auth.hasPrivilege(auth.privileges.listTags),
|
canListTags: auth.hasPrivilege(auth.privileges.listTags),
|
||||||
canUploadPosts: auth.hasPrivilege(auth.privileges.uploadPosts),
|
canUploadPosts: auth.hasPrivilege(auth.privileges.uploadPosts),
|
||||||
}));
|
}));
|
||||||
$el.find('li.' + selectedElement).find('a').addClass('active');
|
$el.find('li.' + selectedElement).find('a').addClass('active');
|
||||||
}
|
}
|
||||||
|
|
||||||
function focus() {
|
function focus() {
|
||||||
var $tmp = jQuery('<a href="#"> </a>');
|
var $tmp = jQuery('<a href="#"> </a>');
|
||||||
$el.prepend($tmp);
|
$el.prepend($tmp);
|
||||||
$tmp.focus();
|
$tmp.focus();
|
||||||
$tmp.remove();
|
$tmp.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getBaseTitle() {
|
function getBaseTitle() {
|
||||||
return baseTitle;
|
return baseTitle;
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeTitle(subTitle) {
|
function changeTitle(subTitle) {
|
||||||
var newTitle = baseTitle;
|
var newTitle = baseTitle;
|
||||||
if (subTitle) {
|
if (subTitle) {
|
||||||
newTitle += ' - ' + subTitle;
|
newTitle += ' - ' + subTitle;
|
||||||
}
|
}
|
||||||
document.title = newTitle;
|
document.title = newTitle;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
init: init,
|
init: init,
|
||||||
render: render,
|
render: render,
|
||||||
select: select,
|
select: select,
|
||||||
focus: focus,
|
focus: focus,
|
||||||
getBaseTitle: getBaseTitle,
|
getBaseTitle: getBaseTitle,
|
||||||
changeTitle: changeTitle,
|
changeTitle: changeTitle,
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,80 +2,80 @@ var App = App || {};
|
||||||
App.Presenters = App.Presenters || {};
|
App.Presenters = App.Presenters || {};
|
||||||
|
|
||||||
App.Presenters.UserAccountRemovalPresenter = function(
|
App.Presenters.UserAccountRemovalPresenter = function(
|
||||||
jQuery,
|
jQuery,
|
||||||
util,
|
util,
|
||||||
promise,
|
promise,
|
||||||
api,
|
api,
|
||||||
auth,
|
auth,
|
||||||
router,
|
router,
|
||||||
messagePresenter) {
|
messagePresenter) {
|
||||||
|
|
||||||
var target;
|
var target;
|
||||||
var templates = {};
|
var templates = {};
|
||||||
var user;
|
var user;
|
||||||
var privileges = {};
|
var privileges = {};
|
||||||
|
|
||||||
function init(params, loaded) {
|
function init(params, loaded) {
|
||||||
user = params.user;
|
user = params.user;
|
||||||
target = params.target;
|
target = params.target;
|
||||||
|
|
||||||
privileges.canDeleteAccount =
|
privileges.canDeleteAccount =
|
||||||
auth.hasPrivilege(auth.privileges.deleteAllAccounts) ||
|
auth.hasPrivilege(auth.privileges.deleteAllAccounts) ||
|
||||||
(auth.hasPrivilege(auth.privileges.deleteOwnAccount) && auth.isLoggedIn(user.name));
|
(auth.hasPrivilege(auth.privileges.deleteOwnAccount) && auth.isLoggedIn(user.name));
|
||||||
|
|
||||||
promise.wait(util.promiseTemplate('account-removal'))
|
promise.wait(util.promiseTemplate('account-removal'))
|
||||||
.then(function(template) {
|
.then(function(template) {
|
||||||
templates.accountRemoval = template;
|
templates.accountRemoval = template;
|
||||||
render();
|
render();
|
||||||
loaded();
|
loaded();
|
||||||
}).fail(function() {
|
}).fail(function() {
|
||||||
console.log(arguments);
|
console.log(arguments);
|
||||||
loaded();
|
loaded();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
var $el = jQuery(target);
|
var $el = jQuery(target);
|
||||||
$el.html(templates.accountRemoval({
|
$el.html(templates.accountRemoval({
|
||||||
user: user,
|
user: user,
|
||||||
canDeleteAccount: privileges.canDeleteAccount}));
|
canDeleteAccount: privileges.canDeleteAccount}));
|
||||||
|
|
||||||
$el.find('form').submit(accountRemovalFormSubmitted);
|
$el.find('form').submit(accountRemovalFormSubmitted);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPrivileges() {
|
function getPrivileges() {
|
||||||
return privileges;
|
return privileges;
|
||||||
}
|
}
|
||||||
|
|
||||||
function accountRemovalFormSubmitted(e) {
|
function accountRemovalFormSubmitted(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var $el = jQuery(target);
|
var $el = jQuery(target);
|
||||||
var $messages = $el.find('.messages');
|
var $messages = $el.find('.messages');
|
||||||
messagePresenter.hideMessages($messages);
|
messagePresenter.hideMessages($messages);
|
||||||
if (!$el.find('input[name=confirmation]:visible').prop('checked')) {
|
if (!$el.find('input[name=confirmation]:visible').prop('checked')) {
|
||||||
messagePresenter.showError($messages, 'Must confirm to proceed.');
|
messagePresenter.showError($messages, 'Must confirm to proceed.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
promise.wait(api.delete('/users/' + user.name))
|
promise.wait(api.delete('/users/' + user.name))
|
||||||
.then(function() {
|
.then(function() {
|
||||||
auth.logout();
|
auth.logout();
|
||||||
var $messageDiv = messagePresenter.showInfo($messages, 'Account deleted. <a href="">Back to main page</a>');
|
var $messageDiv = messagePresenter.showInfo($messages, 'Account deleted. <a href="">Back to main page</a>');
|
||||||
$messageDiv.find('a').click(mainPageLinkClicked);
|
$messageDiv.find('a').click(mainPageLinkClicked);
|
||||||
}).fail(function(response) {
|
}).fail(function(response) {
|
||||||
messagePresenter.showError($messages, response.json && response.json.error || response);
|
messagePresenter.showError($messages, response.json && response.json.error || response);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function mainPageLinkClicked(e) {
|
function mainPageLinkClicked(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
router.navigateToMainPage();
|
router.navigateToMainPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
init: init,
|
init: init,
|
||||||
render: render,
|
render: render,
|
||||||
getPrivileges: getPrivileges
|
getPrivileges: getPrivileges
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,162 +2,162 @@ var App = App || {};
|
||||||
App.Presenters = App.Presenters || {};
|
App.Presenters = App.Presenters || {};
|
||||||
|
|
||||||
App.Presenters.UserAccountSettingsPresenter = function(
|
App.Presenters.UserAccountSettingsPresenter = function(
|
||||||
_,
|
_,
|
||||||
jQuery,
|
jQuery,
|
||||||
util,
|
util,
|
||||||
promise,
|
promise,
|
||||||
api,
|
api,
|
||||||
auth,
|
auth,
|
||||||
messagePresenter) {
|
messagePresenter) {
|
||||||
|
|
||||||
var target;
|
var target;
|
||||||
var templates = {};
|
var templates = {};
|
||||||
var user;
|
var user;
|
||||||
var privileges;
|
var privileges;
|
||||||
var avatarContent;
|
var avatarContent;
|
||||||
var fileDropper;
|
var fileDropper;
|
||||||
|
|
||||||
function init(params, loaded) {
|
function init(params, loaded) {
|
||||||
user = params.user;
|
user = params.user;
|
||||||
target = params.target;
|
target = params.target;
|
||||||
|
|
||||||
privileges = {
|
privileges = {
|
||||||
canBan:
|
canBan:
|
||||||
auth.hasPrivilege(auth.privileges.banUsers),
|
auth.hasPrivilege(auth.privileges.banUsers),
|
||||||
canChangeAccessRank:
|
canChangeAccessRank:
|
||||||
auth.hasPrivilege(auth.privileges.changeAccessRank),
|
auth.hasPrivilege(auth.privileges.changeAccessRank),
|
||||||
canChangeAvatarStyle:
|
canChangeAvatarStyle:
|
||||||
auth.hasPrivilege(auth.privileges.changeAllAvatarStyles) ||
|
auth.hasPrivilege(auth.privileges.changeAllAvatarStyles) ||
|
||||||
(auth.hasPrivilege(auth.privileges.changeOwnAvatarStyle) && auth.isLoggedIn(user.name)),
|
(auth.hasPrivilege(auth.privileges.changeOwnAvatarStyle) && auth.isLoggedIn(user.name)),
|
||||||
canChangeName:
|
canChangeName:
|
||||||
auth.hasPrivilege(auth.privileges.changeAllNames) ||
|
auth.hasPrivilege(auth.privileges.changeAllNames) ||
|
||||||
(auth.hasPrivilege(auth.privileges.changeOwnName) && auth.isLoggedIn(user.name)),
|
(auth.hasPrivilege(auth.privileges.changeOwnName) && auth.isLoggedIn(user.name)),
|
||||||
canChangeEmailAddress:
|
canChangeEmailAddress:
|
||||||
auth.hasPrivilege(auth.privileges.changeAllEmailAddresses) ||
|
auth.hasPrivilege(auth.privileges.changeAllEmailAddresses) ||
|
||||||
(auth.hasPrivilege(auth.privileges.changeOwnEmailAddress) && auth.isLoggedIn(user.name)),
|
(auth.hasPrivilege(auth.privileges.changeOwnEmailAddress) && auth.isLoggedIn(user.name)),
|
||||||
canChangePassword:
|
canChangePassword:
|
||||||
auth.hasPrivilege(auth.privileges.changeAllPasswords) ||
|
auth.hasPrivilege(auth.privileges.changeAllPasswords) ||
|
||||||
(auth.hasPrivilege(auth.privileges.changeOwnPassword) && auth.isLoggedIn(user.name)),
|
(auth.hasPrivilege(auth.privileges.changeOwnPassword) && auth.isLoggedIn(user.name)),
|
||||||
};
|
};
|
||||||
|
|
||||||
promise.wait(util.promiseTemplate('account-settings'))
|
promise.wait(util.promiseTemplate('account-settings'))
|
||||||
.then(function(template) {
|
.then(function(template) {
|
||||||
templates.accountRemoval = template;
|
templates.accountRemoval = template;
|
||||||
render();
|
render();
|
||||||
loaded();
|
loaded();
|
||||||
}).fail(function() {
|
}).fail(function() {
|
||||||
console.log(arguments);
|
console.log(arguments);
|
||||||
loaded();
|
loaded();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
var $el = jQuery(target);
|
var $el = jQuery(target);
|
||||||
$el.html(templates.accountRemoval(_.extend({user: user}, privileges)));
|
$el.html(templates.accountRemoval(_.extend({user: user}, privileges)));
|
||||||
$el.find('form').submit(accountSettingsFormSubmitted);
|
$el.find('form').submit(accountSettingsFormSubmitted);
|
||||||
$el.find('form [name=avatar-style]').change(avatarStyleChanged);
|
$el.find('form [name=avatar-style]').change(avatarStyleChanged);
|
||||||
avatarStyleChanged();
|
avatarStyleChanged();
|
||||||
fileDropper = new App.Controls.FileDropper($el.find('[name=avatar-content]'));
|
fileDropper = new App.Controls.FileDropper($el.find('[name=avatar-content]'));
|
||||||
fileDropper.onChange = avatarContentChanged;
|
fileDropper.onChange = avatarContentChanged;
|
||||||
fileDropper.setNames = true;
|
fileDropper.setNames = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPrivileges() {
|
function getPrivileges() {
|
||||||
return privileges;
|
return privileges;
|
||||||
}
|
}
|
||||||
|
|
||||||
function avatarStyleChanged(e) {
|
function avatarStyleChanged(e) {
|
||||||
var $el = jQuery(target);
|
var $el = jQuery(target);
|
||||||
var $target = $el.find('.avatar-content .file-handler');
|
var $target = $el.find('.avatar-content .file-handler');
|
||||||
if ($el.find('[name=avatar-style]:checked').val() === 'manual') {
|
if ($el.find('[name=avatar-style]:checked').val() === 'manual') {
|
||||||
$target.show();
|
$target.show();
|
||||||
} else {
|
} else {
|
||||||
$target.hide();
|
$target.hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function avatarContentChanged(files) {
|
function avatarContentChanged(files) {
|
||||||
avatarContent = files[0];
|
avatarContent = files[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
function accountSettingsFormSubmitted(e) {
|
function accountSettingsFormSubmitted(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var $el = jQuery(target);
|
var $el = jQuery(target);
|
||||||
var $messages = jQuery(target).find('.messages');
|
var $messages = jQuery(target).find('.messages');
|
||||||
messagePresenter.hideMessages($messages);
|
messagePresenter.hideMessages($messages);
|
||||||
var formData = new FormData();
|
var formData = new FormData();
|
||||||
|
|
||||||
if (privileges.canChangeAvatarStyle) {
|
if (privileges.canChangeAvatarStyle) {
|
||||||
formData.append('avatarStyle', $el.find('[name=avatar-style]:checked').val());
|
formData.append('avatarStyle', $el.find('[name=avatar-style]:checked').val());
|
||||||
if (avatarContent) {
|
if (avatarContent) {
|
||||||
formData.append('avatarContent', avatarContent);
|
formData.append('avatarContent', avatarContent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (privileges.canChangeName) {
|
if (privileges.canChangeName) {
|
||||||
formData.append('userName', $el.find('[name=userName]').val());
|
formData.append('userName', $el.find('[name=userName]').val());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (privileges.canChangeEmailAddress) {
|
if (privileges.canChangeEmailAddress) {
|
||||||
formData.append('email', $el.find('[name=email]').val());
|
formData.append('email', $el.find('[name=email]').val());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (privileges.canChangePassword) {
|
if (privileges.canChangePassword) {
|
||||||
var password = $el.find('[name=password]').val();
|
var password = $el.find('[name=password]').val();
|
||||||
var passwordConfirmation = $el.find('[name=passwordConfirmation]').val();
|
var passwordConfirmation = $el.find('[name=passwordConfirmation]').val();
|
||||||
|
|
||||||
if (password) {
|
if (password) {
|
||||||
if (password !== passwordConfirmation) {
|
if (password !== passwordConfirmation) {
|
||||||
messagePresenter.showError($messages, 'Passwords must be the same.');
|
messagePresenter.showError($messages, 'Passwords must be the same.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
formData.append('password', password);
|
formData.append('password', password);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (privileges.canChangeAccessRank) {
|
if (privileges.canChangeAccessRank) {
|
||||||
formData.append('accessRank', $el.find('[name=access-rank]:checked').val());
|
formData.append('accessRank', $el.find('[name=access-rank]:checked').val());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (privileges.canBan) {
|
if (privileges.canBan) {
|
||||||
formData.append('banned', $el.find('[name=ban]').is(':checked') ? 1 : 0);
|
formData.append('banned', $el.find('[name=ban]').is(':checked') ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
promise.wait(api.post('/users/' + user.name, formData))
|
promise.wait(api.post('/users/' + user.name, formData))
|
||||||
.then(function(response) {
|
.then(function(response) {
|
||||||
editSuccess(response);
|
editSuccess(response);
|
||||||
}).fail(function(response) {
|
}).fail(function(response) {
|
||||||
editFailure(response);
|
editFailure(response);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function editSuccess(apiResponse) {
|
function editSuccess(apiResponse) {
|
||||||
var wasLoggedIn = auth.isLoggedIn(user.name);
|
var wasLoggedIn = auth.isLoggedIn(user.name);
|
||||||
user = apiResponse.json;
|
user = apiResponse.json;
|
||||||
if (wasLoggedIn) {
|
if (wasLoggedIn) {
|
||||||
auth.updateCurrentUser(user);
|
auth.updateCurrentUser(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
render();
|
render();
|
||||||
|
|
||||||
var $messages = jQuery(target).find('.messages');
|
var $messages = jQuery(target).find('.messages');
|
||||||
var message = 'Account settings updated!';
|
var message = 'Account settings updated!';
|
||||||
if (!apiResponse.json.confirmed) {
|
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.';
|
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);
|
messagePresenter.showInfo($messages, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
function editFailure(apiResponse) {
|
function editFailure(apiResponse) {
|
||||||
var $messages = jQuery(target).find('.messages');
|
var $messages = jQuery(target).find('.messages');
|
||||||
messagePresenter.showError($messages, apiResponse.json && apiResponse.json.error || apiResponse);
|
messagePresenter.showError($messages, apiResponse.json && apiResponse.json.error || apiResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
init: init,
|
init: init,
|
||||||
render: render,
|
render: render,
|
||||||
getPrivileges: getPrivileges,
|
getPrivileges: getPrivileges,
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,117 +2,117 @@ var App = App || {};
|
||||||
App.Presenters = App.Presenters || {};
|
App.Presenters = App.Presenters || {};
|
||||||
|
|
||||||
App.Presenters.UserActivationPresenter = function(
|
App.Presenters.UserActivationPresenter = function(
|
||||||
jQuery,
|
jQuery,
|
||||||
promise,
|
promise,
|
||||||
util,
|
util,
|
||||||
auth,
|
auth,
|
||||||
api,
|
api,
|
||||||
router,
|
router,
|
||||||
topNavigationPresenter,
|
topNavigationPresenter,
|
||||||
messagePresenter) {
|
messagePresenter) {
|
||||||
|
|
||||||
var $el = jQuery('#content');
|
var $el = jQuery('#content');
|
||||||
var $messages = $el;
|
var $messages = $el;
|
||||||
var templates = {};
|
var templates = {};
|
||||||
var formHidden = false;
|
var formHidden = false;
|
||||||
var operation;
|
var operation;
|
||||||
|
|
||||||
function init(params, loaded) {
|
function init(params, loaded) {
|
||||||
topNavigationPresenter.select('login');
|
topNavigationPresenter.select('login');
|
||||||
topNavigationPresenter.changeTitle('Account recovery');
|
topNavigationPresenter.changeTitle('Account recovery');
|
||||||
reinit(params, loaded);
|
reinit(params, loaded);
|
||||||
}
|
}
|
||||||
|
|
||||||
function reinit(params, loaded) {
|
function reinit(params, loaded) {
|
||||||
operation = params.operation;
|
operation = params.operation;
|
||||||
promise.wait(util.promiseTemplate('user-query-form'))
|
promise.wait(util.promiseTemplate('user-query-form'))
|
||||||
.then(function(template) {
|
.then(function(template) {
|
||||||
templates.userQuery = template;
|
templates.userQuery = template;
|
||||||
if (params.token) {
|
if (params.token) {
|
||||||
hideForm();
|
hideForm();
|
||||||
confirmToken(params.token);
|
confirmToken(params.token);
|
||||||
} else {
|
} else {
|
||||||
showForm();
|
showForm();
|
||||||
}
|
}
|
||||||
render();
|
render();
|
||||||
loaded();
|
loaded();
|
||||||
}).fail(function() {
|
}).fail(function() {
|
||||||
console.log(arguments);
|
console.log(arguments);
|
||||||
loaded();
|
loaded();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
$el.html(templates.userQuery());
|
$el.html(templates.userQuery());
|
||||||
$messages = $el.find('.messages');
|
$messages = $el.find('.messages');
|
||||||
if (formHidden) {
|
if (formHidden) {
|
||||||
$el.find('form').hide();
|
$el.find('form').hide();
|
||||||
}
|
}
|
||||||
$el.find('form').submit(userQueryFormSubmitted);
|
$el.find('form').submit(userQueryFormSubmitted);
|
||||||
}
|
}
|
||||||
|
|
||||||
function hideForm() {
|
function hideForm() {
|
||||||
formHidden = true;
|
formHidden = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function showForm() {
|
function showForm() {
|
||||||
formHidden = false;
|
formHidden = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function userQueryFormSubmitted(e) {
|
function userQueryFormSubmitted(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
messagePresenter.hideMessages($messages);
|
messagePresenter.hideMessages($messages);
|
||||||
|
|
||||||
var userNameOrEmail = $el.find('form input[name=user]').val();
|
var userNameOrEmail = $el.find('form input[name=user]').val();
|
||||||
if (userNameOrEmail.length === 0) {
|
if (userNameOrEmail.length === 0) {
|
||||||
messagePresenter.showError($messages, 'Field cannot be blank.');
|
messagePresenter.showError($messages, 'Field cannot be blank.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var url = operation === 'passwordReset' ?
|
var url = operation === 'passwordReset' ?
|
||||||
'/password-reset/' + userNameOrEmail :
|
'/password-reset/' + userNameOrEmail :
|
||||||
'/activation/' + userNameOrEmail;
|
'/activation/' + userNameOrEmail;
|
||||||
|
|
||||||
promise.wait(api.post(url))
|
promise.wait(api.post(url))
|
||||||
.then(function(response) {
|
.then(function(response) {
|
||||||
var message = operation === 'passwordReset' ?
|
var message = operation === 'passwordReset' ?
|
||||||
'Password reset request sent.' :
|
'Password reset request sent.' :
|
||||||
'Activation e-mail resent.';
|
'Activation e-mail resent.';
|
||||||
message += ' Check your inbox.<br/>If e-mail doesn\'t show up, check your spam folder.';
|
message += ' Check your inbox.<br/>If e-mail doesn\'t show up, check your spam folder.';
|
||||||
|
|
||||||
$el.find('#user-query-form').slideUp(function() {
|
$el.find('#user-query-form').slideUp(function() {
|
||||||
messagePresenter.showInfo($messages, message);
|
messagePresenter.showInfo($messages, message);
|
||||||
});
|
});
|
||||||
}).fail(function(response) {
|
}).fail(function(response) {
|
||||||
messagePresenter.showError($messages, response.json && response.json.error || response);
|
messagePresenter.showError($messages, response.json && response.json.error || response);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function confirmToken(token) {
|
function confirmToken(token) {
|
||||||
messagePresenter.hideMessages($messages);
|
messagePresenter.hideMessages($messages);
|
||||||
|
|
||||||
var url = operation === 'passwordReset' ?
|
var url = operation === 'passwordReset' ?
|
||||||
'/finish-password-reset/' + token :
|
'/finish-password-reset/' + token :
|
||||||
'/finish-activation/' + token;
|
'/finish-activation/' + token;
|
||||||
|
|
||||||
promise.wait(api.post(url))
|
promise.wait(api.post(url))
|
||||||
.then(function(response) {
|
.then(function(response) {
|
||||||
var message = operation === 'passwordReset' ?
|
var message = operation === 'passwordReset' ?
|
||||||
'Your new password is <strong>' + response.json.newPassword + '</strong>.' :
|
'Your new password is <strong>' + response.json.newPassword + '</strong>.' :
|
||||||
'E-mail activation successful.';
|
'E-mail activation successful.';
|
||||||
|
|
||||||
$el.find('#user-query-form').slideUp(function() {
|
$el.find('#user-query-form').slideUp(function() {
|
||||||
messagePresenter.showInfo($messages, message);
|
messagePresenter.showInfo($messages, message);
|
||||||
});
|
});
|
||||||
}).fail(function(response) {
|
}).fail(function(response) {
|
||||||
messagePresenter.showError($messages, response.json && response.json.error || response);
|
messagePresenter.showError($messages, response.json && response.json.error || response);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
init: init,
|
init: init,
|
||||||
reinit: reinit,
|
reinit: reinit,
|
||||||
render: render,
|
render: render,
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,75 +2,75 @@ var App = App || {};
|
||||||
App.Presenters = App.Presenters || {};
|
App.Presenters = App.Presenters || {};
|
||||||
|
|
||||||
App.Presenters.UserBrowsingSettingsPresenter = function(
|
App.Presenters.UserBrowsingSettingsPresenter = function(
|
||||||
jQuery,
|
jQuery,
|
||||||
util,
|
util,
|
||||||
promise,
|
promise,
|
||||||
auth,
|
auth,
|
||||||
browsingSettings,
|
browsingSettings,
|
||||||
messagePresenter) {
|
messagePresenter) {
|
||||||
|
|
||||||
var target;
|
var target;
|
||||||
var templates = {};
|
var templates = {};
|
||||||
var user;
|
var user;
|
||||||
var privileges = {};
|
var privileges = {};
|
||||||
|
|
||||||
function init(params, loaded) {
|
function init(params, loaded) {
|
||||||
user = params.user;
|
user = params.user;
|
||||||
target = params.target;
|
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'))
|
promise.wait(util.promiseTemplate('browsing-settings'))
|
||||||
.then(function(template) {
|
.then(function(template) {
|
||||||
templates.browsingSettings = template;
|
templates.browsingSettings = template;
|
||||||
render();
|
render();
|
||||||
loaded();
|
loaded();
|
||||||
}).fail(function() {
|
}).fail(function() {
|
||||||
console.log(arguments);
|
console.log(arguments);
|
||||||
loaded();
|
loaded();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
var $el = jQuery(target);
|
var $el = jQuery(target);
|
||||||
$el.html(templates.browsingSettings({user: user, settings: browsingSettings.getSettings()}));
|
$el.html(templates.browsingSettings({user: user, settings: browsingSettings.getSettings()}));
|
||||||
$el.find('form').submit(browsingSettingsFormSubmitted);
|
$el.find('form').submit(browsingSettingsFormSubmitted);
|
||||||
}
|
}
|
||||||
|
|
||||||
function browsingSettingsFormSubmitted(e) {
|
function browsingSettingsFormSubmitted(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var $el = jQuery(target);
|
var $el = jQuery(target);
|
||||||
var $messages = $el.find('.messages');
|
var $messages = $el.find('.messages');
|
||||||
messagePresenter.hideMessages($messages);
|
messagePresenter.hideMessages($messages);
|
||||||
|
|
||||||
var newSettings = {
|
var newSettings = {
|
||||||
endlessScroll: $el.find('[name=endlessScroll]').is(':checked'),
|
endlessScroll: $el.find('[name=endlessScroll]').is(':checked'),
|
||||||
hideDownvoted: $el.find('[name=hideDownvoted]').is(':checked'),
|
hideDownvoted: $el.find('[name=hideDownvoted]').is(':checked'),
|
||||||
listPosts: {
|
listPosts: {
|
||||||
safe: $el.find('[name=listSafePosts]').is(':checked'),
|
safe: $el.find('[name=listSafePosts]').is(':checked'),
|
||||||
sketchy: $el.find('[name=listSketchyPosts]').is(':checked'),
|
sketchy: $el.find('[name=listSketchyPosts]').is(':checked'),
|
||||||
unsafe: $el.find('[name=listUnsafePosts]').is(':checked'),
|
unsafe: $el.find('[name=listUnsafePosts]').is(':checked'),
|
||||||
},
|
},
|
||||||
keyboardShortcuts: $el.find('[name=keyboardShortcuts]').is(':checked'),
|
keyboardShortcuts: $el.find('[name=keyboardShortcuts]').is(':checked'),
|
||||||
};
|
};
|
||||||
|
|
||||||
promise.wait(browsingSettings.setSettings(newSettings))
|
promise.wait(browsingSettings.setSettings(newSettings))
|
||||||
.then(function() {
|
.then(function() {
|
||||||
messagePresenter.showInfo($messages, 'Browsing settings updated!');
|
messagePresenter.showInfo($messages, 'Browsing settings updated!');
|
||||||
}).fail(function() {
|
}).fail(function() {
|
||||||
console.log(arguments);
|
console.log(arguments);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPrivileges() {
|
function getPrivileges() {
|
||||||
return privileges;
|
return privileges;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
init: init,
|
init: init,
|
||||||
render: render,
|
render: render,
|
||||||
getPrivileges: getPrivileges,
|
getPrivileges: getPrivileges,
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,93 +2,93 @@ var App = App || {};
|
||||||
App.Presenters = App.Presenters || {};
|
App.Presenters = App.Presenters || {};
|
||||||
|
|
||||||
App.Presenters.UserListPresenter = function(
|
App.Presenters.UserListPresenter = function(
|
||||||
_,
|
_,
|
||||||
jQuery,
|
jQuery,
|
||||||
util,
|
util,
|
||||||
promise,
|
promise,
|
||||||
auth,
|
auth,
|
||||||
pagerPresenter,
|
pagerPresenter,
|
||||||
topNavigationPresenter) {
|
topNavigationPresenter) {
|
||||||
|
|
||||||
var $el = jQuery('#content');
|
var $el = jQuery('#content');
|
||||||
var templates = {};
|
var templates = {};
|
||||||
var params;
|
var params;
|
||||||
var privileges = {};
|
var privileges = {};
|
||||||
|
|
||||||
function init(params, loaded) {
|
function init(params, loaded) {
|
||||||
topNavigationPresenter.select('users');
|
topNavigationPresenter.select('users');
|
||||||
topNavigationPresenter.changeTitle('Users');
|
topNavigationPresenter.changeTitle('Users');
|
||||||
|
|
||||||
privileges.canViewUsers = auth.hasPrivilege(auth.privileges.viewUsers);
|
privileges.canViewUsers = auth.hasPrivilege(auth.privileges.viewUsers);
|
||||||
|
|
||||||
promise.wait(
|
promise.wait(
|
||||||
util.promiseTemplate('user-list'),
|
util.promiseTemplate('user-list'),
|
||||||
util.promiseTemplate('user-list-item'))
|
util.promiseTemplate('user-list-item'))
|
||||||
.then(function(listTemplate, listItemTemplate) {
|
.then(function(listTemplate, listItemTemplate) {
|
||||||
templates.list = listTemplate;
|
templates.list = listTemplate;
|
||||||
templates.listItem = listItemTemplate;
|
templates.listItem = listItemTemplate;
|
||||||
|
|
||||||
render();
|
render();
|
||||||
loaded();
|
loaded();
|
||||||
|
|
||||||
pagerPresenter.init({
|
pagerPresenter.init({
|
||||||
baseUri: '#/users',
|
baseUri: '#/users',
|
||||||
backendUri: '/users',
|
backendUri: '/users',
|
||||||
$target: $el.find('.pagination-target'),
|
$target: $el.find('.pagination-target'),
|
||||||
updateCallback: function($page, data) {
|
updateCallback: function($page, data) {
|
||||||
renderUsers($page, data.entities);
|
renderUsers($page, data.entities);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
function() {
|
function() {
|
||||||
reinit(params, function() {});
|
reinit(params, function() {});
|
||||||
});
|
});
|
||||||
}).fail(function() {
|
}).fail(function() {
|
||||||
console.log(arguments);
|
console.log(arguments);
|
||||||
loaded();
|
loaded();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function reinit(_params, loaded) {
|
function reinit(_params, loaded) {
|
||||||
params = _params;
|
params = _params;
|
||||||
params.query = params.query || {};
|
params.query = params.query || {};
|
||||||
params.query.order = params.query.order || 'name,asc';
|
params.query.order = params.query.order || 'name,asc';
|
||||||
updateActiveOrder(params.query.order);
|
updateActiveOrder(params.query.order);
|
||||||
|
|
||||||
pagerPresenter.reinit({query: params.query});
|
pagerPresenter.reinit({query: params.query});
|
||||||
loaded();
|
loaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
function deinit() {
|
function deinit() {
|
||||||
pagerPresenter.deinit();
|
pagerPresenter.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
$el.html(templates.list(privileges));
|
$el.html(templates.list(privileges));
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateActiveOrder(activeOrder) {
|
function updateActiveOrder(activeOrder) {
|
||||||
$el.find('.order li a.active').removeClass('active');
|
$el.find('.order li a.active').removeClass('active');
|
||||||
$el.find('.order [href*="' + activeOrder + '"]').addClass('active');
|
$el.find('.order [href*="' + activeOrder + '"]').addClass('active');
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderUsers($page, users) {
|
function renderUsers($page, users) {
|
||||||
var $target = $page.find('.users');
|
var $target = $page.find('.users');
|
||||||
_.each(users, function(user) {
|
_.each(users, function(user) {
|
||||||
var $item = jQuery('<li>' + templates.listItem(_.extend({
|
var $item = jQuery('<li>' + templates.listItem(_.extend({
|
||||||
user: user,
|
user: user,
|
||||||
util: util,
|
util: util,
|
||||||
}, privileges)) + '</li>');
|
}, privileges)) + '</li>');
|
||||||
$target.append($item);
|
$target.append($item);
|
||||||
});
|
});
|
||||||
_.map(_.map($target.find('img'), jQuery), util.loadImagesNicely);
|
_.map(_.map($target.find('img'), jQuery), util.loadImagesNicely);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
init: init,
|
init: init,
|
||||||
reinit: reinit,
|
reinit: reinit,
|
||||||
deinit: deinit,
|
deinit: deinit,
|
||||||
render: render,
|
render: render,
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,105 +2,105 @@ var App = App || {};
|
||||||
App.Presenters = App.Presenters || {};
|
App.Presenters = App.Presenters || {};
|
||||||
|
|
||||||
App.Presenters.UserPresenter = function(
|
App.Presenters.UserPresenter = function(
|
||||||
_,
|
_,
|
||||||
jQuery,
|
jQuery,
|
||||||
util,
|
util,
|
||||||
promise,
|
promise,
|
||||||
api,
|
api,
|
||||||
auth,
|
auth,
|
||||||
topNavigationPresenter,
|
topNavigationPresenter,
|
||||||
presenterManager,
|
presenterManager,
|
||||||
userBrowsingSettingsPresenter,
|
userBrowsingSettingsPresenter,
|
||||||
userAccountSettingsPresenter,
|
userAccountSettingsPresenter,
|
||||||
userAccountRemovalPresenter,
|
userAccountRemovalPresenter,
|
||||||
messagePresenter) {
|
messagePresenter) {
|
||||||
|
|
||||||
var $el = jQuery('#content');
|
var $el = jQuery('#content');
|
||||||
var $messages = $el;
|
var $messages = $el;
|
||||||
var templates = {};
|
var templates = {};
|
||||||
var user;
|
var user;
|
||||||
var userName = null;
|
var userName = null;
|
||||||
var activeTab;
|
var activeTab;
|
||||||
|
|
||||||
function init(params, loaded) {
|
function init(params, loaded) {
|
||||||
promise.wait(util.promiseTemplate('user'))
|
promise.wait(util.promiseTemplate('user'))
|
||||||
.then(function(template) {
|
.then(function(template) {
|
||||||
templates.user = template;
|
templates.user = template;
|
||||||
reinit(params, loaded);
|
reinit(params, loaded);
|
||||||
}).fail(function() {
|
}).fail(function() {
|
||||||
console.log(arguments);
|
console.log(arguments);
|
||||||
loaded();
|
loaded();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function reinit(params, loaded) {
|
function reinit(params, loaded) {
|
||||||
if (params.userName !== userName) {
|
if (params.userName !== userName) {
|
||||||
userName = params.userName;
|
userName = params.userName;
|
||||||
topNavigationPresenter.select(auth.isLoggedIn(userName) ? 'my-account' : 'users');
|
topNavigationPresenter.select(auth.isLoggedIn(userName) ? 'my-account' : 'users');
|
||||||
topNavigationPresenter.changeTitle(userName);
|
topNavigationPresenter.changeTitle(userName);
|
||||||
|
|
||||||
promise.wait(api.get('/users/' + userName))
|
promise.wait(api.get('/users/' + userName))
|
||||||
.then(function(response) {
|
.then(function(response) {
|
||||||
user = response.json;
|
user = response.json;
|
||||||
var extendedContext = _.extend(params, {user: user});
|
var extendedContext = _.extend(params, {user: user});
|
||||||
|
|
||||||
presenterManager.initPresenters([
|
presenterManager.initPresenters([
|
||||||
[userBrowsingSettingsPresenter, _.extend({}, extendedContext, {target: '#browsing-settings-target'})],
|
[userBrowsingSettingsPresenter, _.extend({}, extendedContext, {target: '#browsing-settings-target'})],
|
||||||
[userAccountSettingsPresenter, _.extend({}, extendedContext, {target: '#account-settings-target'})],
|
[userAccountSettingsPresenter, _.extend({}, extendedContext, {target: '#account-settings-target'})],
|
||||||
[userAccountRemovalPresenter, _.extend({}, extendedContext, {target: '#account-removal-target'})]],
|
[userAccountRemovalPresenter, _.extend({}, extendedContext, {target: '#account-removal-target'})]],
|
||||||
function() {
|
function() {
|
||||||
initTabs(params);
|
initTabs(params);
|
||||||
loaded();
|
loaded();
|
||||||
});
|
});
|
||||||
|
|
||||||
}).fail(function(response) {
|
}).fail(function(response) {
|
||||||
$el.empty();
|
$el.empty();
|
||||||
messagePresenter.showError($messages, response.json && response.json.error || response);
|
messagePresenter.showError($messages, response.json && response.json.error || response);
|
||||||
loaded();
|
loaded();
|
||||||
});
|
});
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
initTabs(params);
|
initTabs(params);
|
||||||
loaded();
|
loaded();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function initTabs(params) {
|
function initTabs(params) {
|
||||||
activeTab = params.tab || 'basic-info';
|
activeTab = params.tab || 'basic-info';
|
||||||
render();
|
render();
|
||||||
}
|
}
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
$el.html(templates.user({
|
$el.html(templates.user({
|
||||||
user: user,
|
user: user,
|
||||||
isLoggedIn: auth.isLoggedIn(user.name),
|
isLoggedIn: auth.isLoggedIn(user.name),
|
||||||
util: util,
|
util: util,
|
||||||
canChangeBrowsingSettings: userBrowsingSettingsPresenter.getPrivileges().canChangeBrowsingSettings,
|
canChangeBrowsingSettings: userBrowsingSettingsPresenter.getPrivileges().canChangeBrowsingSettings,
|
||||||
canChangeAccountSettings: _.any(userAccountSettingsPresenter.getPrivileges()),
|
canChangeAccountSettings: _.any(userAccountSettingsPresenter.getPrivileges()),
|
||||||
canDeleteAccount: userAccountRemovalPresenter.getPrivileges().canDeleteAccount}));
|
canDeleteAccount: userAccountRemovalPresenter.getPrivileges().canDeleteAccount}));
|
||||||
$messages = $el.find('.messages');
|
$messages = $el.find('.messages');
|
||||||
util.loadImagesNicely($el.find('img'));
|
util.loadImagesNicely($el.find('img'));
|
||||||
userBrowsingSettingsPresenter.render();
|
userBrowsingSettingsPresenter.render();
|
||||||
userAccountSettingsPresenter.render();
|
userAccountSettingsPresenter.render();
|
||||||
userAccountRemovalPresenter.render();
|
userAccountRemovalPresenter.render();
|
||||||
changeTab(activeTab);
|
changeTab(activeTab);
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeTab(targetTab) {
|
function changeTab(targetTab) {
|
||||||
var $link = $el.find('a[data-tab=' + targetTab + ']');
|
var $link = $el.find('a[data-tab=' + targetTab + ']');
|
||||||
var $links = $link.closest('ul').find('a[data-tab]');
|
var $links = $link.closest('ul').find('a[data-tab]');
|
||||||
var $tabs = $el.find('.tab-wrapper').find('.tab');
|
var $tabs = $el.find('.tab-wrapper').find('.tab');
|
||||||
$links.removeClass('active');
|
$links.removeClass('active');
|
||||||
$link.addClass('active');
|
$link.addClass('active');
|
||||||
$tabs.removeClass('active');
|
$tabs.removeClass('active');
|
||||||
$tabs.filter('[data-tab=' + targetTab + ']').addClass('active');
|
$tabs.filter('[data-tab=' + targetTab + ']').addClass('active');
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
init: init,
|
init: init,
|
||||||
reinit: reinit,
|
reinit: reinit,
|
||||||
render: render
|
render: render
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,84 +2,84 @@ var App = App || {};
|
||||||
|
|
||||||
App.Promise = function(_, jQuery, progress) {
|
App.Promise = function(_, jQuery, progress) {
|
||||||
|
|
||||||
function BrokenPromiseError(promiseId) {
|
function BrokenPromiseError(promiseId) {
|
||||||
this.name = 'BrokenPromiseError';
|
this.name = 'BrokenPromiseError';
|
||||||
this.message = 'Broken promise (promise ID: ' + promiseId + ')';
|
this.message = 'Broken promise (promise ID: ' + promiseId + ')';
|
||||||
}
|
}
|
||||||
BrokenPromiseError.prototype = new Error();
|
BrokenPromiseError.prototype = new Error();
|
||||||
|
|
||||||
var active = [];
|
var active = [];
|
||||||
var promiseId = 0;
|
var promiseId = 0;
|
||||||
|
|
||||||
function make(callback, useProgress) {
|
function make(callback, useProgress) {
|
||||||
var deferred = jQuery.Deferred();
|
var deferred = jQuery.Deferred();
|
||||||
var promise = deferred.promise();
|
var promise = deferred.promise();
|
||||||
promise.promiseId = ++ promiseId;
|
promise.promiseId = ++ promiseId;
|
||||||
|
|
||||||
if (useProgress === true) {
|
if (useProgress === true) {
|
||||||
progress.start();
|
progress.start();
|
||||||
}
|
}
|
||||||
callback(function() {
|
callback(function() {
|
||||||
try {
|
try {
|
||||||
deferred.resolve.apply(deferred, arguments);
|
deferred.resolve.apply(deferred, arguments);
|
||||||
active = _.without(active, promise.promiseId);
|
active = _.without(active, promise.promiseId);
|
||||||
progress.done();
|
progress.done();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (!(e instanceof BrokenPromiseError)) {
|
if (!(e instanceof BrokenPromiseError)) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
}
|
}
|
||||||
progress.reset();
|
progress.reset();
|
||||||
}
|
}
|
||||||
}, function() {
|
}, function() {
|
||||||
try {
|
try {
|
||||||
deferred.reject.apply(deferred, arguments);
|
deferred.reject.apply(deferred, arguments);
|
||||||
active = _.without(active, promise.promiseId);
|
active = _.without(active, promise.promiseId);
|
||||||
progress.done();
|
progress.done();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (!(e instanceof BrokenPromiseError)) {
|
if (!(e instanceof BrokenPromiseError)) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
}
|
}
|
||||||
progress.reset();
|
progress.reset();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
active.push(promise.promiseId);
|
active.push(promise.promiseId);
|
||||||
|
|
||||||
promise.always(function() {
|
promise.always(function() {
|
||||||
if (!_.contains(active, promise.promiseId)) {
|
if (!_.contains(active, promise.promiseId)) {
|
||||||
throw new BrokenPromiseError(promise.promiseId);
|
throw new BrokenPromiseError(promise.promiseId);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
function wait() {
|
function wait() {
|
||||||
var promises = arguments;
|
var promises = arguments;
|
||||||
var deferred = jQuery.Deferred();
|
var deferred = jQuery.Deferred();
|
||||||
return jQuery.when.apply(jQuery, promises)
|
return jQuery.when.apply(jQuery, promises)
|
||||||
.then(function() {
|
.then(function() {
|
||||||
return deferred.resolve.apply(deferred, arguments);
|
return deferred.resolve.apply(deferred, arguments);
|
||||||
}).fail(function() {
|
}).fail(function() {
|
||||||
return deferred.reject.apply(deferred, arguments);
|
return deferred.reject.apply(deferred, arguments);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function abortAll() {
|
function abortAll() {
|
||||||
active = [];
|
active = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
function getActive() {
|
function getActive() {
|
||||||
return active.length;
|
return active.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
make: function(callback) { return make(callback, true); },
|
make: function(callback) { return make(callback, true); },
|
||||||
makeSilent: function(callback) { return make(callback, false); },
|
makeSilent: function(callback) { return make(callback, false); },
|
||||||
wait: wait,
|
wait: wait,
|
||||||
getActive: getActive,
|
getActive: getActive,
|
||||||
abortAll: abortAll,
|
abortAll: abortAll,
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,184 +2,184 @@ var App = App || {};
|
||||||
|
|
||||||
App.Router = function(_, jQuery, promise, util, appState, presenterManager) {
|
App.Router = function(_, jQuery, promise, util, appState, presenterManager) {
|
||||||
|
|
||||||
var root = '#/';
|
var root = '#/';
|
||||||
var previousLocation = window.location.href;
|
var previousLocation = window.location.href;
|
||||||
var routes = [];
|
var routes = [];
|
||||||
|
|
||||||
injectRoutes();
|
injectRoutes();
|
||||||
|
|
||||||
function injectRoutes() {
|
function injectRoutes() {
|
||||||
inject('', 'homePresenter');
|
inject('', 'homePresenter');
|
||||||
inject('#/', 'homePresenter');
|
inject('#/', 'homePresenter');
|
||||||
inject('#/404', 'httpErrorPresenter', {error: 404});
|
inject('#/404', 'httpErrorPresenter', {error: 404});
|
||||||
inject('#/home', 'homePresenter');
|
inject('#/home', 'homePresenter');
|
||||||
inject('#/login', 'loginPresenter');
|
inject('#/login', 'loginPresenter');
|
||||||
inject('#/logout', 'logoutPresenter');
|
inject('#/logout', 'logoutPresenter');
|
||||||
inject('#/register', 'registrationPresenter');
|
inject('#/register', 'registrationPresenter');
|
||||||
inject('#/upload', 'postUploadPresenter');
|
inject('#/upload', 'postUploadPresenter');
|
||||||
inject('#/password-reset(/:token)', 'userActivationPresenter', {operation: 'passwordReset'});
|
inject('#/password-reset(/:token)', 'userActivationPresenter', {operation: 'passwordReset'});
|
||||||
inject('#/activate(/:token)', 'userActivationPresenter', {operation: 'activation'});
|
inject('#/activate(/:token)', 'userActivationPresenter', {operation: 'activation'});
|
||||||
inject('#/users(/:!query)', 'userListPresenter');
|
inject('#/users(/:!query)', 'userListPresenter');
|
||||||
inject('#/user/:userName(/:tab)', 'userPresenter');
|
inject('#/user/:userName(/:tab)', 'userPresenter');
|
||||||
inject('#/posts(/:!query)', 'postListPresenter');
|
inject('#/posts(/:!query)', 'postListPresenter');
|
||||||
inject('#/post/:postNameOrId(/:!query)', 'postPresenter');
|
inject('#/post/:postNameOrId(/:!query)', 'postPresenter');
|
||||||
inject('#/comments(/:!query)', 'globalCommentListPresenter');
|
inject('#/comments(/:!query)', 'globalCommentListPresenter');
|
||||||
inject('#/tags(/:!query)', 'tagListPresenter');
|
inject('#/tags(/:!query)', 'tagListPresenter');
|
||||||
inject('#/tag/:tagName', 'tagPresenter');
|
inject('#/tag/:tagName', 'tagPresenter');
|
||||||
inject('#/help(/:tab)', 'helpPresenter');
|
inject('#/help(/:tab)', 'helpPresenter');
|
||||||
inject('#/history(/:!query)', 'historyPresenter');
|
inject('#/history(/:!query)', 'historyPresenter');
|
||||||
}
|
}
|
||||||
|
|
||||||
function navigate(url, useBrowserDispatcher) {
|
function navigate(url, useBrowserDispatcher) {
|
||||||
if (('pushState' in history) && !useBrowserDispatcher) {
|
if (('pushState' in history) && !useBrowserDispatcher) {
|
||||||
history.pushState('', '', url);
|
history.pushState('', '', url);
|
||||||
dispatch();
|
dispatch();
|
||||||
} else {
|
} else {
|
||||||
window.location.href = url;
|
window.location.href = url;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function navigateToMainPage() {
|
function navigateToMainPage() {
|
||||||
navigate(root);
|
navigate(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
function navigateInplace(url, useBrowserDispatcher) {
|
function navigateInplace(url, useBrowserDispatcher) {
|
||||||
if ('replaceState' in history) {
|
if ('replaceState' in history) {
|
||||||
history.replaceState('', '', url);
|
history.replaceState('', '', url);
|
||||||
if (!useBrowserDispatcher) {
|
if (!useBrowserDispatcher) {
|
||||||
dispatch();
|
dispatch();
|
||||||
} else {
|
} else {
|
||||||
location.reload();
|
location.reload();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
navigate(url, useBrowserDispatcher);
|
navigate(url, useBrowserDispatcher);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function start() {
|
function start() {
|
||||||
if ('onhashchange' in window) {
|
if ('onhashchange' in window) {
|
||||||
window.onhashchange = dispatch;
|
window.onhashchange = dispatch;
|
||||||
} else {
|
} else {
|
||||||
window.onpopstate = dispatch;
|
window.onpopstate = dispatch;
|
||||||
}
|
}
|
||||||
dispatch();
|
dispatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
function inject(definition, presenterName, additionalParams) {
|
function inject(definition, presenterName, additionalParams) {
|
||||||
routes.push(new Route(definition, function(params) {
|
routes.push(new Route(definition, function(params) {
|
||||||
if (util.isExitConfirmationEnabled()) {
|
if (util.isExitConfirmationEnabled()) {
|
||||||
if (window.location.href === previousLocation) {
|
if (window.location.href === previousLocation) {
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
if (window.confirm('Are you sure you want to leave this page? Data will be lost.')) {
|
if (window.confirm('Are you sure you want to leave this page? Data will be lost.')) {
|
||||||
util.disableExitConfirmation();
|
util.disableExitConfirmation();
|
||||||
} else {
|
} else {
|
||||||
window.location.href = previousLocation;
|
window.location.href = previousLocation;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
params = _.extend({}, params, additionalParams, {previousLocation: previousLocation});
|
params = _.extend({}, params, additionalParams, {previousLocation: previousLocation});
|
||||||
|
|
||||||
//abort every operation that can be executed
|
//abort every operation that can be executed
|
||||||
promise.abortAll();
|
promise.abortAll();
|
||||||
previousLocation = window.location.href;
|
previousLocation = window.location.href;
|
||||||
|
|
||||||
var presenter = App.DI.get(presenterName);
|
var presenter = App.DI.get(presenterName);
|
||||||
presenter.name = presenterName;
|
presenter.name = presenterName;
|
||||||
presenterManager.switchContentPresenter(presenter, params);
|
presenterManager.switchContentPresenter(presenter, params);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
function dispatch() {
|
function dispatch() {
|
||||||
var url = document.location.hash;
|
var url = document.location.hash;
|
||||||
for (var i = 0; i < routes.length; i ++) {
|
for (var i = 0; i < routes.length; i ++) {
|
||||||
var route = routes[i];
|
var route = routes[i];
|
||||||
if (route.match(url)) {
|
if (route.match(url)) {
|
||||||
route.callback(route.params);
|
route.callback(route.params);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
navigateInplace('#/404', true);
|
navigateInplace('#/404', true);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseComplexParamValue(value) {
|
function parseComplexParamValue(value) {
|
||||||
var result = {};
|
var result = {};
|
||||||
var params = (value || '').split(/;/);
|
var params = (value || '').split(/;/);
|
||||||
for (var i = 0; i < params.length; i ++) {
|
for (var i = 0; i < params.length; i ++) {
|
||||||
var param = params[i];
|
var param = params[i];
|
||||||
if (!param) {
|
if (!param) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
var kv = param.split(/=/);
|
var kv = param.split(/=/);
|
||||||
result[kv[0]] = kv[1];
|
result[kv[0]] = kv[1];
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
function Route(definition, callback) {
|
function Route(definition, callback) {
|
||||||
var possibleRoutes = getPossibleRoutes(definition);
|
var possibleRoutes = getPossibleRoutes(definition);
|
||||||
|
|
||||||
function getPossibleRoutes(routeDefinition) {
|
function getPossibleRoutes(routeDefinition) {
|
||||||
var parts = [];
|
var parts = [];
|
||||||
var re = new RegExp('\\(([^}]+?)\\)', 'g');
|
var re = new RegExp('\\(([^}]+?)\\)', 'g');
|
||||||
while (true) {
|
while (true) {
|
||||||
var text = re.exec(routeDefinition);
|
var text = re.exec(routeDefinition);
|
||||||
if (!text) {
|
if (!text) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
parts.push(text[1]);
|
parts.push(text[1]);
|
||||||
}
|
}
|
||||||
var possibleRoutes = [routeDefinition.split('(')[0]];
|
var possibleRoutes = [routeDefinition.split('(')[0]];
|
||||||
for (var i = 0; i < parts.length; i ++) {
|
for (var i = 0; i < parts.length; i ++) {
|
||||||
possibleRoutes.push(possibleRoutes[possibleRoutes.length - 1] + parts[i]);
|
possibleRoutes.push(possibleRoutes[possibleRoutes.length - 1] + parts[i]);
|
||||||
}
|
}
|
||||||
return possibleRoutes;
|
return possibleRoutes;
|
||||||
}
|
}
|
||||||
|
|
||||||
function match(url) {
|
function match(url) {
|
||||||
var params = {};
|
var params = {};
|
||||||
for (var i = 0; i < possibleRoutes.length; i ++) {
|
for (var i = 0; i < possibleRoutes.length; i ++) {
|
||||||
var possibleRoute = possibleRoutes[i];
|
var possibleRoute = possibleRoutes[i];
|
||||||
var compare = url;
|
var compare = url;
|
||||||
var possibleRouteParts = possibleRoute.split('/');
|
var possibleRouteParts = possibleRoute.split('/');
|
||||||
var compareParts = compare.split('/');
|
var compareParts = compare.split('/');
|
||||||
if (possibleRoute.search(':') > 0) {
|
if (possibleRoute.search(':') > 0) {
|
||||||
for (var j = 0; j < possibleRouteParts.length; j ++) {
|
for (var j = 0; j < possibleRouteParts.length; j ++) {
|
||||||
if ((j < compareParts.length) && (possibleRouteParts[j].charAt(0) === ':')) {
|
if ((j < compareParts.length) && (possibleRouteParts[j].charAt(0) === ':')) {
|
||||||
var key = possibleRouteParts[j].substring(1);
|
var key = possibleRouteParts[j].substring(1);
|
||||||
var value = compareParts[j];
|
var value = compareParts[j];
|
||||||
if (key.charAt(0) === '!') {
|
if (key.charAt(0) === '!') {
|
||||||
key = key.substring(1);
|
key = key.substring(1);
|
||||||
value = parseComplexParamValue(value);
|
value = parseComplexParamValue(value);
|
||||||
}
|
}
|
||||||
params[key] = value;
|
params[key] = value;
|
||||||
compareParts[j] = possibleRouteParts[j];
|
compareParts[j] = possibleRouteParts[j];
|
||||||
compare = compareParts.join('/');
|
compare = compareParts.join('/');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (possibleRoute === compare) {
|
if (possibleRoute === compare) {
|
||||||
this.params = params;
|
this.params = params;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.match = match;
|
this.match = match;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
start: start,
|
start: start,
|
||||||
navigate: navigate,
|
navigate: navigate,
|
||||||
navigateInplace: navigateInplace,
|
navigateInplace: navigateInplace,
|
||||||
navigateToMainPage: navigateToMainPage,
|
navigateToMainPage: navigateToMainPage,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
App.DI.registerSingleton('router', ['_', 'jQuery', 'promise', 'util', 'appState', 'presenterManager'], App.Router);
|
App.DI.registerSingleton('router', ['_', 'jQuery', 'promise', 'util', 'appState', 'presenterManager'], App.Router);
|
||||||
|
|
|
@ -3,83 +3,83 @@ App.Services = App.Services || {};
|
||||||
|
|
||||||
App.Services.PostsAroundCalculator = function(_, promise, util, pager) {
|
App.Services.PostsAroundCalculator = function(_, promise, util, pager) {
|
||||||
|
|
||||||
pager.init({url: '/posts'});
|
pager.init({url: '/posts'});
|
||||||
|
|
||||||
function resetCache() {
|
function resetCache() {
|
||||||
pager.resetCache();
|
pager.resetCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLinksToPostsAround(query, postId) {
|
function getLinksToPostsAround(query, postId) {
|
||||||
return promise.make(function(resolve, reject) {
|
return promise.make(function(resolve, reject) {
|
||||||
pager.setSearchParams(query);
|
pager.setSearchParams(query);
|
||||||
pager.setPage(query.page);
|
pager.setPage(query.page);
|
||||||
promise.wait(pager.retrieveCached())
|
promise.wait(pager.retrieveCached())
|
||||||
.then(function(response) {
|
.then(function(response) {
|
||||||
var postIds = _.pluck(response.entities, 'id');
|
var postIds = _.pluck(response.entities, 'id');
|
||||||
var position = _.indexOf(postIds, postId);
|
var position = _.indexOf(postIds, postId);
|
||||||
|
|
||||||
if (position === -1) {
|
if (position === -1) {
|
||||||
resolve(null, null);
|
resolve(null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
promise.wait(
|
promise.wait(
|
||||||
getLinkToPostAround(postIds, position, query.page, -1),
|
getLinkToPostAround(postIds, position, query.page, -1),
|
||||||
getLinkToPostAround(postIds, position, query.page, 1))
|
getLinkToPostAround(postIds, position, query.page, 1))
|
||||||
.then(function(nextPostUrl, prevPostUrl) {
|
.then(function(nextPostUrl, prevPostUrl) {
|
||||||
resolve(nextPostUrl, prevPostUrl);
|
resolve(nextPostUrl, prevPostUrl);
|
||||||
}).fail(function() {
|
}).fail(function() {
|
||||||
reject();
|
reject();
|
||||||
});
|
});
|
||||||
}).fail(function() {
|
}).fail(function() {
|
||||||
reject();
|
reject();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLinkToPostAround(postIds, position, page, direction) {
|
function getLinkToPostAround(postIds, position, page, direction) {
|
||||||
return promise.make(function(resolve, reject) {
|
return promise.make(function(resolve, reject) {
|
||||||
if (position + direction >= 0 && position + direction < postIds.length) {
|
if (position + direction >= 0 && position + direction < postIds.length) {
|
||||||
var url = util.appendComplexRouteParam(
|
var url = util.appendComplexRouteParam(
|
||||||
'#/post/' + postIds[position + direction],
|
'#/post/' + postIds[position + direction],
|
||||||
util.simplifySearchQuery(
|
util.simplifySearchQuery(
|
||||||
_.extend(
|
_.extend(
|
||||||
{page: page},
|
{page: page},
|
||||||
pager.getSearchParams())));
|
pager.getSearchParams())));
|
||||||
|
|
||||||
resolve(url);
|
resolve(url);
|
||||||
} else if (page + direction >= 1) {
|
} else if (page + direction >= 1) {
|
||||||
pager.setPage(page + direction);
|
pager.setPage(page + direction);
|
||||||
promise.wait(pager.retrieveCached())
|
promise.wait(pager.retrieveCached())
|
||||||
.then(function(response) {
|
.then(function(response) {
|
||||||
if (response.entities.length) {
|
if (response.entities.length) {
|
||||||
var post = direction === - 1 ?
|
var post = direction === - 1 ?
|
||||||
_.last(response.entities) :
|
_.last(response.entities) :
|
||||||
_.first(response.entities);
|
_.first(response.entities);
|
||||||
|
|
||||||
var url = util.appendComplexRouteParam(
|
var url = util.appendComplexRouteParam(
|
||||||
'#/post/' + post.id,
|
'#/post/' + post.id,
|
||||||
util.simplifySearchQuery(
|
util.simplifySearchQuery(
|
||||||
_.extend(
|
_.extend(
|
||||||
{page: page + direction},
|
{page: page + direction},
|
||||||
pager.getSearchParams())));
|
pager.getSearchParams())));
|
||||||
|
|
||||||
resolve(url);
|
resolve(url);
|
||||||
} else {
|
} else {
|
||||||
resolve(null);
|
resolve(null);
|
||||||
}
|
}
|
||||||
}).fail(function() {
|
}).fail(function() {
|
||||||
reject();
|
reject();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
resolve(null);
|
resolve(null);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
resetCache: resetCache,
|
resetCache: resetCache,
|
||||||
getLinksToPostsAround: getLinksToPostsAround,
|
getLinksToPostsAround: getLinksToPostsAround,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
App.DI.register('postsAroundCalculator', ['_', 'promise', 'util', 'pager'], App.Services.PostsAroundCalculator);
|
App.DI.register('postsAroundCalculator', ['_', 'promise', 'util', 'pager'], App.Services.PostsAroundCalculator);
|
||||||
|
|
|
@ -2,31 +2,31 @@ var App = App || {};
|
||||||
App.Services = App.Services || {};
|
App.Services = App.Services || {};
|
||||||
|
|
||||||
App.Services.TagList = function(jQuery) {
|
App.Services.TagList = function(jQuery) {
|
||||||
var tags = [];
|
var tags = [];
|
||||||
|
|
||||||
function refreshTags() {
|
function refreshTags() {
|
||||||
jQuery.ajax({
|
jQuery.ajax({
|
||||||
success: function(data, textStatus, xhr) {
|
success: function(data, textStatus, xhr) {
|
||||||
tags = data;
|
tags = data;
|
||||||
},
|
},
|
||||||
error: function(xhr, textStatus, errorThrown) {
|
error: function(xhr, textStatus, errorThrown) {
|
||||||
console.log(new Error(errorThrown));
|
console.log(new Error(errorThrown));
|
||||||
},
|
},
|
||||||
type: 'GET',
|
type: 'GET',
|
||||||
url: '/data/tags.json',
|
url: '/data/tags.json',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTags() {
|
function getTags() {
|
||||||
return tags;
|
return tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
refreshTags();
|
refreshTags();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
refreshTags: refreshTags,
|
refreshTags: refreshTags,
|
||||||
getTags: getTags,
|
getTags: getTags,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
App.DI.registerSingleton('tagList', ['jQuery'], App.Services.TagList);
|
App.DI.registerSingleton('tagList', ['jQuery'], App.Services.TagList);
|
||||||
|
|
|
@ -2,50 +2,50 @@ var App = App || {};
|
||||||
|
|
||||||
App.State = function() {
|
App.State = function() {
|
||||||
|
|
||||||
var properties = {};
|
var properties = {};
|
||||||
var observers = {};
|
var observers = {};
|
||||||
|
|
||||||
function get(key) {
|
function get(key) {
|
||||||
return properties[key];
|
return properties[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
function set(key, value) {
|
function set(key, value) {
|
||||||
properties[key] = value;
|
properties[key] = value;
|
||||||
if (key in observers) {
|
if (key in observers) {
|
||||||
for (var observerName in observers[key]) {
|
for (var observerName in observers[key]) {
|
||||||
if (observers[key].hasOwnProperty(observerName)) {
|
if (observers[key].hasOwnProperty(observerName)) {
|
||||||
observers[key][observerName](key, value);
|
observers[key][observerName](key, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function startObserving(key, observerName, callback) {
|
function startObserving(key, observerName, callback) {
|
||||||
if (!(key in observers)) {
|
if (!(key in observers)) {
|
||||||
observers[key] = {};
|
observers[key] = {};
|
||||||
}
|
}
|
||||||
if (!(observerName in observers[key])) {
|
if (!(observerName in observers[key])) {
|
||||||
observers[key][observerName] = {};
|
observers[key][observerName] = {};
|
||||||
}
|
}
|
||||||
observers[key][observerName] = callback;
|
observers[key][observerName] = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
function stopObserving(key, observerName) {
|
function stopObserving(key, observerName) {
|
||||||
if (!(key in observers)) {
|
if (!(key in observers)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!(observerName in observers[key])) {
|
if (!(observerName in observers[key])) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
delete observers[key][observerName];
|
delete observers[key][observerName];
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
get: get,
|
get: get,
|
||||||
set: set,
|
set: set,
|
||||||
startObserving: startObserving,
|
startObserving: startObserving,
|
||||||
stopObserving: stopObserving,
|
stopObserving: stopObserving,
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,146 +2,146 @@ var App = App || {};
|
||||||
App.Util = App.Util || {};
|
App.Util = App.Util || {};
|
||||||
|
|
||||||
App.Util.Draggable = function(jQuery) {
|
App.Util.Draggable = function(jQuery) {
|
||||||
var KEY_LEFT = 37;
|
var KEY_LEFT = 37;
|
||||||
var KEY_UP = 38;
|
var KEY_UP = 38;
|
||||||
var KEY_RIGHT = 39;
|
var KEY_RIGHT = 39;
|
||||||
var KEY_DOWN = 40;
|
var KEY_DOWN = 40;
|
||||||
|
|
||||||
function relativeDragStrategy($element) {
|
function relativeDragStrategy($element) {
|
||||||
var $parent = $element.parent();
|
var $parent = $element.parent();
|
||||||
var delta;
|
var delta;
|
||||||
var x = $element.offset().left - $parent.offset().left;
|
var x = $element.offset().left - $parent.offset().left;
|
||||||
var y = $element.offset().top - $parent.offset().top;
|
var y = $element.offset().top - $parent.offset().top;
|
||||||
|
|
||||||
var getPosition = function() {
|
var getPosition = function() {
|
||||||
return {x: x, y: y};
|
return {x: x, y: y};
|
||||||
};
|
};
|
||||||
|
|
||||||
var setPosition = function(newX, newY) {
|
var setPosition = function(newX, newY) {
|
||||||
x = newX;
|
x = newX;
|
||||||
y = newY;
|
y = newY;
|
||||||
var screenX = Math.min(Math.max(newX, 0), $parent.outerWidth() - $element.outerWidth());
|
var screenX = Math.min(Math.max(newX, 0), $parent.outerWidth() - $element.outerWidth());
|
||||||
var screenY = Math.min(Math.max(newY, 0), $parent.outerHeight() - $element.outerHeight());
|
var screenY = Math.min(Math.max(newY, 0), $parent.outerHeight() - $element.outerHeight());
|
||||||
screenX *= 100.0 / $parent.outerWidth();
|
screenX *= 100.0 / $parent.outerWidth();
|
||||||
screenY *= 100.0 / $parent.outerHeight();
|
screenY *= 100.0 / $parent.outerHeight();
|
||||||
$element.css({
|
$element.css({
|
||||||
left: screenX + '%',
|
left: screenX + '%',
|
||||||
top: screenY + '%'});
|
top: screenY + '%'});
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
mouseClicked: function(e) {
|
mouseClicked: function(e) {
|
||||||
delta = {
|
delta = {
|
||||||
x: $element.offset().left - e.clientX,
|
x: $element.offset().left - e.clientX,
|
||||||
y: $element.offset().top - e.clientY,
|
y: $element.offset().top - e.clientY,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
mouseMoved: function(e) {
|
mouseMoved: function(e) {
|
||||||
setPosition(
|
setPosition(
|
||||||
e.clientX + delta.x - $parent.offset().left,
|
e.clientX + delta.x - $parent.offset().left,
|
||||||
e.clientY + delta.y - $parent.offset().top);
|
e.clientY + delta.y - $parent.offset().top);
|
||||||
},
|
},
|
||||||
|
|
||||||
getPosition: getPosition,
|
getPosition: getPosition,
|
||||||
setPosition: setPosition,
|
setPosition: setPosition,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function absoluteDragStrategy($element) {
|
function absoluteDragStrategy($element) {
|
||||||
var delta;
|
var delta;
|
||||||
var x = $element.offset().left;
|
var x = $element.offset().left;
|
||||||
var y = $element.offset().top;
|
var y = $element.offset().top;
|
||||||
|
|
||||||
var getPosition = function() {
|
var getPosition = function() {
|
||||||
return {x: x, y: y};
|
return {x: x, y: y};
|
||||||
};
|
};
|
||||||
|
|
||||||
var setPosition = function(newX, newY) {
|
var setPosition = function(newX, newY) {
|
||||||
x = newX;
|
x = newX;
|
||||||
y = newY;
|
y = newY;
|
||||||
$element.css({
|
$element.css({
|
||||||
left: x + 'px',
|
left: x + 'px',
|
||||||
top: y + 'px'});
|
top: y + 'px'});
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
mouseClicked: function(e) {
|
mouseClicked: function(e) {
|
||||||
delta = {
|
delta = {
|
||||||
x: $element.position().left - e.clientX,
|
x: $element.position().left - e.clientX,
|
||||||
y: $element.position().top - e.clientY,
|
y: $element.position().top - e.clientY,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
mouseMoved: function(e) {
|
mouseMoved: function(e) {
|
||||||
setPosition(e.clientX + delta.x, e.clientY + delta.y);
|
setPosition(e.clientX + delta.x, e.clientY + delta.y);
|
||||||
},
|
},
|
||||||
|
|
||||||
getPosition: getPosition,
|
getPosition: getPosition,
|
||||||
setPosition: setPosition,
|
setPosition: setPosition,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeDraggable($element, dragStrategy, enableHotkeys) {
|
function makeDraggable($element, dragStrategy, enableHotkeys) {
|
||||||
var strategy = dragStrategy($element);
|
var strategy = dragStrategy($element);
|
||||||
$element.data('drag-strategy', strategy);
|
$element.data('drag-strategy', strategy);
|
||||||
|
|
||||||
$element.addClass('draggable');
|
$element.addClass('draggable');
|
||||||
|
|
||||||
$element.mousedown(function(e) {
|
$element.mousedown(function(e) {
|
||||||
if (e.target !== $element.get(0)) {
|
if (e.target !== $element.get(0)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
$element.focus();
|
$element.focus();
|
||||||
$element.addClass('dragging');
|
$element.addClass('dragging');
|
||||||
|
|
||||||
strategy.mouseClicked(e);
|
strategy.mouseClicked(e);
|
||||||
jQuery(window).bind('mousemove.elemmove', function(e) {
|
jQuery(window).bind('mousemove.elemmove', function(e) {
|
||||||
strategy.mouseMoved(e);
|
strategy.mouseMoved(e);
|
||||||
}).bind('mouseup.elemmove', function(e) {
|
}).bind('mouseup.elemmove', function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
strategy.mouseMoved(e);
|
strategy.mouseMoved(e);
|
||||||
$element.removeClass('dragging');
|
$element.removeClass('dragging');
|
||||||
jQuery(window).unbind('mousemove.elemmove');
|
jQuery(window).unbind('mousemove.elemmove');
|
||||||
jQuery(window).unbind('mouseup.elemmove');
|
jQuery(window).unbind('mouseup.elemmove');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
if (enableHotkeys) {
|
if (enableHotkeys) {
|
||||||
$element.keydown(function(e) {
|
$element.keydown(function(e) {
|
||||||
var position = strategy.getPosition();
|
var position = strategy.getPosition();
|
||||||
var oldPosition = {x: position.x, y: position.y};
|
var oldPosition = {x: position.x, y: position.y};
|
||||||
if (e.shiftKey) {
|
if (e.shiftKey) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var delta = e.ctrlKey ? 10 : 1;
|
var delta = e.ctrlKey ? 10 : 1;
|
||||||
if (e.which === KEY_LEFT) {
|
if (e.which === KEY_LEFT) {
|
||||||
position.x -= delta;
|
position.x -= delta;
|
||||||
} else if (e.which === KEY_RIGHT) {
|
} else if (e.which === KEY_RIGHT) {
|
||||||
position.x += delta;
|
position.x += delta;
|
||||||
} else if (e.which === KEY_UP) {
|
} else if (e.which === KEY_UP) {
|
||||||
position.y -= delta;
|
position.y -= delta;
|
||||||
} else if (e.which === KEY_DOWN) {
|
} else if (e.which === KEY_DOWN) {
|
||||||
position.y += delta;
|
position.y += delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (position.x !== oldPosition.x || position.y !== oldPosition.y) {
|
if (position.x !== oldPosition.x || position.y !== oldPosition.y) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.stopImmediatePropagation();
|
e.stopImmediatePropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
strategy.setPosition(position.x, position.y);
|
strategy.setPosition(position.x, position.y);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
makeDraggable: makeDraggable,
|
makeDraggable: makeDraggable,
|
||||||
absoluteDragStrategy: absoluteDragStrategy,
|
absoluteDragStrategy: absoluteDragStrategy,
|
||||||
relativeDragStrategy: relativeDragStrategy,
|
relativeDragStrategy: relativeDragStrategy,
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -3,265 +3,265 @@ App.Util = App.Util || {};
|
||||||
|
|
||||||
App.Util.Misc = function(_, jQuery, marked, promise) {
|
App.Util.Misc = function(_, jQuery, marked, promise) {
|
||||||
|
|
||||||
var exitConfirmationEnabled = false;
|
var exitConfirmationEnabled = false;
|
||||||
|
|
||||||
function transparentPixel() {
|
function transparentPixel() {
|
||||||
return 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
|
return 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
|
||||||
}
|
}
|
||||||
|
|
||||||
function enableExitConfirmation() {
|
function enableExitConfirmation() {
|
||||||
exitConfirmationEnabled = true;
|
exitConfirmationEnabled = true;
|
||||||
jQuery(window).bind('beforeunload', function(e) {
|
jQuery(window).bind('beforeunload', function(e) {
|
||||||
return 'There are unsaved changes.';
|
return 'There are unsaved changes.';
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function disableExitConfirmation() {
|
function disableExitConfirmation() {
|
||||||
exitConfirmationEnabled = false;
|
exitConfirmationEnabled = false;
|
||||||
jQuery(window).unbind('beforeunload');
|
jQuery(window).unbind('beforeunload');
|
||||||
}
|
}
|
||||||
|
|
||||||
function isExitConfirmationEnabled() {
|
function isExitConfirmationEnabled() {
|
||||||
return exitConfirmationEnabled;
|
return exitConfirmationEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadImagesNicely($img) {
|
function loadImagesNicely($img) {
|
||||||
if (!$img.get(0).complete) {
|
if (!$img.get(0).complete) {
|
||||||
$img.addClass('loading');
|
$img.addClass('loading');
|
||||||
$img.css({opacity: 0});
|
$img.css({opacity: 0});
|
||||||
var $div = jQuery('<div>Loading ' + $img.attr('alt') + '…</div>');
|
var $div = jQuery('<div>Loading ' + $img.attr('alt') + '…</div>');
|
||||||
var width = $img.width();
|
var width = $img.width();
|
||||||
var height = $img.height();
|
var height = $img.height();
|
||||||
if (width > 50 && height > 50) {
|
if (width > 50 && height > 50) {
|
||||||
$div.css({
|
$div.css({
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
width: width + 'px',
|
width: width + 'px',
|
||||||
height: height + 'px',
|
height: height + 'px',
|
||||||
color: 'rgba(0, 0, 0, 0.15)',
|
color: 'rgba(0, 0, 0, 0.15)',
|
||||||
zIndex: -1,
|
zIndex: -1,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
textAlign: 'center'});
|
textAlign: 'center'});
|
||||||
$div.insertBefore($img);
|
$div.insertBefore($img);
|
||||||
$div.offset($img.offset());
|
$div.offset($img.offset());
|
||||||
}
|
}
|
||||||
$img.bind('load', function() {
|
$img.bind('load', function() {
|
||||||
$img.animate({opacity: 1}, 'fast');
|
$img.animate({opacity: 1}, 'fast');
|
||||||
$img.removeClass('loading');
|
$img.removeClass('loading');
|
||||||
$div.fadeOut($div.remove);
|
$div.fadeOut($div.remove);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function promiseTemplate(templateName) {
|
function promiseTemplate(templateName) {
|
||||||
return promiseTemplateFromDOM(templateName) ||
|
return promiseTemplateFromDOM(templateName) ||
|
||||||
promiseTemplateWithAJAX(templateName);
|
promiseTemplateWithAJAX(templateName);
|
||||||
}
|
}
|
||||||
|
|
||||||
function promiseTemplateFromDOM(templateName) {
|
function promiseTemplateFromDOM(templateName) {
|
||||||
var $template = jQuery('#' + templateName + '-template');
|
var $template = jQuery('#' + templateName + '-template');
|
||||||
if ($template.length) {
|
if ($template.length) {
|
||||||
return promise.make(function(resolve, reject) {
|
return promise.make(function(resolve, reject) {
|
||||||
resolve(_.template($template.html()));
|
resolve(_.template($template.html()));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function promiseTemplateWithAJAX(templateName) {
|
function promiseTemplateWithAJAX(templateName) {
|
||||||
return promise.make(function(resolve, reject) {
|
return promise.make(function(resolve, reject) {
|
||||||
var templatesDir = '/templates';
|
var templatesDir = '/templates';
|
||||||
var templateUrl = templatesDir + '/' + templateName + '.tpl';
|
var templateUrl = templatesDir + '/' + templateName + '.tpl';
|
||||||
|
|
||||||
jQuery.ajax({
|
jQuery.ajax({
|
||||||
url: templateUrl,
|
url: templateUrl,
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
success: function(data, textStatus, xhr) {
|
success: function(data, textStatus, xhr) {
|
||||||
resolve(_.template(data));
|
resolve(_.template(data));
|
||||||
},
|
},
|
||||||
error: function(xhr, textStatus, errorThrown) {
|
error: function(xhr, textStatus, errorThrown) {
|
||||||
console.log(new Error('Error while loading template ' + templateName + ': ' + errorThrown));
|
console.log(new Error('Error while loading template ' + templateName + ': ' + errorThrown));
|
||||||
reject();
|
reject();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatRelativeTime(timeString) {
|
function formatRelativeTime(timeString) {
|
||||||
if (!timeString) {
|
if (!timeString) {
|
||||||
return 'never';
|
return 'never';
|
||||||
}
|
}
|
||||||
|
|
||||||
var then = Date.parse(timeString);
|
var then = Date.parse(timeString);
|
||||||
var now = Date.now();
|
var now = Date.now();
|
||||||
var difference = Math.abs(now - then);
|
var difference = Math.abs(now - then);
|
||||||
var future = now < then;
|
var future = now < then;
|
||||||
|
|
||||||
var text = (function(difference) {
|
var text = (function(difference) {
|
||||||
var mul = 1000;
|
var mul = 1000;
|
||||||
var prevMul;
|
var prevMul;
|
||||||
|
|
||||||
mul *= 60;
|
mul *= 60;
|
||||||
if (difference < mul) {
|
if (difference < mul) {
|
||||||
return 'a few seconds';
|
return 'a few seconds';
|
||||||
} else if (difference < mul * 2) {
|
} else if (difference < mul * 2) {
|
||||||
return 'a minute';
|
return 'a minute';
|
||||||
}
|
}
|
||||||
|
|
||||||
prevMul = mul; mul *= 60;
|
prevMul = mul; mul *= 60;
|
||||||
if (difference < mul) {
|
if (difference < mul) {
|
||||||
return Math.round(difference / prevMul) + ' minutes';
|
return Math.round(difference / prevMul) + ' minutes';
|
||||||
} else if (difference < mul * 2) {
|
} else if (difference < mul * 2) {
|
||||||
return 'an hour';
|
return 'an hour';
|
||||||
}
|
}
|
||||||
|
|
||||||
prevMul = mul; mul *= 24;
|
prevMul = mul; mul *= 24;
|
||||||
if (difference < mul) {
|
if (difference < mul) {
|
||||||
return Math.round(difference / prevMul) + ' hours';
|
return Math.round(difference / prevMul) + ' hours';
|
||||||
} else if (difference < mul * 2) {
|
} else if (difference < mul * 2) {
|
||||||
return 'a day';
|
return 'a day';
|
||||||
}
|
}
|
||||||
|
|
||||||
prevMul = mul; mul *= 30.42;
|
prevMul = mul; mul *= 30.42;
|
||||||
if (difference < mul) {
|
if (difference < mul) {
|
||||||
return Math.round(difference / prevMul) + ' days';
|
return Math.round(difference / prevMul) + ' days';
|
||||||
} else if (difference < mul * 2) {
|
} else if (difference < mul * 2) {
|
||||||
return 'a month';
|
return 'a month';
|
||||||
}
|
}
|
||||||
|
|
||||||
prevMul = mul; mul *= 12;
|
prevMul = mul; mul *= 12;
|
||||||
if (difference < mul) {
|
if (difference < mul) {
|
||||||
return Math.round(difference / prevMul) + ' months';
|
return Math.round(difference / prevMul) + ' months';
|
||||||
} else if (difference < mul * 2) {
|
} else if (difference < mul * 2) {
|
||||||
return 'a year';
|
return 'a year';
|
||||||
}
|
}
|
||||||
|
|
||||||
return Math.round(difference / mul) + ' years';
|
return Math.round(difference / mul) + ' years';
|
||||||
})(difference);
|
})(difference);
|
||||||
|
|
||||||
if (text === 'a day') {
|
if (text === 'a day') {
|
||||||
return future ? 'tomorrow' : 'yesterday';
|
return future ? 'tomorrow' : 'yesterday';
|
||||||
}
|
}
|
||||||
return future ? 'in ' + text : text + ' ago';
|
return future ? 'in ' + text : text + ' ago';
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatAbsoluteTime(timeString) {
|
function formatAbsoluteTime(timeString) {
|
||||||
var time = new Date(Date.parse(timeString));
|
var time = new Date(Date.parse(timeString));
|
||||||
return time.toString();
|
return time.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatUnits(number, base, suffixes, callback) {
|
function formatUnits(number, base, suffixes, callback) {
|
||||||
if (!number && number !== 0) {
|
if (!number && number !== 0) {
|
||||||
return NaN;
|
return NaN;
|
||||||
}
|
}
|
||||||
number *= 1.0;
|
number *= 1.0;
|
||||||
|
|
||||||
var suffix = suffixes.shift();
|
var suffix = suffixes.shift();
|
||||||
while (number >= base && suffixes.length > 0) {
|
while (number >= base && suffixes.length > 0) {
|
||||||
suffix = suffixes.shift();
|
suffix = suffixes.shift();
|
||||||
number /= base;
|
number /= base;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof(callback) === 'undefined') {
|
if (typeof(callback) === 'undefined') {
|
||||||
callback = function(number, suffix) {
|
callback = function(number, suffix) {
|
||||||
return suffix ? number.toFixed(1) + suffix : number;
|
return suffix ? number.toFixed(1) + suffix : number;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return callback(number, suffix);
|
return callback(number, suffix);
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatFileSize(fileSize) {
|
function formatFileSize(fileSize) {
|
||||||
return formatUnits(
|
return formatUnits(
|
||||||
fileSize,
|
fileSize,
|
||||||
1024,
|
1024,
|
||||||
['B', 'K', 'M', 'G'],
|
['B', 'K', 'M', 'G'],
|
||||||
function(number, suffix) {
|
function(number, suffix) {
|
||||||
var decimalPlaces = number < 20 && suffix !== 'B' ? 1 : 0;
|
var decimalPlaces = number < 20 && suffix !== 'B' ? 1 : 0;
|
||||||
return number.toFixed(decimalPlaces) + suffix;
|
return number.toFixed(decimalPlaces) + suffix;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatMarkdown(text) {
|
function formatMarkdown(text) {
|
||||||
var renderer = new marked.Renderer();
|
var renderer = new marked.Renderer();
|
||||||
|
|
||||||
var options = {
|
var options = {
|
||||||
renderer: renderer,
|
renderer: renderer,
|
||||||
breaks: true,
|
breaks: true,
|
||||||
sanitize: true,
|
sanitize: true,
|
||||||
smartypants: true,
|
smartypants: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
var preDecorator = function(text) {
|
var preDecorator = function(text) {
|
||||||
//prevent ^#... from being treated as headers, due to tag permalinks
|
//prevent ^#... from being treated as headers, due to tag permalinks
|
||||||
text = text.replace(/^#/g, '%%%#');
|
text = text.replace(/^#/g, '%%%#');
|
||||||
//fix \ before ~ being stripped away
|
//fix \ before ~ being stripped away
|
||||||
text = text.replace(/\\~/g, '%%%T');
|
text = text.replace(/\\~/g, '%%%T');
|
||||||
return text;
|
return text;
|
||||||
};
|
};
|
||||||
|
|
||||||
var postDecorator = function(text) {
|
var postDecorator = function(text) {
|
||||||
//restore fixes
|
//restore fixes
|
||||||
text = text.replace(/%%%T/g, '\\~');
|
text = text.replace(/%%%T/g, '\\~');
|
||||||
text = text.replace(/%%%#/g, '#');
|
text = text.replace(/%%%#/g, '#');
|
||||||
|
|
||||||
//search permalinks
|
//search permalinks
|
||||||
text = text.replace(/\[search\]((?:[^\[]|\[(?!\/?search\]))+)\[\/search\]/ig, '<a href="#/posts/query=$1"><code>$1</code></a>');
|
text = text.replace(/\[search\]((?:[^\[]|\[(?!\/?search\]))+)\[\/search\]/ig, '<a href="#/posts/query=$1"><code>$1</code></a>');
|
||||||
//spoilers
|
//spoilers
|
||||||
text = text.replace(/\[spoiler\]((?:[^\[]|\[(?!\/?spoiler\]))+)\[\/spoiler\]/ig, '<span class="spoiler">$1</span>');
|
text = text.replace(/\[spoiler\]((?:[^\[]|\[(?!\/?spoiler\]))+)\[\/spoiler\]/ig, '<span class="spoiler">$1</span>');
|
||||||
//[small]
|
//[small]
|
||||||
text = text.replace(/\[small\]((?:[^\[]|\[(?!\/?small\]))+)\[\/small\]/ig, '<small>$1</small>');
|
text = text.replace(/\[small\]((?:[^\[]|\[(?!\/?small\]))+)\[\/small\]/ig, '<small>$1</small>');
|
||||||
//strike-through
|
//strike-through
|
||||||
text = text.replace(/(^|[^\\])(~~|~)([^~]+)\2/g, '$1<del>$3</del>');
|
text = text.replace(/(^|[^\\])(~~|~)([^~]+)\2/g, '$1<del>$3</del>');
|
||||||
text = text.replace(/\\~/g, '~');
|
text = text.replace(/\\~/g, '~');
|
||||||
//post premalinks
|
//post premalinks
|
||||||
text = text.replace(/(^|[\s<>\(\)\[\]])@(\d+)/g, '$1<a href="#/post/$2"><code>@$2</code></a>');
|
text = text.replace(/(^|[\s<>\(\)\[\]])@(\d+)/g, '$1<a href="#/post/$2"><code>@$2</code></a>');
|
||||||
//user permalinks
|
//user permalinks
|
||||||
text = text.replace(/(^|[\s<>\(\)\[\]])\+([a-zA-Z0-9_-]+)/g, '$1<a href="#/user/$2"><code>+$2</code></a>');
|
text = text.replace(/(^|[\s<>\(\)\[\]])\+([a-zA-Z0-9_-]+)/g, '$1<a href="#/user/$2"><code>+$2</code></a>');
|
||||||
//tag permalinks
|
//tag permalinks
|
||||||
text = text.replace(/(^|[\s<>\(\)\[\]])\#([^\s<>/\\]+)/g, '$1<a href="#/posts/query=$2"><code>#$2</code></a>');
|
text = text.replace(/(^|[\s<>\(\)\[\]])\#([^\s<>/\\]+)/g, '$1<a href="#/posts/query=$2"><code>#$2</code></a>');
|
||||||
return text;
|
return text;
|
||||||
};
|
};
|
||||||
|
|
||||||
return postDecorator(marked(preDecorator(text), options));
|
return postDecorator(marked(preDecorator(text), options));
|
||||||
}
|
}
|
||||||
|
|
||||||
function appendComplexRouteParam(baseUri, params) {
|
function appendComplexRouteParam(baseUri, params) {
|
||||||
var result = baseUri + '/';
|
var result = baseUri + '/';
|
||||||
_.each(params, function(v, k) {
|
_.each(params, function(v, k) {
|
||||||
if (typeof(v) !== 'undefined') {
|
if (typeof(v) !== 'undefined') {
|
||||||
result += k + '=' + v + ';';
|
result += k + '=' + v + ';';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return result.slice(0, -1);
|
return result.slice(0, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
function simplifySearchQuery(query) {
|
function simplifySearchQuery(query) {
|
||||||
if (typeof(query) === 'undefined') {
|
if (typeof(query) === 'undefined') {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
if (query.page === 1) {
|
if (query.page === 1) {
|
||||||
delete query.page;
|
delete query.page;
|
||||||
}
|
}
|
||||||
query = _.pick(query, _.identity); //remove falsy values
|
query = _.pick(query, _.identity); //remove falsy values
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
promiseTemplate: promiseTemplate,
|
promiseTemplate: promiseTemplate,
|
||||||
formatRelativeTime: formatRelativeTime,
|
formatRelativeTime: formatRelativeTime,
|
||||||
formatAbsoluteTime: formatAbsoluteTime,
|
formatAbsoluteTime: formatAbsoluteTime,
|
||||||
formatFileSize: formatFileSize,
|
formatFileSize: formatFileSize,
|
||||||
formatMarkdown: formatMarkdown,
|
formatMarkdown: formatMarkdown,
|
||||||
enableExitConfirmation: enableExitConfirmation,
|
enableExitConfirmation: enableExitConfirmation,
|
||||||
disableExitConfirmation: disableExitConfirmation,
|
disableExitConfirmation: disableExitConfirmation,
|
||||||
isExitConfirmationEnabled: isExitConfirmationEnabled,
|
isExitConfirmationEnabled: isExitConfirmationEnabled,
|
||||||
transparentPixel: transparentPixel,
|
transparentPixel: transparentPixel,
|
||||||
loadImagesNicely: loadImagesNicely,
|
loadImagesNicely: loadImagesNicely,
|
||||||
appendComplexRouteParam: appendComplexRouteParam,
|
appendComplexRouteParam: appendComplexRouteParam,
|
||||||
simplifySearchQuery: simplifySearchQuery,
|
simplifySearchQuery: simplifySearchQuery,
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,108 +2,108 @@ var App = App || {};
|
||||||
App.Util = App.Util || {};
|
App.Util = App.Util || {};
|
||||||
|
|
||||||
App.Util.Resizable = function(jQuery) {
|
App.Util.Resizable = function(jQuery) {
|
||||||
var KEY_LEFT = 37;
|
var KEY_LEFT = 37;
|
||||||
var KEY_UP = 38;
|
var KEY_UP = 38;
|
||||||
var KEY_RIGHT = 39;
|
var KEY_RIGHT = 39;
|
||||||
var KEY_DOWN = 40;
|
var KEY_DOWN = 40;
|
||||||
|
|
||||||
function relativeResizeStrategy($element) {
|
function relativeResizeStrategy($element) {
|
||||||
var $parent = $element.parent();
|
var $parent = $element.parent();
|
||||||
var delta;
|
var delta;
|
||||||
var width = $element.width();
|
var width = $element.width();
|
||||||
var height = $element.height();
|
var height = $element.height();
|
||||||
|
|
||||||
var getSize = function() {
|
var getSize = function() {
|
||||||
return {width: width, height: height};
|
return {width: width, height: height};
|
||||||
};
|
};
|
||||||
|
|
||||||
var setSize = function(newWidth, newHeight) {
|
var setSize = function(newWidth, newHeight) {
|
||||||
width = newWidth;
|
width = newWidth;
|
||||||
height = newHeight;
|
height = newHeight;
|
||||||
var screenWidth = Math.min(Math.max(width, 20), $parent.outerWidth() + $parent.offset().left - $element.offset().left);
|
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);
|
var screenHeight = Math.min(Math.max(height, 20), $parent.outerHeight() + $parent.offset().top - $element.offset().top);
|
||||||
screenWidth *= 100.0 / $parent.outerWidth();
|
screenWidth *= 100.0 / $parent.outerWidth();
|
||||||
screenHeight *= 100.0 / $parent.outerHeight();
|
screenHeight *= 100.0 / $parent.outerHeight();
|
||||||
$element.css({
|
$element.css({
|
||||||
width: screenWidth + '%',
|
width: screenWidth + '%',
|
||||||
height: screenHeight + '%'});
|
height: screenHeight + '%'});
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
mouseClicked: function(e) {
|
mouseClicked: function(e) {
|
||||||
delta = {
|
delta = {
|
||||||
x: $element.width() - e.clientX,
|
x: $element.width() - e.clientX,
|
||||||
y: $element.height() - e.clientY,
|
y: $element.height() - e.clientY,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
mouseMoved: function(e) {
|
mouseMoved: function(e) {
|
||||||
setSize(
|
setSize(
|
||||||
e.clientX + delta.x,
|
e.clientX + delta.x,
|
||||||
e.clientY + delta.y);
|
e.clientY + delta.y);
|
||||||
},
|
},
|
||||||
|
|
||||||
getSize: getSize,
|
getSize: getSize,
|
||||||
setSize: setSize,
|
setSize: setSize,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeResizable($element, enableHotkeys) {
|
function makeResizable($element, enableHotkeys) {
|
||||||
var $resizer = jQuery('<div class="resizer"></div>');
|
var $resizer = jQuery('<div class="resizer"></div>');
|
||||||
var strategy = relativeResizeStrategy($element);
|
var strategy = relativeResizeStrategy($element);
|
||||||
$element.append($resizer);
|
$element.append($resizer);
|
||||||
|
|
||||||
$resizer.mousedown(function(e) {
|
$resizer.mousedown(function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
$element.focus();
|
$element.focus();
|
||||||
$element.addClass('resizing');
|
$element.addClass('resizing');
|
||||||
|
|
||||||
strategy.mouseClicked(e);
|
strategy.mouseClicked(e);
|
||||||
|
|
||||||
jQuery(window).bind('mousemove.elemsize', function(e) {
|
jQuery(window).bind('mousemove.elemsize', function(e) {
|
||||||
strategy.mouseMoved(e);
|
strategy.mouseMoved(e);
|
||||||
}).bind('mouseup.elemsize', function(e) {
|
}).bind('mouseup.elemsize', function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
strategy.mouseMoved(e);
|
strategy.mouseMoved(e);
|
||||||
$element.removeClass('resizing');
|
$element.removeClass('resizing');
|
||||||
jQuery(window).unbind('mousemove.elemsize');
|
jQuery(window).unbind('mousemove.elemsize');
|
||||||
jQuery(window).unbind('mouseup.elemsize');
|
jQuery(window).unbind('mouseup.elemsize');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
if (enableHotkeys) {
|
if (enableHotkeys) {
|
||||||
$element.keydown(function(e) {
|
$element.keydown(function(e) {
|
||||||
var size = strategy.getSize();
|
var size = strategy.getSize();
|
||||||
var oldSize = {width: size.width, height: size.height};
|
var oldSize = {width: size.width, height: size.height};
|
||||||
if (!e.shiftKey) {
|
if (!e.shiftKey) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var delta = e.ctrlKey ? 10 : 1;
|
var delta = e.ctrlKey ? 10 : 1;
|
||||||
if (e.which === KEY_LEFT) {
|
if (e.which === KEY_LEFT) {
|
||||||
size.width -= delta;
|
size.width -= delta;
|
||||||
} else if (e.which === KEY_RIGHT) {
|
} else if (e.which === KEY_RIGHT) {
|
||||||
size.width += delta;
|
size.width += delta;
|
||||||
} else if (e.which === KEY_UP) {
|
} else if (e.which === KEY_UP) {
|
||||||
size.height -= delta;
|
size.height -= delta;
|
||||||
} else if (e.which === KEY_DOWN) {
|
} else if (e.which === KEY_DOWN) {
|
||||||
size.height += delta;
|
size.height += delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size.width !== oldSize.width || size.height !== oldSize.height) {
|
if (size.width !== oldSize.width || size.height !== oldSize.height) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.stopImmediatePropagation();
|
e.stopImmediatePropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
strategy.setSize(size.width, size.height);
|
strategy.setSize(size.width, size.height);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
makeResizable: makeResizable,
|
makeResizable: makeResizable,
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,42 +5,42 @@ $startTime = microtime(true);
|
||||||
|
|
||||||
final class Bootstrap
|
final class Bootstrap
|
||||||
{
|
{
|
||||||
private static $startTime;
|
private static $startTime;
|
||||||
|
|
||||||
public static function init($startTime)
|
public static function init($startTime)
|
||||||
{
|
{
|
||||||
self::$startTime = $startTime;
|
self::$startTime = $startTime;
|
||||||
self::setTimezone();
|
self::setTimezone();
|
||||||
self::turnErrorsIntoExceptions();
|
self::turnErrorsIntoExceptions();
|
||||||
self::initAutoloader();
|
self::initAutoloader();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getStartTime()
|
public static function getStartTime()
|
||||||
{
|
{
|
||||||
return self::$startTime;
|
return self::$startTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function setTimezone()
|
private static function setTimezone()
|
||||||
{
|
{
|
||||||
date_default_timezone_set('UTC');
|
date_default_timezone_set('UTC');
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function initAutoloader()
|
private static function initAutoloader()
|
||||||
{
|
{
|
||||||
require(__DIR__
|
require(__DIR__
|
||||||
. DIRECTORY_SEPARATOR . '..'
|
. DIRECTORY_SEPARATOR . '..'
|
||||||
. DIRECTORY_SEPARATOR . 'vendor'
|
. DIRECTORY_SEPARATOR . 'vendor'
|
||||||
. DIRECTORY_SEPARATOR . 'autoload.php');
|
. DIRECTORY_SEPARATOR . 'autoload.php');
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function turnErrorsIntoExceptions()
|
private static function turnErrorsIntoExceptions()
|
||||||
{
|
{
|
||||||
set_error_handler(
|
set_error_handler(
|
||||||
function($errno, $errstr, $errfile, $errline, array $errcontext)
|
function($errno, $errstr, $errfile, $errline, array $errcontext)
|
||||||
{
|
{
|
||||||
throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
|
throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Bootstrap::init($startTime);
|
Bootstrap::init($startTime);
|
||||||
|
|
126
src/Config.php
126
src/Config.php
|
@ -3,79 +3,79 @@ namespace Szurubooru;
|
||||||
|
|
||||||
class Config extends \ArrayObject
|
class Config extends \ArrayObject
|
||||||
{
|
{
|
||||||
private $dataDirectory;
|
private $dataDirectory;
|
||||||
private $publicDataDirectory;
|
private $publicDataDirectory;
|
||||||
|
|
||||||
public function __construct($dataDirectory, $publicDataDirectory)
|
public function __construct($dataDirectory, $publicDataDirectory)
|
||||||
{
|
{
|
||||||
$this->setFlags($this->getArrayObjectFlags());
|
$this->setFlags($this->getArrayObjectFlags());
|
||||||
$this->dataDirectory = $dataDirectory;
|
$this->dataDirectory = $dataDirectory;
|
||||||
$this->publicDataDirectory = $publicDataDirectory;
|
$this->publicDataDirectory = $publicDataDirectory;
|
||||||
$this->tryLoadFromIni([
|
$this->tryLoadFromIni([
|
||||||
$dataDirectory . DIRECTORY_SEPARATOR . 'config.ini',
|
$dataDirectory . DIRECTORY_SEPARATOR . 'config.ini',
|
||||||
$dataDirectory . DIRECTORY_SEPARATOR . 'local.ini']);
|
$dataDirectory . DIRECTORY_SEPARATOR . 'local.ini']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function tryLoadFromIni($configPaths)
|
public function tryLoadFromIni($configPaths)
|
||||||
{
|
{
|
||||||
if (!is_array($configPaths))
|
if (!is_array($configPaths))
|
||||||
$configPaths = [$configPaths];
|
$configPaths = [$configPaths];
|
||||||
|
|
||||||
foreach ($configPaths as $configPath)
|
foreach ($configPaths as $configPath)
|
||||||
{
|
{
|
||||||
if (file_exists($configPath))
|
if (file_exists($configPath))
|
||||||
$this->loadFromIni($configPath);
|
$this->loadFromIni($configPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDataDirectory()
|
public function getDataDirectory()
|
||||||
{
|
{
|
||||||
return $this->dataDirectory;
|
return $this->dataDirectory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPublicDataDirectory()
|
public function getPublicDataDirectory()
|
||||||
{
|
{
|
||||||
return $this->publicDataDirectory;
|
return $this->publicDataDirectory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function offsetGet($index)
|
public function offsetGet($index)
|
||||||
{
|
{
|
||||||
if (!parent::offsetExists($index))
|
if (!parent::offsetExists($index))
|
||||||
return null;
|
return null;
|
||||||
return parent::offsetGet($index);
|
return parent::offsetGet($index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function loadFromIni($configPath)
|
public function loadFromIni($configPath)
|
||||||
{
|
{
|
||||||
$array = parse_ini_file($configPath, true, INI_SCANNER_RAW);
|
$array = parse_ini_file($configPath, true, INI_SCANNER_RAW);
|
||||||
|
|
||||||
foreach ($array as $key => $value)
|
foreach ($array as $key => $value)
|
||||||
{
|
{
|
||||||
if (!is_array($value))
|
if (!is_array($value))
|
||||||
{
|
{
|
||||||
$this->offsetSet($key, $value);
|
$this->offsetSet($key, $value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$section = $key;
|
$section = $key;
|
||||||
$ptr = $this;
|
$ptr = $this;
|
||||||
|
|
||||||
foreach (explode('.', $section) as $subSection)
|
foreach (explode('.', $section) as $subSection)
|
||||||
{
|
{
|
||||||
if (!$ptr->offsetExists($subSection))
|
if (!$ptr->offsetExists($subSection))
|
||||||
$ptr->offsetSet($subSection, new \ArrayObject([], $this->getArrayObjectFlags()));
|
$ptr->offsetSet($subSection, new \ArrayObject([], $this->getArrayObjectFlags()));
|
||||||
|
|
||||||
$ptr = $ptr->$subSection;
|
$ptr = $ptr->$subSection;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($value as $sectionKey => $sectionValue)
|
foreach ($value as $sectionKey => $sectionValue)
|
||||||
$ptr->offsetSet($sectionKey, $sectionValue);
|
$ptr->offsetSet($sectionKey, $sectionValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getArrayObjectFlags()
|
private function getArrayObjectFlags()
|
||||||
{
|
{
|
||||||
return parent::ARRAY_AS_PROPS | parent::STD_PROP_LIST;
|
return parent::ARRAY_AS_PROPS | parent::STD_PROP_LIST;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,300 +12,300 @@ use Szurubooru\Search\Result;
|
||||||
|
|
||||||
abstract class AbstractDao implements ICrudDao, IBatchDao
|
abstract class AbstractDao implements ICrudDao, IBatchDao
|
||||||
{
|
{
|
||||||
protected $pdo;
|
protected $pdo;
|
||||||
protected $tableName;
|
protected $tableName;
|
||||||
protected $entityConverter;
|
protected $entityConverter;
|
||||||
protected $driver;
|
protected $driver;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
DatabaseConnection $databaseConnection,
|
DatabaseConnection $databaseConnection,
|
||||||
$tableName,
|
$tableName,
|
||||||
IEntityConverter $entityConverter)
|
IEntityConverter $entityConverter)
|
||||||
{
|
{
|
||||||
$this->setDatabaseConnection($databaseConnection);
|
$this->setDatabaseConnection($databaseConnection);
|
||||||
$this->tableName = $tableName;
|
$this->tableName = $tableName;
|
||||||
$this->entityConverter = $entityConverter;
|
$this->entityConverter = $entityConverter;
|
||||||
$this->entityConverter->setEntityDecorator(function($entity)
|
$this->entityConverter->setEntityDecorator(function($entity)
|
||||||
{
|
{
|
||||||
$this->afterLoad($entity);
|
$this->afterLoad($entity);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTableName()
|
public function getTableName()
|
||||||
{
|
{
|
||||||
return $this->tableName;
|
return $this->tableName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getEntityConverter()
|
public function getEntityConverter()
|
||||||
{
|
{
|
||||||
return $this->entityConverter;
|
return $this->entityConverter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function save(&$entity)
|
public function save(&$entity)
|
||||||
{
|
{
|
||||||
$entity = $this->upsert($entity);
|
$entity = $this->upsert($entity);
|
||||||
$this->afterSave($entity);
|
$this->afterSave($entity);
|
||||||
$this->afterBatchSave([$entity]);
|
$this->afterBatchSave([$entity]);
|
||||||
return $entity;
|
return $entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function batchSave(array $entities)
|
public function batchSave(array $entities)
|
||||||
{
|
{
|
||||||
foreach ($entities as $key => $entity)
|
foreach ($entities as $key => $entity)
|
||||||
{
|
{
|
||||||
$entities[$key] = $this->upsert($entity);
|
$entities[$key] = $this->upsert($entity);
|
||||||
$this->afterSave($entity);
|
$this->afterSave($entity);
|
||||||
}
|
}
|
||||||
if (count($entities) > 0)
|
if (count($entities) > 0)
|
||||||
$this->afterBatchSave([$entity]);
|
$this->afterBatchSave([$entity]);
|
||||||
return $entities;
|
return $entities;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findAll()
|
public function findAll()
|
||||||
{
|
{
|
||||||
$query = $this->pdo->from($this->tableName);
|
$query = $this->pdo->from($this->tableName);
|
||||||
return $this->arrayToEntities($query);
|
return $this->arrayToEntities($query);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findById($entityId)
|
public function findById($entityId)
|
||||||
{
|
{
|
||||||
return $this->findOneBy($this->getIdColumn(), $entityId);
|
return $this->findOneBy($this->getIdColumn(), $entityId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findByIds($entityIds)
|
public function findByIds($entityIds)
|
||||||
{
|
{
|
||||||
return $this->findBy($this->getIdColumn(), $entityIds);
|
return $this->findBy($this->getIdColumn(), $entityIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findFiltered(IFilter $searchFilter)
|
public function findFiltered(IFilter $searchFilter)
|
||||||
{
|
{
|
||||||
$query = $this->pdo->from($this->tableName);
|
$query = $this->pdo->from($this->tableName);
|
||||||
|
|
||||||
$orderByString = self::compileOrderBy($searchFilter->getOrder());
|
$orderByString = self::compileOrderBy($searchFilter->getOrder());
|
||||||
if ($orderByString)
|
if ($orderByString)
|
||||||
$query->orderBy($orderByString);
|
$query->orderBy($orderByString);
|
||||||
|
|
||||||
$this->decorateQueryFromFilter($query, $searchFilter);
|
$this->decorateQueryFromFilter($query, $searchFilter);
|
||||||
if ($searchFilter->getPageSize() > 0)
|
if ($searchFilter->getPageSize() > 0)
|
||||||
{
|
{
|
||||||
$query->limit($searchFilter->getPageSize());
|
$query->limit($searchFilter->getPageSize());
|
||||||
$query->offset($searchFilter->getPageSize() * max(0, $searchFilter->getPageNumber() - 1));
|
$query->offset($searchFilter->getPageSize() * max(0, $searchFilter->getPageNumber() - 1));
|
||||||
}
|
}
|
||||||
$entities = $this->arrayToEntities(iterator_to_array($query));
|
$entities = $this->arrayToEntities(iterator_to_array($query));
|
||||||
|
|
||||||
$query = $this->pdo->from($this->tableName);
|
$query = $this->pdo->from($this->tableName);
|
||||||
$this->decorateQueryFromFilter($query, $searchFilter);
|
$this->decorateQueryFromFilter($query, $searchFilter);
|
||||||
$totalRecords = count($query);
|
$totalRecords = count($query);
|
||||||
|
|
||||||
$searchResult = new Result();
|
$searchResult = new Result();
|
||||||
$searchResult->setSearchFilter($searchFilter);
|
$searchResult->setSearchFilter($searchFilter);
|
||||||
$searchResult->setEntities($entities);
|
$searchResult->setEntities($entities);
|
||||||
$searchResult->setTotalRecords($totalRecords);
|
$searchResult->setTotalRecords($totalRecords);
|
||||||
$searchResult->setPageNumber($searchFilter->getPageNumber());
|
$searchResult->setPageNumber($searchFilter->getPageNumber());
|
||||||
$searchResult->setPageSize($searchFilter->getPageSize());
|
$searchResult->setPageSize($searchFilter->getPageSize());
|
||||||
return $searchResult;
|
return $searchResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function deleteAll()
|
public function deleteAll()
|
||||||
{
|
{
|
||||||
foreach ($this->findAll() as $entity)
|
foreach ($this->findAll() as $entity)
|
||||||
{
|
{
|
||||||
$this->beforeDelete($entity);
|
$this->beforeDelete($entity);
|
||||||
}
|
}
|
||||||
$this->pdo->deleteFrom($this->tableName)->execute();
|
$this->pdo->deleteFrom($this->tableName)->execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function deleteById($entityId)
|
public function deleteById($entityId)
|
||||||
{
|
{
|
||||||
return $this->deleteBy($this->getIdColumn(), $entityId);
|
return $this->deleteBy($this->getIdColumn(), $entityId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function update(Entity $entity)
|
public function update(Entity $entity)
|
||||||
{
|
{
|
||||||
$arrayEntity = $this->entityConverter->toArray($entity);
|
$arrayEntity = $this->entityConverter->toArray($entity);
|
||||||
unset($arrayEntity['id']);
|
unset($arrayEntity['id']);
|
||||||
$this->pdo->update($this->tableName)->set($arrayEntity)->where($this->getIdColumn(), $entity->getId())->execute();
|
$this->pdo->update($this->tableName)->set($arrayEntity)->where($this->getIdColumn(), $entity->getId())->execute();
|
||||||
return $entity;
|
return $entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function create(Entity $entity)
|
public function create(Entity $entity)
|
||||||
{
|
{
|
||||||
$sql = 'UPDATE sequencer SET lastUsedId = (@lastUsedId := (lastUsedId + 1)) WHERE tableName = :tableName';
|
$sql = 'UPDATE sequencer SET lastUsedId = (@lastUsedId := (lastUsedId + 1)) WHERE tableName = :tableName';
|
||||||
$query = $this->pdo->prepare($sql);
|
$query = $this->pdo->prepare($sql);
|
||||||
$query->bindValue(':tableName', $this->tableName);
|
$query->bindValue(':tableName', $this->tableName);
|
||||||
$query->execute();
|
$query->execute();
|
||||||
$lastUsedId = $this->pdo->query('SELECT @lastUsedId')->fetchColumn();
|
$lastUsedId = $this->pdo->query('SELECT @lastUsedId')->fetchColumn();
|
||||||
|
|
||||||
$entity->setId(intval($lastUsedId));
|
$entity->setId(intval($lastUsedId));
|
||||||
$arrayEntity = $this->entityConverter->toArray($entity);
|
$arrayEntity = $this->entityConverter->toArray($entity);
|
||||||
$this->pdo->insertInto($this->tableName)->values($arrayEntity)->execute();
|
$this->pdo->insertInto($this->tableName)->values($arrayEntity)->execute();
|
||||||
return $entity;
|
return $entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getIdColumn()
|
protected function getIdColumn()
|
||||||
{
|
{
|
||||||
return 'id';
|
return 'id';
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function hasAnyRecords()
|
protected function hasAnyRecords()
|
||||||
{
|
{
|
||||||
return count(iterator_to_array($this->pdo->from($this->tableName)->limit(1))) > 0;
|
return count(iterator_to_array($this->pdo->from($this->tableName)->limit(1))) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function findBy($columnName, $value)
|
protected function findBy($columnName, $value)
|
||||||
{
|
{
|
||||||
if (is_array($value) && empty($value))
|
if (is_array($value) && empty($value))
|
||||||
return [];
|
return [];
|
||||||
$query = $this->pdo->from($this->tableName)->where($columnName, $value);
|
$query = $this->pdo->from($this->tableName)->where($columnName, $value);
|
||||||
$arrayEntities = iterator_to_array($query);
|
$arrayEntities = iterator_to_array($query);
|
||||||
return $this->arrayToEntities($arrayEntities);
|
return $this->arrayToEntities($arrayEntities);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function findOneBy($columnName, $value)
|
protected function findOneBy($columnName, $value)
|
||||||
{
|
{
|
||||||
$entities = $this->findBy($columnName, $value);
|
$entities = $this->findBy($columnName, $value);
|
||||||
if (!$entities)
|
if (!$entities)
|
||||||
return null;
|
return null;
|
||||||
return array_shift($entities);
|
return array_shift($entities);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function deleteBy($columnName, $value)
|
protected function deleteBy($columnName, $value)
|
||||||
{
|
{
|
||||||
foreach ($this->findBy($columnName, $value) as $entity)
|
foreach ($this->findBy($columnName, $value) as $entity)
|
||||||
{
|
{
|
||||||
$this->beforeDelete($entity);
|
$this->beforeDelete($entity);
|
||||||
}
|
}
|
||||||
$this->pdo->deleteFrom($this->tableName)->where($columnName, $value)->execute();
|
$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)
|
protected function decorateQueryFromRequirement($query, Requirement $requirement)
|
||||||
{
|
{
|
||||||
$value = $requirement->getValue();
|
$value = $requirement->getValue();
|
||||||
$sqlColumn = $requirement->getType();
|
$sqlColumn = $requirement->getType();
|
||||||
|
|
||||||
if ($value instanceof RequirementCompositeValue)
|
if ($value instanceof RequirementCompositeValue)
|
||||||
{
|
{
|
||||||
$sql = $sqlColumn;
|
$sql = $sqlColumn;
|
||||||
$bindings = $value->getValues();
|
$bindings = $value->getValues();
|
||||||
|
|
||||||
if ($requirement->isNegated())
|
if ($requirement->isNegated())
|
||||||
$sql = 'NOT ' . $sql;
|
$sql = 'NOT ' . $sql;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if ($value instanceof RequirementRangedValue)
|
else if ($value instanceof RequirementRangedValue)
|
||||||
{
|
{
|
||||||
if ($value->getMinValue() && $value->getMaxValue())
|
if ($value->getMinValue() && $value->getMaxValue())
|
||||||
{
|
{
|
||||||
$sql = $sqlColumn . ' >= ? AND ' . $sqlColumn . ' <= ?';
|
$sql = $sqlColumn . ' >= ? AND ' . $sqlColumn . ' <= ?';
|
||||||
$bindings = [$value->getMinValue(), $value->getMaxValue()];
|
$bindings = [$value->getMinValue(), $value->getMaxValue()];
|
||||||
}
|
}
|
||||||
elseif ($value->getMinValue())
|
elseif ($value->getMinValue())
|
||||||
{
|
{
|
||||||
$sql = $sqlColumn . ' >= ?';
|
$sql = $sqlColumn . ' >= ?';
|
||||||
$bindings = [$value->getMinValue()];
|
$bindings = [$value->getMinValue()];
|
||||||
}
|
}
|
||||||
elseif ($value->getMaxValue())
|
elseif ($value->getMaxValue())
|
||||||
{
|
{
|
||||||
$sql = $sqlColumn . ' <= ?';
|
$sql = $sqlColumn . ' <= ?';
|
||||||
$bindings = [$value->getMaxValue()];
|
$bindings = [$value->getMaxValue()];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw new \RuntimeException('Neither min or max value was supplied');
|
throw new \RuntimeException('Neither min or max value was supplied');
|
||||||
|
|
||||||
if ($requirement->isNegated())
|
if ($requirement->isNegated())
|
||||||
$sql = 'NOT (' . $sql . ')';
|
$sql = 'NOT (' . $sql . ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
else if ($value instanceof RequirementSingleValue)
|
else if ($value instanceof RequirementSingleValue)
|
||||||
{
|
{
|
||||||
$sql = $sqlColumn;
|
$sql = $sqlColumn;
|
||||||
$bindings = [$value->getValue()];
|
$bindings = [$value->getValue()];
|
||||||
|
|
||||||
if ($requirement->isNegated())
|
if ($requirement->isNegated())
|
||||||
$sql = 'NOT ' . $sql;
|
$sql = 'NOT ' . $sql;
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
throw new \Exception('Bad value: ' . get_class($value));
|
throw new \Exception('Bad value: ' . get_class($value));
|
||||||
|
|
||||||
$query->where($sql, $bindings);
|
$query->where($sql, $bindings);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function arrayToEntities($arrayEntities, $entityConverter = null)
|
protected function arrayToEntities($arrayEntities, $entityConverter = null)
|
||||||
{
|
{
|
||||||
if ($entityConverter === null)
|
if ($entityConverter === null)
|
||||||
$entityConverter = $this->entityConverter;
|
$entityConverter = $this->entityConverter;
|
||||||
|
|
||||||
$entities = [];
|
$entities = [];
|
||||||
foreach ($arrayEntities as $arrayEntity)
|
foreach ($arrayEntities as $arrayEntity)
|
||||||
{
|
{
|
||||||
$entity = $entityConverter->toEntity($arrayEntity);
|
$entity = $entityConverter->toEntity($arrayEntity);
|
||||||
$entities[$entity->getId()] = $entity;
|
$entities[$entity->getId()] = $entity;
|
||||||
}
|
}
|
||||||
return $entities;
|
return $entities;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function setDatabaseConnection(DatabaseConnection $databaseConnection)
|
private function setDatabaseConnection(DatabaseConnection $databaseConnection)
|
||||||
{
|
{
|
||||||
$this->pdo = $databaseConnection->getPDO();
|
$this->pdo = $databaseConnection->getPDO();
|
||||||
$this->driver = $databaseConnection->getDriver();
|
$this->driver = $databaseConnection->getDriver();
|
||||||
}
|
}
|
||||||
|
|
||||||
private function decorateQueryFromFilter($query, IFilter $filter)
|
private function decorateQueryFromFilter($query, IFilter $filter)
|
||||||
{
|
{
|
||||||
foreach ($filter->getRequirements() as $requirement)
|
foreach ($filter->getRequirements() as $requirement)
|
||||||
{
|
{
|
||||||
$this->decorateQueryFromRequirement($query, $requirement);
|
$this->decorateQueryFromRequirement($query, $requirement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function compileOrderBy($order)
|
private function compileOrderBy($order)
|
||||||
{
|
{
|
||||||
$orderByString = '';
|
$orderByString = '';
|
||||||
foreach ($order as $orderColumn => $orderDir)
|
foreach ($order as $orderColumn => $orderDir)
|
||||||
{
|
{
|
||||||
if ($orderColumn === IFilter::ORDER_RANDOM)
|
if ($orderColumn === IFilter::ORDER_RANDOM)
|
||||||
{
|
{
|
||||||
$driver = $this->driver;
|
$driver = $this->driver;
|
||||||
if ($driver === 'sqlite')
|
if ($driver === 'sqlite')
|
||||||
{
|
{
|
||||||
$orderColumn = 'RANDOM()';
|
$orderColumn = 'RANDOM()';
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$orderColumn = 'RAND()';
|
$orderColumn = 'RAND()';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$orderByString .= $orderColumn . ' ' . ($orderDir === IFilter::ORDER_DESC ? 'DESC' : 'ASC') . ', ';
|
$orderByString .= $orderColumn . ' ' . ($orderDir === IFilter::ORDER_DESC ? 'DESC' : 'ASC') . ', ';
|
||||||
}
|
}
|
||||||
return substr($orderByString, 0, -2);
|
return substr($orderByString, 0, -2);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function upsert(Entity $entity)
|
private function upsert(Entity $entity)
|
||||||
{
|
{
|
||||||
if ($entity->getId())
|
if ($entity->getId())
|
||||||
{
|
{
|
||||||
return $this->update($entity);
|
return $this->update($entity);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return $this->create($entity);
|
return $this->create($entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,42 +10,42 @@ use Szurubooru\Entities\Post;
|
||||||
|
|
||||||
class CommentDao extends AbstractDao implements ICrudDao
|
class CommentDao extends AbstractDao implements ICrudDao
|
||||||
{
|
{
|
||||||
private $userDao;
|
private $userDao;
|
||||||
private $postDao;
|
private $postDao;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
DatabaseConnection $databaseConnection,
|
DatabaseConnection $databaseConnection,
|
||||||
UserDao $userDao,
|
UserDao $userDao,
|
||||||
PostDao $postDao)
|
PostDao $postDao)
|
||||||
{
|
{
|
||||||
parent::__construct(
|
parent::__construct(
|
||||||
$databaseConnection,
|
$databaseConnection,
|
||||||
'comments',
|
'comments',
|
||||||
new CommentEntityConverter());
|
new CommentEntityConverter());
|
||||||
|
|
||||||
$this->userDao = $userDao;
|
$this->userDao = $userDao;
|
||||||
$this->postDao = $postDao;
|
$this->postDao = $postDao;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findByPost(Post $post)
|
public function findByPost(Post $post)
|
||||||
{
|
{
|
||||||
return $this->findBy('postId', $post->getId());
|
return $this->findBy('postId', $post->getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function afterLoad(Entity $comment)
|
protected function afterLoad(Entity $comment)
|
||||||
{
|
{
|
||||||
$comment->setLazyLoader(
|
$comment->setLazyLoader(
|
||||||
Comment::LAZY_LOADER_USER,
|
Comment::LAZY_LOADER_USER,
|
||||||
function (Comment $comment)
|
function (Comment $comment)
|
||||||
{
|
{
|
||||||
return $this->userDao->findById($comment->getUserId());
|
return $this->userDao->findById($comment->getUserId());
|
||||||
});
|
});
|
||||||
|
|
||||||
$comment->setLazyLoader(
|
$comment->setLazyLoader(
|
||||||
Comment::LAZY_LOADER_POST,
|
Comment::LAZY_LOADER_POST,
|
||||||
function (Comment $comment)
|
function (Comment $comment)
|
||||||
{
|
{
|
||||||
return $this->postDao->findById($comment->getPostId());
|
return $this->postDao->findById($comment->getPostId());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,43 +5,43 @@ use Szurubooru\Entities\Entity;
|
||||||
|
|
||||||
abstract class AbstractEntityConverter implements IEntityConverter
|
abstract class AbstractEntityConverter implements IEntityConverter
|
||||||
{
|
{
|
||||||
private $entityDecorator = null;
|
private $entityDecorator = null;
|
||||||
|
|
||||||
public function setEntityDecorator(callable $entityDecorator)
|
public function setEntityDecorator(callable $entityDecorator)
|
||||||
{
|
{
|
||||||
$this->entityDecorator = $entityDecorator;
|
$this->entityDecorator = $entityDecorator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function toEntity(array $array)
|
public function toEntity(array $array)
|
||||||
{
|
{
|
||||||
$entity = $this->toBasicEntity($array);
|
$entity = $this->toBasicEntity($array);
|
||||||
$func = $this->entityDecorator;
|
$func = $this->entityDecorator;
|
||||||
if ($func !== null)
|
if ($func !== null)
|
||||||
$func($entity);
|
$func($entity);
|
||||||
return $entity;
|
return $entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function toArray(Entity $entity)
|
public function toArray(Entity $entity)
|
||||||
{
|
{
|
||||||
$array = $this->toBasicArray($entity);
|
$array = $this->toBasicArray($entity);
|
||||||
if ($entity->getId() !== null)
|
if ($entity->getId() !== null)
|
||||||
$array['id'] = $entity->getId();
|
$array['id'] = $entity->getId();
|
||||||
return $array;
|
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)
|
protected function dbTimeToEntityTime($time)
|
||||||
{
|
{
|
||||||
if ($time === null)
|
if ($time === null)
|
||||||
return null;
|
return null;
|
||||||
return date('c', strtotime($time));
|
return date('c', strtotime($time));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function entityTimeToDbTime($time)
|
protected function entityTimeToDbTime($time)
|
||||||
{
|
{
|
||||||
return $time === null ? null : date('Y-m-d H:i:s', strtotime($time));
|
return $time === null ? null : date('Y-m-d H:i:s', strtotime($time));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,27 +5,27 @@ use Szurubooru\Entities\Entity;
|
||||||
|
|
||||||
class CommentEntityConverter extends AbstractEntityConverter implements IEntityConverter
|
class CommentEntityConverter extends AbstractEntityConverter implements IEntityConverter
|
||||||
{
|
{
|
||||||
public function toBasicArray(Entity $entity)
|
public function toBasicArray(Entity $entity)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
[
|
[
|
||||||
'userId' => $entity->getUserId(),
|
'userId' => $entity->getUserId(),
|
||||||
'postId' => $entity->getPostId(),
|
'postId' => $entity->getPostId(),
|
||||||
'text' => $entity->getText(),
|
'text' => $entity->getText(),
|
||||||
'creationTime' => $this->entityTimeToDbTime($entity->getCreationTime()),
|
'creationTime' => $this->entityTimeToDbTime($entity->getCreationTime()),
|
||||||
'lastEditTime' => $this->entityTimeToDbTime($entity->getLastEditTime()),
|
'lastEditTime' => $this->entityTimeToDbTime($entity->getLastEditTime()),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function toBasicEntity(array $array)
|
public function toBasicEntity(array $array)
|
||||||
{
|
{
|
||||||
$entity = new Comment(intval($array['id']));
|
$entity = new Comment(intval($array['id']));
|
||||||
$entity->setUserId($array['userId']);
|
$entity->setUserId($array['userId']);
|
||||||
$entity->setPostId($array['postId']);
|
$entity->setPostId($array['postId']);
|
||||||
$entity->setText($array['text']);
|
$entity->setText($array['text']);
|
||||||
$entity->setCreationTime($this->dbTimeToEntityTime($array['creationTime']));
|
$entity->setCreationTime($this->dbTimeToEntityTime($array['creationTime']));
|
||||||
$entity->setLastEditTime($this->dbTimeToEntityTime($array['lastEditTime']));
|
$entity->setLastEditTime($this->dbTimeToEntityTime($array['lastEditTime']));
|
||||||
$entity->setMeta(Comment::META_SCORE, intval($array['score']));
|
$entity->setMeta(Comment::META_SCORE, intval($array['score']));
|
||||||
return $entity;
|
return $entity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,22 +5,22 @@ use Szurubooru\Entities\Favorite;
|
||||||
|
|
||||||
class FavoriteEntityConverter extends AbstractEntityConverter implements IEntityConverter
|
class FavoriteEntityConverter extends AbstractEntityConverter implements IEntityConverter
|
||||||
{
|
{
|
||||||
public function toBasicArray(Entity $entity)
|
public function toBasicArray(Entity $entity)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
[
|
[
|
||||||
'userId' => $entity->getUserId(),
|
'userId' => $entity->getUserId(),
|
||||||
'postId' => $entity->getPostId(),
|
'postId' => $entity->getPostId(),
|
||||||
'time' => $this->entityTimeToDbTime($entity->getTime()),
|
'time' => $this->entityTimeToDbTime($entity->getTime()),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function toBasicEntity(array $array)
|
public function toBasicEntity(array $array)
|
||||||
{
|
{
|
||||||
$entity = new Favorite(intval($array['id']));
|
$entity = new Favorite(intval($array['id']));
|
||||||
$entity->setUserId($array['userId']);
|
$entity->setUserId($array['userId']);
|
||||||
$entity->setPostId($array['postId']);
|
$entity->setPostId($array['postId']);
|
||||||
$entity->setTime($this->dbTimeToEntityTime($array['time']));
|
$entity->setTime($this->dbTimeToEntityTime($array['time']));
|
||||||
return $entity;
|
return $entity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,20 +5,20 @@ use Szurubooru\Entities\GlobalParam;
|
||||||
|
|
||||||
class GlobalParamEntityConverter extends AbstractEntityConverter implements IEntityConverter
|
class GlobalParamEntityConverter extends AbstractEntityConverter implements IEntityConverter
|
||||||
{
|
{
|
||||||
public function toBasicArray(Entity $entity)
|
public function toBasicArray(Entity $entity)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
[
|
[
|
||||||
'dataKey' => $entity->getKey(),
|
'dataKey' => $entity->getKey(),
|
||||||
'dataValue' => $entity->getValue(),
|
'dataValue' => $entity->getValue(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function toBasicEntity(array $array)
|
public function toBasicEntity(array $array)
|
||||||
{
|
{
|
||||||
$entity = new GlobalParam(intval($array['id']));
|
$entity = new GlobalParam(intval($array['id']));
|
||||||
$entity->setKey($array['dataKey']);
|
$entity->setKey($array['dataKey']);
|
||||||
$entity->setValue($array['dataValue']);
|
$entity->setValue($array['dataValue']);
|
||||||
return $entity;
|
return $entity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use Szurubooru\Entities\Entity;
|
||||||
|
|
||||||
interface IEntityConverter
|
interface IEntityConverter
|
||||||
{
|
{
|
||||||
public function toArray(Entity $entity);
|
public function toArray(Entity $entity);
|
||||||
|
|
||||||
public function toEntity(array $array);
|
public function toEntity(array $array);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,52 +5,52 @@ use Szurubooru\Entities\Post;
|
||||||
|
|
||||||
class PostEntityConverter extends AbstractEntityConverter implements IEntityConverter
|
class PostEntityConverter extends AbstractEntityConverter implements IEntityConverter
|
||||||
{
|
{
|
||||||
public function toBasicArray(Entity $entity)
|
public function toBasicArray(Entity $entity)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
[
|
[
|
||||||
'name' => $entity->getName(),
|
'name' => $entity->getName(),
|
||||||
'userId' => $entity->getUserId(),
|
'userId' => $entity->getUserId(),
|
||||||
'uploadTime' => $this->entityTimeToDbTime($entity->getUploadTime()),
|
'uploadTime' => $this->entityTimeToDbTime($entity->getUploadTime()),
|
||||||
'lastEditTime' => $this->entityTimeToDbTime($entity->getLastEditTime()),
|
'lastEditTime' => $this->entityTimeToDbTime($entity->getLastEditTime()),
|
||||||
'safety' => $entity->getSafety(),
|
'safety' => $entity->getSafety(),
|
||||||
'contentType' => $entity->getContentType(),
|
'contentType' => $entity->getContentType(),
|
||||||
'contentChecksum' => $entity->getContentChecksum(),
|
'contentChecksum' => $entity->getContentChecksum(),
|
||||||
'contentMimeType' => $entity->getContentMimeType(),
|
'contentMimeType' => $entity->getContentMimeType(),
|
||||||
'source' => $entity->getSource(),
|
'source' => $entity->getSource(),
|
||||||
'imageWidth' => $entity->getImageWidth(),
|
'imageWidth' => $entity->getImageWidth(),
|
||||||
'imageHeight' => $entity->getImageHeight(),
|
'imageHeight' => $entity->getImageHeight(),
|
||||||
'originalFileSize' => $entity->getOriginalFileSize(),
|
'originalFileSize' => $entity->getOriginalFileSize(),
|
||||||
'originalFileName' => $entity->getOriginalFileName(),
|
'originalFileName' => $entity->getOriginalFileName(),
|
||||||
'featureCount' => $entity->getFeatureCount(),
|
'featureCount' => $entity->getFeatureCount(),
|
||||||
'lastFeatureTime' => $this->entityTimeToDbTime($entity->getLastFeatureTime()),
|
'lastFeatureTime' => $this->entityTimeToDbTime($entity->getLastFeatureTime()),
|
||||||
'flags' => $entity->getFlags(),
|
'flags' => $entity->getFlags(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function toBasicEntity(array $array)
|
public function toBasicEntity(array $array)
|
||||||
{
|
{
|
||||||
$entity = new Post(intval($array['id']));
|
$entity = new Post(intval($array['id']));
|
||||||
$entity->setName($array['name']);
|
$entity->setName($array['name']);
|
||||||
$entity->setUserId($array['userId']);
|
$entity->setUserId($array['userId']);
|
||||||
$entity->setUploadTime($this->dbTimeToEntityTime($array['uploadTime']));
|
$entity->setUploadTime($this->dbTimeToEntityTime($array['uploadTime']));
|
||||||
$entity->setLastEditTime($this->dbTimeToEntityTime($array['lastEditTime']));
|
$entity->setLastEditTime($this->dbTimeToEntityTime($array['lastEditTime']));
|
||||||
$entity->setSafety(intval($array['safety']));
|
$entity->setSafety(intval($array['safety']));
|
||||||
$entity->setContentType(intval($array['contentType']));
|
$entity->setContentType(intval($array['contentType']));
|
||||||
$entity->setContentChecksum($array['contentChecksum']);
|
$entity->setContentChecksum($array['contentChecksum']);
|
||||||
$entity->setContentMimeType($array['contentMimeType']);
|
$entity->setContentMimeType($array['contentMimeType']);
|
||||||
$entity->setSource($array['source']);
|
$entity->setSource($array['source']);
|
||||||
$entity->setImageWidth($array['imageWidth']);
|
$entity->setImageWidth($array['imageWidth']);
|
||||||
$entity->setImageHeight($array['imageHeight']);
|
$entity->setImageHeight($array['imageHeight']);
|
||||||
$entity->setOriginalFileSize($array['originalFileSize']);
|
$entity->setOriginalFileSize($array['originalFileSize']);
|
||||||
$entity->setOriginalFileName($array['originalFileName']);
|
$entity->setOriginalFileName($array['originalFileName']);
|
||||||
$entity->setFeatureCount(intval($array['featureCount']));
|
$entity->setFeatureCount(intval($array['featureCount']));
|
||||||
$entity->setLastFeatureTime($this->dbTimeToEntityTime($array['lastFeatureTime']));
|
$entity->setLastFeatureTime($this->dbTimeToEntityTime($array['lastFeatureTime']));
|
||||||
$entity->setFlags(intval($array['flags']));
|
$entity->setFlags(intval($array['flags']));
|
||||||
$entity->setMeta(Post::META_TAG_COUNT, intval($array['tagCount']));
|
$entity->setMeta(Post::META_TAG_COUNT, intval($array['tagCount']));
|
||||||
$entity->setMeta(Post::META_FAV_COUNT, intval($array['favCount']));
|
$entity->setMeta(Post::META_FAV_COUNT, intval($array['favCount']));
|
||||||
$entity->setMeta(Post::META_COMMENT_COUNT, intval($array['commentCount']));
|
$entity->setMeta(Post::META_COMMENT_COUNT, intval($array['commentCount']));
|
||||||
$entity->setMeta(Post::META_SCORE, intval($array['score']));
|
$entity->setMeta(Post::META_SCORE, intval($array['score']));
|
||||||
return $entity;
|
return $entity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,28 +5,28 @@ use Szurubooru\Entities\PostNote;
|
||||||
|
|
||||||
class PostNoteEntityConverter extends AbstractEntityConverter implements IEntityConverter
|
class PostNoteEntityConverter extends AbstractEntityConverter implements IEntityConverter
|
||||||
{
|
{
|
||||||
public function toBasicArray(Entity $entity)
|
public function toBasicArray(Entity $entity)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
[
|
[
|
||||||
'postId' => $entity->getPostId(),
|
'postId' => $entity->getPostId(),
|
||||||
'x' => $entity->getLeft(),
|
'x' => $entity->getLeft(),
|
||||||
'y' => $entity->getTop(),
|
'y' => $entity->getTop(),
|
||||||
'width' => $entity->getWidth(),
|
'width' => $entity->getWidth(),
|
||||||
'height' => $entity->getHeight(),
|
'height' => $entity->getHeight(),
|
||||||
'text' => $entity->getText(),
|
'text' => $entity->getText(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function toBasicEntity(array $array)
|
public function toBasicEntity(array $array)
|
||||||
{
|
{
|
||||||
$entity = new PostNote(intval($array['id']));
|
$entity = new PostNote(intval($array['id']));
|
||||||
$entity->setPostId($array['postId']);
|
$entity->setPostId($array['postId']);
|
||||||
$entity->setLeft(floatval($array['x']));
|
$entity->setLeft(floatval($array['x']));
|
||||||
$entity->setTop(floatval($array['y']));
|
$entity->setTop(floatval($array['y']));
|
||||||
$entity->setWidth(floatval($array['width']));
|
$entity->setWidth(floatval($array['width']));
|
||||||
$entity->setHeight(floatval($array['height']));
|
$entity->setHeight(floatval($array['height']));
|
||||||
$entity->setText($array['text']);
|
$entity->setText($array['text']);
|
||||||
return $entity;
|
return $entity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,26 +5,26 @@ use Szurubooru\Entities\Score;
|
||||||
|
|
||||||
class ScoreEntityConverter extends AbstractEntityConverter implements IEntityConverter
|
class ScoreEntityConverter extends AbstractEntityConverter implements IEntityConverter
|
||||||
{
|
{
|
||||||
public function toBasicArray(Entity $entity)
|
public function toBasicArray(Entity $entity)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
[
|
[
|
||||||
'userId' => $entity->getUserId(),
|
'userId' => $entity->getUserId(),
|
||||||
'postId' => $entity->getPostId(),
|
'postId' => $entity->getPostId(),
|
||||||
'commentId' => $entity->getCommentId(),
|
'commentId' => $entity->getCommentId(),
|
||||||
'time' => $this->entityTimeToDbTime($entity->getTime()),
|
'time' => $this->entityTimeToDbTime($entity->getTime()),
|
||||||
'score' => $entity->getScore(),
|
'score' => $entity->getScore(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function toBasicEntity(array $array)
|
public function toBasicEntity(array $array)
|
||||||
{
|
{
|
||||||
$entity = new Score(intval($array['id']));
|
$entity = new Score(intval($array['id']));
|
||||||
$entity->setUserId($array['userId']);
|
$entity->setUserId($array['userId']);
|
||||||
$entity->setPostId($array['postId']);
|
$entity->setPostId($array['postId']);
|
||||||
$entity->setCommentId($array['commentId']);
|
$entity->setCommentId($array['commentId']);
|
||||||
$entity->setTime($this->dbTimeToEntityTime($array['time']));
|
$entity->setTime($this->dbTimeToEntityTime($array['time']));
|
||||||
$entity->setScore(intval($array['score']));
|
$entity->setScore(intval($array['score']));
|
||||||
return $entity;
|
return $entity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,30 +5,30 @@ use Szurubooru\Entities\Snapshot;
|
||||||
|
|
||||||
class SnapshotEntityConverter extends AbstractEntityConverter implements IEntityConverter
|
class SnapshotEntityConverter extends AbstractEntityConverter implements IEntityConverter
|
||||||
{
|
{
|
||||||
public function toBasicArray(Entity $entity)
|
public function toBasicArray(Entity $entity)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
[
|
[
|
||||||
'time' => $this->entityTimeToDbTime($entity->getTime()),
|
'time' => $this->entityTimeToDbTime($entity->getTime()),
|
||||||
'type' => $entity->getType(),
|
'type' => $entity->getType(),
|
||||||
'primaryKey' => $entity->getPrimaryKey(),
|
'primaryKey' => $entity->getPrimaryKey(),
|
||||||
'userId' => $entity->getUserId(),
|
'userId' => $entity->getUserId(),
|
||||||
'operation' => $entity->getOperation(),
|
'operation' => $entity->getOperation(),
|
||||||
'data' => gzdeflate(json_encode($entity->getData())),
|
'data' => gzdeflate(json_encode($entity->getData())),
|
||||||
'dataDifference' => gzdeflate(json_encode($entity->getDataDifference())),
|
'dataDifference' => gzdeflate(json_encode($entity->getDataDifference())),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function toBasicEntity(array $array)
|
public function toBasicEntity(array $array)
|
||||||
{
|
{
|
||||||
$entity = new Snapshot(intval($array['id']));
|
$entity = new Snapshot(intval($array['id']));
|
||||||
$entity->setTime($this->dbTimeToEntityTime($array['time']));
|
$entity->setTime($this->dbTimeToEntityTime($array['time']));
|
||||||
$entity->setType(intval($array['type']));
|
$entity->setType(intval($array['type']));
|
||||||
$entity->setPrimaryKey($array['primaryKey']);
|
$entity->setPrimaryKey($array['primaryKey']);
|
||||||
$entity->setUserId(intval($array['userId']));
|
$entity->setUserId(intval($array['userId']));
|
||||||
$entity->setOperation($array['operation']);
|
$entity->setOperation($array['operation']);
|
||||||
$entity->setData(json_decode(gzinflate($array['data']), true));
|
$entity->setData(json_decode(gzinflate($array['data']), true));
|
||||||
$entity->setDataDifference(json_decode(gzinflate($array['dataDifference']), true));
|
$entity->setDataDifference(json_decode(gzinflate($array['dataDifference']), true));
|
||||||
return $entity;
|
return $entity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,25 +5,25 @@ use Szurubooru\Entities\Tag;
|
||||||
|
|
||||||
class TagEntityConverter extends AbstractEntityConverter implements IEntityConverter
|
class TagEntityConverter extends AbstractEntityConverter implements IEntityConverter
|
||||||
{
|
{
|
||||||
public function toBasicArray(Entity $entity)
|
public function toBasicArray(Entity $entity)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
[
|
[
|
||||||
'name' => $entity->getName(),
|
'name' => $entity->getName(),
|
||||||
'creationTime' => $this->entityTimeToDbTime($entity->getCreationTime()),
|
'creationTime' => $this->entityTimeToDbTime($entity->getCreationTime()),
|
||||||
'banned' => intval($entity->isBanned()),
|
'banned' => intval($entity->isBanned()),
|
||||||
'category' => $entity->getCategory(),
|
'category' => $entity->getCategory(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function toBasicEntity(array $array)
|
public function toBasicEntity(array $array)
|
||||||
{
|
{
|
||||||
$entity = new Tag(intval($array['id']));
|
$entity = new Tag(intval($array['id']));
|
||||||
$entity->setName($array['name']);
|
$entity->setName($array['name']);
|
||||||
$entity->setCreationTime($this->dbTimeToEntityTime($array['creationTime']));
|
$entity->setCreationTime($this->dbTimeToEntityTime($array['creationTime']));
|
||||||
$entity->setMeta(Tag::META_USAGES, intval($array['usages']));
|
$entity->setMeta(Tag::META_USAGES, intval($array['usages']));
|
||||||
$entity->setBanned($array['banned']);
|
$entity->setBanned($array['banned']);
|
||||||
$entity->setCategory($array['category']);
|
$entity->setCategory($array['category']);
|
||||||
return $entity;
|
return $entity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,22 +5,22 @@ use Szurubooru\Entities\Token;
|
||||||
|
|
||||||
class TokenEntityConverter extends AbstractEntityConverter implements IEntityConverter
|
class TokenEntityConverter extends AbstractEntityConverter implements IEntityConverter
|
||||||
{
|
{
|
||||||
public function toBasicArray(Entity $entity)
|
public function toBasicArray(Entity $entity)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
[
|
[
|
||||||
'name' => $entity->getName(),
|
'name' => $entity->getName(),
|
||||||
'purpose' => $entity->getPurpose(),
|
'purpose' => $entity->getPurpose(),
|
||||||
'additionalData' => $entity->getAdditionalData(),
|
'additionalData' => $entity->getAdditionalData(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function toBasicEntity(array $array)
|
public function toBasicEntity(array $array)
|
||||||
{
|
{
|
||||||
$entity = new Token(intval($array['id']));
|
$entity = new Token(intval($array['id']));
|
||||||
$entity->setName($array['name']);
|
$entity->setName($array['name']);
|
||||||
$entity->setPurpose($array['purpose']);
|
$entity->setPurpose($array['purpose']);
|
||||||
$entity->setAdditionalData($array['additionalData']);
|
$entity->setAdditionalData($array['additionalData']);
|
||||||
return $entity;
|
return $entity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,40 +5,40 @@ use Szurubooru\Entities\User;
|
||||||
|
|
||||||
class UserEntityConverter extends AbstractEntityConverter implements IEntityConverter
|
class UserEntityConverter extends AbstractEntityConverter implements IEntityConverter
|
||||||
{
|
{
|
||||||
public function toBasicArray(Entity $entity)
|
public function toBasicArray(Entity $entity)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
[
|
[
|
||||||
'name' => $entity->getName(),
|
'name' => $entity->getName(),
|
||||||
'email' => $entity->getEmail(),
|
'email' => $entity->getEmail(),
|
||||||
'emailUnconfirmed' => $entity->getEmailUnconfirmed(),
|
'emailUnconfirmed' => $entity->getEmailUnconfirmed(),
|
||||||
'passwordHash' => $entity->getPasswordHash(),
|
'passwordHash' => $entity->getPasswordHash(),
|
||||||
'passwordSalt' => $entity->getPasswordSalt(),
|
'passwordSalt' => $entity->getPasswordSalt(),
|
||||||
'accessRank' => $entity->getAccessRank(),
|
'accessRank' => $entity->getAccessRank(),
|
||||||
'registrationTime' => $this->entityTimeToDbTime($entity->getRegistrationTime()),
|
'registrationTime' => $this->entityTimeToDbTime($entity->getRegistrationTime()),
|
||||||
'lastLoginTime' => $this->entityTimeToDbTime($entity->getLastLoginTime()),
|
'lastLoginTime' => $this->entityTimeToDbTime($entity->getLastLoginTime()),
|
||||||
'avatarStyle' => $entity->getAvatarStyle(),
|
'avatarStyle' => $entity->getAvatarStyle(),
|
||||||
'browsingSettings' => json_encode($entity->getBrowsingSettings()),
|
'browsingSettings' => json_encode($entity->getBrowsingSettings()),
|
||||||
'accountConfirmed' => intval($entity->isAccountConfirmed()),
|
'accountConfirmed' => intval($entity->isAccountConfirmed()),
|
||||||
'banned' => intval($entity->isBanned()),
|
'banned' => intval($entity->isBanned()),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function toBasicEntity(array $array)
|
public function toBasicEntity(array $array)
|
||||||
{
|
{
|
||||||
$entity = new User(intval($array['id']));
|
$entity = new User(intval($array['id']));
|
||||||
$entity->setName($array['name']);
|
$entity->setName($array['name']);
|
||||||
$entity->setEmail($array['email']);
|
$entity->setEmail($array['email']);
|
||||||
$entity->setEmailUnconfirmed($array['emailUnconfirmed']);
|
$entity->setEmailUnconfirmed($array['emailUnconfirmed']);
|
||||||
$entity->setPasswordHash($array['passwordHash']);
|
$entity->setPasswordHash($array['passwordHash']);
|
||||||
$entity->setPasswordSalt($array['passwordSalt']);
|
$entity->setPasswordSalt($array['passwordSalt']);
|
||||||
$entity->setAccessRank(intval($array['accessRank']));
|
$entity->setAccessRank(intval($array['accessRank']));
|
||||||
$entity->setRegistrationTime($this->dbTimeToEntityTime($array['registrationTime']));
|
$entity->setRegistrationTime($this->dbTimeToEntityTime($array['registrationTime']));
|
||||||
$entity->setLastLoginTime($this->dbTimeToEntityTime($array['lastLoginTime']));
|
$entity->setLastLoginTime($this->dbTimeToEntityTime($array['lastLoginTime']));
|
||||||
$entity->setAvatarStyle(intval($array['avatarStyle']));
|
$entity->setAvatarStyle(intval($array['avatarStyle']));
|
||||||
$entity->setBrowsingSettings(json_decode($array['browsingSettings']));
|
$entity->setBrowsingSettings(json_decode($array['browsingSettings']));
|
||||||
$entity->setAccountConfirmed($array['accountConfirmed']);
|
$entity->setAccountConfirmed($array['accountConfirmed']);
|
||||||
$entity->setBanned($array['banned']);
|
$entity->setBanned($array['banned']);
|
||||||
return $entity;
|
return $entity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,65 +10,65 @@ use Szurubooru\Services\TimeService;
|
||||||
|
|
||||||
class FavoritesDao extends AbstractDao implements ICrudDao
|
class FavoritesDao extends AbstractDao implements ICrudDao
|
||||||
{
|
{
|
||||||
private $timeService;
|
private $timeService;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
DatabaseConnection $databaseConnection,
|
DatabaseConnection $databaseConnection,
|
||||||
TimeService $timeService)
|
TimeService $timeService)
|
||||||
{
|
{
|
||||||
parent::__construct(
|
parent::__construct(
|
||||||
$databaseConnection,
|
$databaseConnection,
|
||||||
'favorites',
|
'favorites',
|
||||||
new FavoriteEntityConverter());
|
new FavoriteEntityConverter());
|
||||||
|
|
||||||
$this->timeService = $timeService;
|
$this->timeService = $timeService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findByEntity(Entity $entity)
|
public function findByEntity(Entity $entity)
|
||||||
{
|
{
|
||||||
if ($entity instanceof Post)
|
if ($entity instanceof Post)
|
||||||
return $this->findBy('postId', $entity->getId());
|
return $this->findBy('postId', $entity->getId());
|
||||||
else
|
else
|
||||||
throw new \InvalidArgumentException();
|
throw new \InvalidArgumentException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function set(User $user, Entity $entity)
|
public function set(User $user, Entity $entity)
|
||||||
{
|
{
|
||||||
$favorite = $this->get($user, $entity);
|
$favorite = $this->get($user, $entity);
|
||||||
if (!$favorite)
|
if (!$favorite)
|
||||||
{
|
{
|
||||||
$favorite = new Favorite();
|
$favorite = new Favorite();
|
||||||
$favorite->setTime($this->timeService->getCurrentTime());
|
$favorite->setTime($this->timeService->getCurrentTime());
|
||||||
$favorite->setUserId($user->getId());
|
$favorite->setUserId($user->getId());
|
||||||
|
|
||||||
if ($entity instanceof Post)
|
if ($entity instanceof Post)
|
||||||
$favorite->setPostId($entity->getId());
|
$favorite->setPostId($entity->getId());
|
||||||
else
|
else
|
||||||
throw new \InvalidArgumentException();
|
throw new \InvalidArgumentException();
|
||||||
|
|
||||||
$this->save($favorite);
|
$this->save($favorite);
|
||||||
}
|
}
|
||||||
return $favorite;
|
return $favorite;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function delete(User $user, Entity $entity)
|
public function delete(User $user, Entity $entity)
|
||||||
{
|
{
|
||||||
$favorite = $this->get($user, $entity);
|
$favorite = $this->get($user, $entity);
|
||||||
if ($favorite)
|
if ($favorite)
|
||||||
$this->deleteById($favorite->getId());
|
$this->deleteById($favorite->getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
private function get(User $user, Entity $entity)
|
private function get(User $user, Entity $entity)
|
||||||
{
|
{
|
||||||
$query = $this->pdo->from($this->tableName)->where('userId', $user->getId());
|
$query = $this->pdo->from($this->tableName)->where('userId', $user->getId());
|
||||||
|
|
||||||
if ($entity instanceof Post)
|
if ($entity instanceof Post)
|
||||||
$query->where('postId', $entity->getId());
|
$query->where('postId', $entity->getId());
|
||||||
else
|
else
|
||||||
throw new \InvalidArgumentException();
|
throw new \InvalidArgumentException();
|
||||||
|
|
||||||
$arrayEntities = iterator_to_array($query);
|
$arrayEntities = iterator_to_array($query);
|
||||||
$entities = $this->arrayToEntities($arrayEntities);
|
$entities = $this->arrayToEntities($arrayEntities);
|
||||||
return array_shift($entities);
|
return array_shift($entities);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,93 +4,93 @@ use Szurubooru\Dao\IFileDao;
|
||||||
|
|
||||||
class FileDao implements IFileDao
|
class FileDao implements IFileDao
|
||||||
{
|
{
|
||||||
private $directory;
|
private $directory;
|
||||||
|
|
||||||
public function __construct($directory)
|
public function __construct($directory)
|
||||||
{
|
{
|
||||||
$this->directory = $directory;
|
$this->directory = $directory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function load($fileName)
|
public function load($fileName)
|
||||||
{
|
{
|
||||||
$fullPath = $this->getFullPath($fileName);
|
$fullPath = $this->getFullPath($fileName);
|
||||||
return file_exists($fullPath)
|
return file_exists($fullPath)
|
||||||
? file_get_contents($fullPath)
|
? file_get_contents($fullPath)
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function save($fileName, $data)
|
public function save($fileName, $data)
|
||||||
{
|
{
|
||||||
$fullPath = $this->getFullPath($fileName);
|
$fullPath = $this->getFullPath($fileName);
|
||||||
$this->createFolders($fileName);
|
$this->createFolders($fileName);
|
||||||
file_put_contents($fullPath, $data);
|
file_put_contents($fullPath, $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function delete($fileName)
|
public function delete($fileName)
|
||||||
{
|
{
|
||||||
$fullPath = $this->getFullPath($fileName);
|
$fullPath = $this->getFullPath($fileName);
|
||||||
if (file_exists($fullPath))
|
if (file_exists($fullPath))
|
||||||
unlink($fullPath);
|
unlink($fullPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function exists($fileName)
|
public function exists($fileName)
|
||||||
{
|
{
|
||||||
$fullPath = $this->getFullPath($fileName);
|
$fullPath = $this->getFullPath($fileName);
|
||||||
return file_exists($fullPath);
|
return file_exists($fullPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFullPath($fileName)
|
public function getFullPath($fileName)
|
||||||
{
|
{
|
||||||
return $this->directory . DIRECTORY_SEPARATOR . $fileName;
|
return $this->directory . DIRECTORY_SEPARATOR . $fileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function listAll()
|
public function listAll()
|
||||||
{
|
{
|
||||||
$iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->directory));
|
$iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->directory));
|
||||||
$files = [];
|
$files = [];
|
||||||
foreach ($iterator as $path)
|
foreach ($iterator as $path)
|
||||||
{
|
{
|
||||||
if (!$path->isDir())
|
if (!$path->isDir())
|
||||||
$files[] = $this->getRelativePath($this->directory, $path->getPathName());
|
$files[] = $this->getRelativePath($this->directory, $path->getPathName());
|
||||||
}
|
}
|
||||||
return $files;
|
return $files;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function createFolders($fileName)
|
private function createFolders($fileName)
|
||||||
{
|
{
|
||||||
$fullPath = dirname($this->getFullPath($fileName));
|
$fullPath = dirname($this->getFullPath($fileName));
|
||||||
if (!file_exists($fullPath))
|
if (!file_exists($fullPath))
|
||||||
mkdir($fullPath, 0777, true);
|
mkdir($fullPath, 0777, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getRelativePath($from, $to)
|
private function getRelativePath($from, $to)
|
||||||
{
|
{
|
||||||
$from = is_dir($from) ? rtrim($from, '\/') . '/' : $from;
|
$from = is_dir($from) ? rtrim($from, '\/') . '/' : $from;
|
||||||
$to = is_dir($to) ? rtrim($to, '\/') . '/' : $to;
|
$to = is_dir($to) ? rtrim($to, '\/') . '/' : $to;
|
||||||
$from = explode('/', str_replace('\\', '/', $from));
|
$from = explode('/', str_replace('\\', '/', $from));
|
||||||
$to = explode('/', str_replace('\\', '/', $to));
|
$to = explode('/', str_replace('\\', '/', $to));
|
||||||
$relPath = $to;
|
$relPath = $to;
|
||||||
foreach($from as $depth => $dir)
|
foreach($from as $depth => $dir)
|
||||||
{
|
{
|
||||||
if($dir === $to[$depth])
|
if($dir === $to[$depth])
|
||||||
{
|
{
|
||||||
array_shift($relPath);
|
array_shift($relPath);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$remaining = count($from) - $depth;
|
$remaining = count($from) - $depth;
|
||||||
if ($remaining > 1)
|
if ($remaining > 1)
|
||||||
{
|
{
|
||||||
$padLength = (count($relPath) + $remaining - 1) * -1;
|
$padLength = (count($relPath) + $remaining - 1) * -1;
|
||||||
$relPath = array_pad($relPath, $padLength, '..');
|
$relPath = array_pad($relPath, $padLength, '..');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$relPath[0] = $relPath[0];
|
$relPath[0] = $relPath[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return implode('/', $relPath);
|
return implode('/', $relPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,32 +5,32 @@ use Szurubooru\DatabaseConnection;
|
||||||
|
|
||||||
class GlobalParamDao extends AbstractDao implements ICrudDao
|
class GlobalParamDao extends AbstractDao implements ICrudDao
|
||||||
{
|
{
|
||||||
public function __construct(DatabaseConnection $databaseConnection)
|
public function __construct(DatabaseConnection $databaseConnection)
|
||||||
{
|
{
|
||||||
parent::__construct(
|
parent::__construct(
|
||||||
$databaseConnection,
|
$databaseConnection,
|
||||||
'globals',
|
'globals',
|
||||||
new GlobalParamEntityConverter());
|
new GlobalParamEntityConverter());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function save(&$entity)
|
public function save(&$entity)
|
||||||
{
|
{
|
||||||
if (!$entity->getId())
|
if (!$entity->getId())
|
||||||
{
|
{
|
||||||
$otherEntityWithThisKey = $this->findByKey($entity->getKey());
|
$otherEntityWithThisKey = $this->findByKey($entity->getKey());
|
||||||
if ($otherEntityWithThisKey)
|
if ($otherEntityWithThisKey)
|
||||||
$entity->setId($otherEntityWithThisKey->getId());
|
$entity->setId($otherEntityWithThisKey->getId());
|
||||||
}
|
}
|
||||||
parent::save($entity);
|
parent::save($entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findByKey($key)
|
public function findByKey($key)
|
||||||
{
|
{
|
||||||
return $this->findOneBy('dataKey', $key);
|
return $this->findOneBy('dataKey', $key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function deleteByKey($key)
|
public function deleteByKey($key)
|
||||||
{
|
{
|
||||||
return $this->deleteBy('dataKey', $key);
|
return $this->deleteBy('dataKey', $key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,9 @@ namespace Szurubooru\Dao;
|
||||||
|
|
||||||
interface IBatchDao
|
interface IBatchDao
|
||||||
{
|
{
|
||||||
public function findAll();
|
public function findAll();
|
||||||
|
|
||||||
public function deleteAll();
|
public function deleteAll();
|
||||||
|
|
||||||
public function batchSave(array $objects);
|
public function batchSave(array $objects);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,9 @@ namespace Szurubooru\Dao;
|
||||||
|
|
||||||
interface ICrudDao
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,11 +3,11 @@ namespace Szurubooru\Dao;
|
||||||
|
|
||||||
interface IFileDao
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,295 +13,295 @@ use Szurubooru\Services\ThumbnailService;
|
||||||
|
|
||||||
class PostDao extends AbstractDao implements ICrudDao
|
class PostDao extends AbstractDao implements ICrudDao
|
||||||
{
|
{
|
||||||
private $tagDao;
|
private $tagDao;
|
||||||
private $userDao;
|
private $userDao;
|
||||||
private $fileDao;
|
private $fileDao;
|
||||||
private $thumbnailService;
|
private $thumbnailService;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
DatabaseConnection $databaseConnection,
|
DatabaseConnection $databaseConnection,
|
||||||
TagDao $tagDao,
|
TagDao $tagDao,
|
||||||
UserDao $userDao,
|
UserDao $userDao,
|
||||||
PublicFileDao $fileDao,
|
PublicFileDao $fileDao,
|
||||||
ThumbnailService $thumbnailService)
|
ThumbnailService $thumbnailService)
|
||||||
{
|
{
|
||||||
parent::__construct(
|
parent::__construct(
|
||||||
$databaseConnection,
|
$databaseConnection,
|
||||||
'posts',
|
'posts',
|
||||||
new PostEntityConverter());
|
new PostEntityConverter());
|
||||||
|
|
||||||
$this->tagDao = $tagDao;
|
$this->tagDao = $tagDao;
|
||||||
$this->userDao = $userDao;
|
$this->userDao = $userDao;
|
||||||
$this->fileDao = $fileDao;
|
$this->fileDao = $fileDao;
|
||||||
$this->thumbnailService = $thumbnailService;
|
$this->thumbnailService = $thumbnailService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCount()
|
public function getCount()
|
||||||
{
|
{
|
||||||
return count($this->pdo->from($this->tableName));
|
return count($this->pdo->from($this->tableName));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTotalFileSize()
|
public function getTotalFileSize()
|
||||||
{
|
{
|
||||||
$query = $this->pdo->from($this->tableName)->select('SUM(originalFileSize) AS __sum');
|
$query = $this->pdo->from($this->tableName)->select('SUM(originalFileSize) AS __sum');
|
||||||
return iterator_to_array($query)[0]['__sum'];
|
return iterator_to_array($query)[0]['__sum'];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findByName($name)
|
public function findByName($name)
|
||||||
{
|
{
|
||||||
return $this->findOneBy('name', $name);
|
return $this->findOneBy('name', $name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findByTagName($tagName)
|
public function findByTagName($tagName)
|
||||||
{
|
{
|
||||||
$query = $this->pdo->from('posts')
|
$query = $this->pdo->from('posts')
|
||||||
->innerJoin('postTags', 'postTags.postId = posts.id')
|
->innerJoin('postTags', 'postTags.postId = posts.id')
|
||||||
->innerJoin('tags', 'postTags.tagId = tags.id')
|
->innerJoin('tags', 'postTags.tagId = tags.id')
|
||||||
->where('tags.name', $tagName);
|
->where('tags.name', $tagName);
|
||||||
$arrayEntities = iterator_to_array($query);
|
$arrayEntities = iterator_to_array($query);
|
||||||
return $this->arrayToEntities($arrayEntities);
|
return $this->arrayToEntities($arrayEntities);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findByContentChecksum($checksum)
|
public function findByContentChecksum($checksum)
|
||||||
{
|
{
|
||||||
return $this->findOneBy('contentChecksum', $checksum);
|
return $this->findOneBy('contentChecksum', $checksum);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function afterLoad(Entity $post)
|
protected function afterLoad(Entity $post)
|
||||||
{
|
{
|
||||||
$post->setLazyLoader(
|
$post->setLazyLoader(
|
||||||
Post::LAZY_LOADER_CONTENT,
|
Post::LAZY_LOADER_CONTENT,
|
||||||
function (Post $post)
|
function (Post $post)
|
||||||
{
|
{
|
||||||
return $this->fileDao->load($post->getContentPath());
|
return $this->fileDao->load($post->getContentPath());
|
||||||
});
|
});
|
||||||
|
|
||||||
$post->setLazyLoader(
|
$post->setLazyLoader(
|
||||||
Post::LAZY_LOADER_THUMBNAIL_SOURCE_CONTENT,
|
Post::LAZY_LOADER_THUMBNAIL_SOURCE_CONTENT,
|
||||||
function (Post $post)
|
function (Post $post)
|
||||||
{
|
{
|
||||||
return $this->fileDao->load($post->getThumbnailSourceContentPath());
|
return $this->fileDao->load($post->getThumbnailSourceContentPath());
|
||||||
});
|
});
|
||||||
|
|
||||||
$post->setLazyLoader(
|
$post->setLazyLoader(
|
||||||
Post::LAZY_LOADER_USER,
|
Post::LAZY_LOADER_USER,
|
||||||
function (Post $post)
|
function (Post $post)
|
||||||
{
|
{
|
||||||
return $this->getUser($post);
|
return $this->getUser($post);
|
||||||
});
|
});
|
||||||
|
|
||||||
$post->setLazyLoader(
|
$post->setLazyLoader(
|
||||||
Post::LAZY_LOADER_TAGS,
|
Post::LAZY_LOADER_TAGS,
|
||||||
function (Post $post)
|
function (Post $post)
|
||||||
{
|
{
|
||||||
return $this->getTags($post);
|
return $this->getTags($post);
|
||||||
});
|
});
|
||||||
|
|
||||||
$post->setLazyLoader(
|
$post->setLazyLoader(
|
||||||
Post::LAZY_LOADER_RELATED_POSTS,
|
Post::LAZY_LOADER_RELATED_POSTS,
|
||||||
function (Post $post)
|
function (Post $post)
|
||||||
{
|
{
|
||||||
return $this->getRelatedPosts($post);
|
return $this->getRelatedPosts($post);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function afterSave(Entity $post)
|
protected function afterSave(Entity $post)
|
||||||
{
|
{
|
||||||
$this->syncContent($post);
|
$this->syncContent($post);
|
||||||
$this->syncThumbnailSourceContent($post);
|
$this->syncThumbnailSourceContent($post);
|
||||||
$this->syncTags($post);
|
$this->syncTags($post);
|
||||||
$this->syncPostRelations($post);
|
$this->syncPostRelations($post);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function decorateQueryFromRequirement($query, Requirement $requirement)
|
protected function decorateQueryFromRequirement($query, Requirement $requirement)
|
||||||
{
|
{
|
||||||
if ($requirement->getType() === PostFilter::REQUIREMENT_TAG)
|
if ($requirement->getType() === PostFilter::REQUIREMENT_TAG)
|
||||||
{
|
{
|
||||||
$tagName = $requirement->getValue()->getValue();
|
$tagName = $requirement->getValue()->getValue();
|
||||||
$tag = $this->tagDao->findByName($tagName);
|
$tag = $this->tagDao->findByName($tagName);
|
||||||
if (!$tag)
|
if (!$tag)
|
||||||
throw new \DomainException('Invalid tag: "' . $tagName . '"');
|
throw new \DomainException('Invalid tag: "' . $tagName . '"');
|
||||||
|
|
||||||
$sql = 'EXISTS (
|
$sql = 'EXISTS (
|
||||||
SELECT 1 FROM postTags
|
SELECT 1 FROM postTags
|
||||||
WHERE postTags.postId = posts.id
|
WHERE postTags.postId = posts.id
|
||||||
AND postTags.tagId = ?)';
|
AND postTags.tagId = ?)';
|
||||||
|
|
||||||
if ($requirement->isNegated())
|
if ($requirement->isNegated())
|
||||||
$sql = 'NOT ' . $sql;
|
$sql = 'NOT ' . $sql;
|
||||||
|
|
||||||
$query->where($sql, $tag->getId());
|
$query->where($sql, $tag->getId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
elseif ($requirement->getType() === PostFilter::REQUIREMENT_FAVORITE)
|
elseif ($requirement->getType() === PostFilter::REQUIREMENT_FAVORITE)
|
||||||
{
|
{
|
||||||
foreach ($requirement->getValue()->getValues() as $userName)
|
foreach ($requirement->getValue()->getValues() as $userName)
|
||||||
{
|
{
|
||||||
$sql = 'EXISTS (
|
$sql = 'EXISTS (
|
||||||
SELECT 1 FROM favorites f
|
SELECT 1 FROM favorites f
|
||||||
WHERE f.postId = posts.id
|
WHERE f.postId = posts.id
|
||||||
AND f.userId = (SELECT id FROM users WHERE name = ?))';
|
AND f.userId = (SELECT id FROM users WHERE name = ?))';
|
||||||
if ($requirement->isNegated())
|
if ($requirement->isNegated())
|
||||||
$sql = 'NOT ' . $sql;
|
$sql = 'NOT ' . $sql;
|
||||||
$query->where($sql, [$userName]);
|
$query->where($sql, [$userName]);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
elseif ($requirement->getType() === PostFilter::REQUIREMENT_COMMENT_AUTHOR)
|
elseif ($requirement->getType() === PostFilter::REQUIREMENT_COMMENT_AUTHOR)
|
||||||
{
|
{
|
||||||
foreach ($requirement->getValue()->getValues() as $userName)
|
foreach ($requirement->getValue()->getValues() as $userName)
|
||||||
{
|
{
|
||||||
$sql = 'EXISTS (
|
$sql = 'EXISTS (
|
||||||
SELECT 1 FROM comments c
|
SELECT 1 FROM comments c
|
||||||
WHERE c.postId = posts.id
|
WHERE c.postId = posts.id
|
||||||
AND c.userId = (SELECT id FROM users WHERE name = ?))';
|
AND c.userId = (SELECT id FROM users WHERE name = ?))';
|
||||||
if ($requirement->isNegated())
|
if ($requirement->isNegated())
|
||||||
$sql = 'NOT ' . $sql;
|
$sql = 'NOT ' . $sql;
|
||||||
$query->where($sql, [$userName]);
|
$query->where($sql, [$userName]);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
elseif ($requirement->getType() === PostFilter::REQUIREMENT_UPLOADER)
|
elseif ($requirement->getType() === PostFilter::REQUIREMENT_UPLOADER)
|
||||||
{
|
{
|
||||||
foreach ($requirement->getValue()->getValues() as $userName)
|
foreach ($requirement->getValue()->getValues() as $userName)
|
||||||
{
|
{
|
||||||
$alias = 'u' . uniqid();
|
$alias = 'u' . uniqid();
|
||||||
$query->innerJoin('users ' . $alias, $alias . '.id = posts.userId');
|
$query->innerJoin('users ' . $alias, $alias . '.id = posts.userId');
|
||||||
$sql = $alias . '.name = ?';
|
$sql = $alias . '.name = ?';
|
||||||
if ($requirement->isNegated())
|
if ($requirement->isNegated())
|
||||||
$sql = 'NOT ' . $sql;
|
$sql = 'NOT ' . $sql;
|
||||||
$query->where($sql, [$userName]);
|
$query->where($sql, [$userName]);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
elseif ($requirement->getType() === PostFilter::REQUIREMENT_USER_SCORE)
|
elseif ($requirement->getType() === PostFilter::REQUIREMENT_USER_SCORE)
|
||||||
{
|
{
|
||||||
$values = $requirement->getValue()->getValues();
|
$values = $requirement->getValue()->getValues();
|
||||||
$userName = $values[0];
|
$userName = $values[0];
|
||||||
$score = $values[1];
|
$score = $values[1];
|
||||||
$sql = 'EXISTS (
|
$sql = 'EXISTS (
|
||||||
SELECT 1 FROM scores
|
SELECT 1 FROM scores
|
||||||
WHERE scores.postId = posts.id
|
WHERE scores.postId = posts.id
|
||||||
AND scores.userId = (SELECT id FROM users WHERE name = ?)
|
AND scores.userId = (SELECT id FROM users WHERE name = ?)
|
||||||
AND scores.score = ?)';
|
AND scores.score = ?)';
|
||||||
if ($requirement->isNegated())
|
if ($requirement->isNegated())
|
||||||
$sql = 'NOT ' . $sql;
|
$sql = 'NOT ' . $sql;
|
||||||
$query->where($sql, [$userName, $score]);
|
$query->where($sql, [$userName, $score]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
parent::decorateQueryFromRequirement($query, $requirement);
|
parent::decorateQueryFromRequirement($query, $requirement);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getTags(Post $post)
|
private function getTags(Post $post)
|
||||||
{
|
{
|
||||||
return $this->tagDao->findByPostId($post->getId());
|
return $this->tagDao->findByPostId($post->getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getUser(Post $post)
|
private function getUser(Post $post)
|
||||||
{
|
{
|
||||||
return $this->userDao->findById($post->getUserId());
|
return $this->userDao->findById($post->getUserId());
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getRelatedPosts(Post $post)
|
private function getRelatedPosts(Post $post)
|
||||||
{
|
{
|
||||||
$relatedPostIds = [];
|
$relatedPostIds = [];
|
||||||
|
|
||||||
foreach ($this->pdo->from('postRelations')->where('post1id', $post->getId()) as $arrayEntity)
|
foreach ($this->pdo->from('postRelations')->where('post1id', $post->getId()) as $arrayEntity)
|
||||||
{
|
{
|
||||||
$postId = intval($arrayEntity['post2id']);
|
$postId = intval($arrayEntity['post2id']);
|
||||||
if ($postId !== $post->getId())
|
if ($postId !== $post->getId())
|
||||||
$relatedPostIds[] = $postId;
|
$relatedPostIds[] = $postId;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($this->pdo->from('postRelations')->where('post2id', $post->getId()) as $arrayEntity)
|
foreach ($this->pdo->from('postRelations')->where('post2id', $post->getId()) as $arrayEntity)
|
||||||
{
|
{
|
||||||
$postId = intval($arrayEntity['post1id']);
|
$postId = intval($arrayEntity['post1id']);
|
||||||
if ($postId !== $post->getId())
|
if ($postId !== $post->getId())
|
||||||
$relatedPostIds[] = $postId;
|
$relatedPostIds[] = $postId;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->findByIds($relatedPostIds);
|
return $this->findByIds($relatedPostIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function syncContent(Post $post)
|
private function syncContent(Post $post)
|
||||||
{
|
{
|
||||||
$targetPath = $post->getContentPath();
|
$targetPath = $post->getContentPath();
|
||||||
$content = $post->getContent();
|
$content = $post->getContent();
|
||||||
if ($content)
|
if ($content)
|
||||||
$this->fileDao->save($targetPath, $content);
|
$this->fileDao->save($targetPath, $content);
|
||||||
else
|
else
|
||||||
$this->fileDao->delete($targetPath, $content);
|
$this->fileDao->delete($targetPath, $content);
|
||||||
$this->thumbnailService->deleteUsedThumbnails($targetPath);
|
$this->thumbnailService->deleteUsedThumbnails($targetPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function syncThumbnailSourceContent(Post $post)
|
private function syncThumbnailSourceContent(Post $post)
|
||||||
{
|
{
|
||||||
$targetPath = $post->getThumbnailSourceContentPath();
|
$targetPath = $post->getThumbnailSourceContentPath();
|
||||||
$content = $post->getThumbnailSourceContent();
|
$content = $post->getThumbnailSourceContent();
|
||||||
if ($content)
|
if ($content)
|
||||||
$this->fileDao->save($targetPath, $content);
|
$this->fileDao->save($targetPath, $content);
|
||||||
else
|
else
|
||||||
$this->fileDao->delete($targetPath);
|
$this->fileDao->delete($targetPath);
|
||||||
$this->thumbnailService->deleteUsedThumbnails($targetPath);
|
$this->thumbnailService->deleteUsedThumbnails($targetPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function syncTags(Post $post)
|
private function syncTags(Post $post)
|
||||||
{
|
{
|
||||||
$tagIds = array_map(
|
$tagIds = array_map(
|
||||||
function ($tag)
|
function ($tag)
|
||||||
{
|
{
|
||||||
if (!$tag->getId())
|
if (!$tag->getId())
|
||||||
throw new \RuntimeException('Unsaved entities found');
|
throw new \RuntimeException('Unsaved entities found');
|
||||||
return $tag->getId();
|
return $tag->getId();
|
||||||
},
|
},
|
||||||
$post->getTags());
|
$post->getTags());
|
||||||
|
|
||||||
$existingTagRelationIds = array_map(
|
$existingTagRelationIds = array_map(
|
||||||
function ($arrayEntity)
|
function ($arrayEntity)
|
||||||
{
|
{
|
||||||
return $arrayEntity['tagId'];
|
return $arrayEntity['tagId'];
|
||||||
},
|
},
|
||||||
iterator_to_array($this->pdo->from('postTags')->where('postId', $post->getId())));
|
iterator_to_array($this->pdo->from('postTags')->where('postId', $post->getId())));
|
||||||
|
|
||||||
$tagRelationsToInsert = array_diff($tagIds, $existingTagRelationIds);
|
$tagRelationsToInsert = array_diff($tagIds, $existingTagRelationIds);
|
||||||
$tagRelationsToDelete = array_diff($existingTagRelationIds, $tagIds);
|
$tagRelationsToDelete = array_diff($existingTagRelationIds, $tagIds);
|
||||||
|
|
||||||
foreach ($tagRelationsToInsert as $tagId)
|
foreach ($tagRelationsToInsert as $tagId)
|
||||||
{
|
{
|
||||||
$this->pdo->insertInto('postTags')->values(['postId' => $post->getId(), 'tagId' => $tagId])->execute();
|
$this->pdo->insertInto('postTags')->values(['postId' => $post->getId(), 'tagId' => $tagId])->execute();
|
||||||
}
|
}
|
||||||
foreach ($tagRelationsToDelete as $tagId)
|
foreach ($tagRelationsToDelete as $tagId)
|
||||||
{
|
{
|
||||||
$this->pdo->deleteFrom('postTags')->where('postId', $post->getId())->where('tagId', $tagId)->execute();
|
$this->pdo->deleteFrom('postTags')->where('postId', $post->getId())->where('tagId', $tagId)->execute();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function syncPostRelations(Post $post)
|
private function syncPostRelations(Post $post)
|
||||||
{
|
{
|
||||||
$relatedPostIds = array_filter(array_unique(array_map(
|
$relatedPostIds = array_filter(array_unique(array_map(
|
||||||
function ($post)
|
function ($post)
|
||||||
{
|
{
|
||||||
if (!$post->getId())
|
if (!$post->getId())
|
||||||
throw new \RuntimeException('Unsaved entities found');
|
throw new \RuntimeException('Unsaved entities found');
|
||||||
return $post->getId();
|
return $post->getId();
|
||||||
},
|
},
|
||||||
$post->getRelatedPosts())));
|
$post->getRelatedPosts())));
|
||||||
|
|
||||||
$this->pdo->deleteFrom('postRelations')->where('post1id', $post->getId())->execute();
|
$this->pdo->deleteFrom('postRelations')->where('post1id', $post->getId())->execute();
|
||||||
$this->pdo->deleteFrom('postRelations')->where('post2id', $post->getId())->execute();
|
$this->pdo->deleteFrom('postRelations')->where('post2id', $post->getId())->execute();
|
||||||
foreach ($relatedPostIds as $postId)
|
foreach ($relatedPostIds as $postId)
|
||||||
{
|
{
|
||||||
$this->pdo
|
$this->pdo
|
||||||
->insertInto('postRelations')
|
->insertInto('postRelations')
|
||||||
->values([
|
->values([
|
||||||
'post1id' => $post->getId(),
|
'post1id' => $post->getId(),
|
||||||
'post2id' => $postId])
|
'post2id' => $postId])
|
||||||
->execute();
|
->execute();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,32 +8,32 @@ use Szurubooru\Entities\PostNote;
|
||||||
|
|
||||||
class PostNoteDao extends AbstractDao implements ICrudDao
|
class PostNoteDao extends AbstractDao implements ICrudDao
|
||||||
{
|
{
|
||||||
private $postDao;
|
private $postDao;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
DatabaseConnection $databaseConnection,
|
DatabaseConnection $databaseConnection,
|
||||||
PostDao $postDao)
|
PostDao $postDao)
|
||||||
{
|
{
|
||||||
parent::__construct(
|
parent::__construct(
|
||||||
$databaseConnection,
|
$databaseConnection,
|
||||||
'postNotes',
|
'postNotes',
|
||||||
new PostNoteEntityConverter());
|
new PostNoteEntityConverter());
|
||||||
|
|
||||||
$this->postDao = $postDao;
|
$this->postDao = $postDao;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findByPostId($postId)
|
public function findByPostId($postId)
|
||||||
{
|
{
|
||||||
return $this->findBy('postId', $postId);
|
return $this->findBy('postId', $postId);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function afterLoad(Entity $postNote)
|
protected function afterLoad(Entity $postNote)
|
||||||
{
|
{
|
||||||
$postNote->setLazyLoader(
|
$postNote->setLazyLoader(
|
||||||
PostNote::LAZY_LOADER_POST,
|
PostNote::LAZY_LOADER_POST,
|
||||||
function (PostNote $postNote)
|
function (PostNote $postNote)
|
||||||
{
|
{
|
||||||
return $this->postDao->findById($postNote->getPostId());
|
return $this->postDao->findById($postNote->getPostId());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,8 @@ use Szurubooru\Dao\IFileDao;
|
||||||
|
|
||||||
class PublicFileDao extends FileDao implements IFileDao
|
class PublicFileDao extends FileDao implements IFileDao
|
||||||
{
|
{
|
||||||
public function __construct(Config $config)
|
public function __construct(Config $config)
|
||||||
{
|
{
|
||||||
parent::__construct($config->getPublicDataDirectory());
|
parent::__construct($config->getPublicDataDirectory());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,70 +11,70 @@ use Szurubooru\Services\TimeService;
|
||||||
|
|
||||||
class ScoreDao extends AbstractDao implements ICrudDao
|
class ScoreDao extends AbstractDao implements ICrudDao
|
||||||
{
|
{
|
||||||
private $timeService;
|
private $timeService;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
DatabaseConnection $databaseConnection,
|
DatabaseConnection $databaseConnection,
|
||||||
TimeService $timeService)
|
TimeService $timeService)
|
||||||
{
|
{
|
||||||
parent::__construct(
|
parent::__construct(
|
||||||
$databaseConnection,
|
$databaseConnection,
|
||||||
'scores',
|
'scores',
|
||||||
new ScoreEntityConverter());
|
new ScoreEntityConverter());
|
||||||
|
|
||||||
$this->timeService = $timeService;
|
$this->timeService = $timeService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getScoreValue(Entity $entity)
|
public function getScoreValue(Entity $entity)
|
||||||
{
|
{
|
||||||
$query = $this->getBaseQuery($entity);
|
$query = $this->getBaseQuery($entity);
|
||||||
$query->select(null);
|
$query->select(null);
|
||||||
$query->select('SUM(score) AS score');
|
$query->select('SUM(score) AS score');
|
||||||
return iterator_to_array($query)[0]['score'];
|
return iterator_to_array($query)[0]['score'];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUserScore(User $user, Entity $entity)
|
public function getUserScore(User $user, Entity $entity)
|
||||||
{
|
{
|
||||||
$query = $this->getBaseQuery($entity);
|
$query = $this->getBaseQuery($entity);
|
||||||
$query->where('userId', $user->getId());
|
$query->where('userId', $user->getId());
|
||||||
|
|
||||||
$arrayEntities = iterator_to_array($query);
|
$arrayEntities = iterator_to_array($query);
|
||||||
$entities = $this->arrayToEntities($arrayEntities);
|
$entities = $this->arrayToEntities($arrayEntities);
|
||||||
return array_shift($entities);
|
return array_shift($entities);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setUserScore(User $user, Entity $entity, $scoreValue)
|
public function setUserScore(User $user, Entity $entity, $scoreValue)
|
||||||
{
|
{
|
||||||
$score = $this->getUserScore($user, $entity);
|
$score = $this->getUserScore($user, $entity);
|
||||||
if (!$score)
|
if (!$score)
|
||||||
{
|
{
|
||||||
$score = new Score();
|
$score = new Score();
|
||||||
$score->setTime($this->timeService->getCurrentTime());
|
$score->setTime($this->timeService->getCurrentTime());
|
||||||
$score->setUserId($user->getId());
|
$score->setUserId($user->getId());
|
||||||
|
|
||||||
if ($entity instanceof Post)
|
if ($entity instanceof Post)
|
||||||
$score->setPostId($entity->getId());
|
$score->setPostId($entity->getId());
|
||||||
elseif ($entity instanceof Comment)
|
elseif ($entity instanceof Comment)
|
||||||
$score->setCommentId($entity->getId());
|
$score->setCommentId($entity->getId());
|
||||||
else
|
else
|
||||||
throw new \InvalidArgumentException();
|
throw new \InvalidArgumentException();
|
||||||
}
|
}
|
||||||
$score->setScore($scoreValue);
|
$score->setScore($scoreValue);
|
||||||
$this->save($score);
|
$this->save($score);
|
||||||
return $score;
|
return $score;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getBaseQuery($entity)
|
private function getBaseQuery($entity)
|
||||||
{
|
{
|
||||||
$query = $this->pdo->from($this->tableName);
|
$query = $this->pdo->from($this->tableName);
|
||||||
|
|
||||||
if ($entity instanceof Post)
|
if ($entity instanceof Post)
|
||||||
$query->where('postId', $entity->getId());
|
$query->where('postId', $entity->getId());
|
||||||
elseif ($entity instanceof Comment)
|
elseif ($entity instanceof Comment)
|
||||||
$query->where('commentId', $entity->getId());
|
$query->where('commentId', $entity->getId());
|
||||||
else
|
else
|
||||||
throw new \InvalidArgumentException();
|
throw new \InvalidArgumentException();
|
||||||
|
|
||||||
return $query;
|
return $query;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,47 +8,47 @@ use Szurubooru\Entities\Snapshot;
|
||||||
|
|
||||||
class SnapshotDao extends AbstractDao
|
class SnapshotDao extends AbstractDao
|
||||||
{
|
{
|
||||||
private $userDao;
|
private $userDao;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
DatabaseConnection $databaseConnection,
|
DatabaseConnection $databaseConnection,
|
||||||
UserDao $userDao)
|
UserDao $userDao)
|
||||||
{
|
{
|
||||||
parent::__construct(
|
parent::__construct(
|
||||||
$databaseConnection,
|
$databaseConnection,
|
||||||
'snapshots',
|
'snapshots',
|
||||||
new SnapshotEntityConverter());
|
new SnapshotEntityConverter());
|
||||||
|
|
||||||
$this->userDao = $userDao;
|
$this->userDao = $userDao;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findEarlierSnapshots(Snapshot $snapshot)
|
public function findEarlierSnapshots(Snapshot $snapshot)
|
||||||
{
|
{
|
||||||
$query = $this->pdo
|
$query = $this->pdo
|
||||||
->from($this->tableName)
|
->from($this->tableName)
|
||||||
->where('type', $snapshot->getType())
|
->where('type', $snapshot->getType())
|
||||||
->where('primaryKey', $snapshot->getPrimaryKey())
|
->where('primaryKey', $snapshot->getPrimaryKey())
|
||||||
->orderBy('time DESC');
|
->orderBy('time DESC');
|
||||||
|
|
||||||
if ($snapshot->getId())
|
if ($snapshot->getId())
|
||||||
$query->where('id < ?', $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)
|
public function afterLoad(Entity $snapshot)
|
||||||
{
|
{
|
||||||
$snapshot->setLazyLoader(
|
$snapshot->setLazyLoader(
|
||||||
Snapshot::LAZY_LOADER_USER,
|
Snapshot::LAZY_LOADER_USER,
|
||||||
function (Snapshot $snapshot)
|
function (Snapshot $snapshot)
|
||||||
{
|
{
|
||||||
return $this->getUser($snapshot);
|
return $this->getUser($snapshot);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getUser(Snapshot $snapshot)
|
private function getUser(Snapshot $snapshot)
|
||||||
{
|
{
|
||||||
$userId = $snapshot->getUserId();
|
$userId = $snapshot->getUserId();
|
||||||
return $this->userDao->findById($userId);
|
return $this->userDao->findById($userId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,213 +10,213 @@ use Szurubooru\Search\Requirements\Requirement;
|
||||||
|
|
||||||
class TagDao extends AbstractDao implements ICrudDao
|
class TagDao extends AbstractDao implements ICrudDao
|
||||||
{
|
{
|
||||||
const TAG_RELATION_IMPLICATION = 1;
|
const TAG_RELATION_IMPLICATION = 1;
|
||||||
const TAG_RELATION_SUGGESTION = 2;
|
const TAG_RELATION_SUGGESTION = 2;
|
||||||
|
|
||||||
public function __construct(DatabaseConnection $databaseConnection)
|
public function __construct(DatabaseConnection $databaseConnection)
|
||||||
{
|
{
|
||||||
parent::__construct(
|
parent::__construct(
|
||||||
$databaseConnection,
|
$databaseConnection,
|
||||||
'tags',
|
'tags',
|
||||||
new TagEntityConverter());
|
new TagEntityConverter());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findByName($tagName)
|
public function findByName($tagName)
|
||||||
{
|
{
|
||||||
return $this->findOneBy('name', $tagName);
|
return $this->findOneBy('name', $tagName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findByNames($tagNames)
|
public function findByNames($tagNames)
|
||||||
{
|
{
|
||||||
return $this->findBy('name', $tagNames);
|
return $this->findBy('name', $tagNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findByPostId($postId)
|
public function findByPostId($postId)
|
||||||
{
|
{
|
||||||
return $this->findByPostIds([$postId]);
|
return $this->findByPostIds([$postId]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findByPostIds($postIds)
|
public function findByPostIds($postIds)
|
||||||
{
|
{
|
||||||
$query = $this->pdo->from($this->tableName)
|
$query = $this->pdo->from($this->tableName)
|
||||||
->innerJoin('postTags', 'postTags.tagId = tags.id')
|
->innerJoin('postTags', 'postTags.tagId = tags.id')
|
||||||
->where('postTags.postId', $postIds);
|
->where('postTags.postId', $postIds);
|
||||||
$arrayEntities = iterator_to_array($query);
|
$arrayEntities = iterator_to_array($query);
|
||||||
return $this->arrayToEntities($arrayEntities);
|
return $this->arrayToEntities($arrayEntities);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findSiblings($tagName)
|
public function findSiblings($tagName)
|
||||||
{
|
{
|
||||||
$tag = $this->findByName($tagName);
|
$tag = $this->findByName($tagName);
|
||||||
if (!$tag)
|
if (!$tag)
|
||||||
return [];
|
return [];
|
||||||
$tagId = $tag->getId();
|
$tagId = $tag->getId();
|
||||||
$query = $this->pdo->from($this->tableName)
|
$query = $this->pdo->from($this->tableName)
|
||||||
->select('COUNT(pt2.postId) AS postCount')
|
->select('COUNT(pt2.postId) AS postCount')
|
||||||
->innerJoin('postTags pt1', 'pt1.tagId = tags.id')
|
->innerJoin('postTags pt1', 'pt1.tagId = tags.id')
|
||||||
->innerJoin('postTags pt2', 'pt2.postId = pt1.postId')
|
->innerJoin('postTags pt2', 'pt2.postId = pt1.postId')
|
||||||
->where('pt2.tagId', $tagId)
|
->where('pt2.tagId', $tagId)
|
||||||
->groupBy('tags.id')
|
->groupBy('tags.id')
|
||||||
->orderBy('postCount DESC, name ASC');
|
->orderBy('postCount DESC, name ASC');
|
||||||
|
|
||||||
$arrayEntities = array_filter(
|
$arrayEntities = array_filter(
|
||||||
iterator_to_array($query),
|
iterator_to_array($query),
|
||||||
function($arrayEntity) use ($tagName)
|
function($arrayEntity) use ($tagName)
|
||||||
{
|
{
|
||||||
return strcasecmp($arrayEntity['name'], $tagName) !== 0;
|
return strcasecmp($arrayEntity['name'], $tagName) !== 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
return $this->arrayToEntities($arrayEntities);
|
return $this->arrayToEntities($arrayEntities);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function export()
|
public function export()
|
||||||
{
|
{
|
||||||
$exported = [];
|
$exported = [];
|
||||||
foreach ($this->pdo->from($this->tableName) as $arrayEntity)
|
foreach ($this->pdo->from($this->tableName) as $arrayEntity)
|
||||||
{
|
{
|
||||||
$exported[$arrayEntity['id']] = [
|
$exported[$arrayEntity['id']] = [
|
||||||
'name' => $arrayEntity['name'],
|
'name' => $arrayEntity['name'],
|
||||||
'usages' => intval($arrayEntity['usages']),
|
'usages' => intval($arrayEntity['usages']),
|
||||||
'banned' => boolval($arrayEntity['banned'])
|
'banned' => boolval($arrayEntity['banned'])
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
//upgrades on old databases
|
//upgrades on old databases
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
$relations = iterator_to_array($this->pdo->from('tagRelations'));
|
$relations = iterator_to_array($this->pdo->from('tagRelations'));
|
||||||
}
|
}
|
||||||
catch (\Exception $e)
|
catch (\Exception $e)
|
||||||
{
|
{
|
||||||
$relations = [];
|
$relations = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($relations as $arrayEntity)
|
foreach ($relations as $arrayEntity)
|
||||||
{
|
{
|
||||||
$key1 = $arrayEntity['tag1id'];
|
$key1 = $arrayEntity['tag1id'];
|
||||||
$key2 = $arrayEntity['tag2id'];
|
$key2 = $arrayEntity['tag2id'];
|
||||||
$type = intval($arrayEntity['type']);
|
$type = intval($arrayEntity['type']);
|
||||||
if ($type === self::TAG_RELATION_IMPLICATION)
|
if ($type === self::TAG_RELATION_IMPLICATION)
|
||||||
$target = 'implications';
|
$target = 'implications';
|
||||||
elseif ($type === self::TAG_RELATION_SUGGESTION)
|
elseif ($type === self::TAG_RELATION_SUGGESTION)
|
||||||
$target = 'suggestions';
|
$target = 'suggestions';
|
||||||
else
|
else
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!isset($exported[$key1]) || !isset($exported[$key2]))
|
if (!isset($exported[$key1]) || !isset($exported[$key2]))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!isset($exported[$key1][$target]))
|
if (!isset($exported[$key1][$target]))
|
||||||
$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)
|
protected function afterLoad(Entity $tag)
|
||||||
{
|
{
|
||||||
$tag->setLazyLoader(
|
$tag->setLazyLoader(
|
||||||
Tag::LAZY_LOADER_IMPLIED_TAGS,
|
Tag::LAZY_LOADER_IMPLIED_TAGS,
|
||||||
function (Tag $tag)
|
function (Tag $tag)
|
||||||
{
|
{
|
||||||
return $this->findImpliedTags($tag);
|
return $this->findImpliedTags($tag);
|
||||||
});
|
});
|
||||||
|
|
||||||
$tag->setLazyLoader(
|
$tag->setLazyLoader(
|
||||||
Tag::LAZY_LOADER_SUGGESTED_TAGS,
|
Tag::LAZY_LOADER_SUGGESTED_TAGS,
|
||||||
function (Tag $tag)
|
function (Tag $tag)
|
||||||
{
|
{
|
||||||
return $this->findSuggested($tag);
|
return $this->findSuggested($tag);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function afterSave(Entity $tag)
|
protected function afterSave(Entity $tag)
|
||||||
{
|
{
|
||||||
$this->syncImpliedTags($tag);
|
$this->syncImpliedTags($tag);
|
||||||
$this->syncSuggestedTags($tag);
|
$this->syncSuggestedTags($tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function decorateQueryFromRequirement($query, Requirement $requirement)
|
protected function decorateQueryFromRequirement($query, Requirement $requirement)
|
||||||
{
|
{
|
||||||
if ($requirement->getType() === TagFilter::REQUIREMENT_PARTIAL_TAG_NAME)
|
if ($requirement->getType() === TagFilter::REQUIREMENT_PARTIAL_TAG_NAME)
|
||||||
{
|
{
|
||||||
$sql = 'INSTR(LOWER(tags.name), LOWER(?)) > 0';
|
$sql = 'INSTR(LOWER(tags.name), LOWER(?)) > 0';
|
||||||
|
|
||||||
if ($requirement->isNegated())
|
if ($requirement->isNegated())
|
||||||
$sql = 'NOT ' . $sql;
|
$sql = 'NOT ' . $sql;
|
||||||
|
|
||||||
$query->where($sql, $requirement->getValue()->getValue());
|
$query->where($sql, $requirement->getValue()->getValue());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
elseif ($requirement->getType() === TagFilter::REQUIREMENT_CATEGORY)
|
elseif ($requirement->getType() === TagFilter::REQUIREMENT_CATEGORY)
|
||||||
{
|
{
|
||||||
$sql = 'IFNULL(category, \'default\')';
|
$sql = 'IFNULL(category, \'default\')';
|
||||||
$requirement->setType($sql);
|
$requirement->setType($sql);
|
||||||
return parent::decorateQueryFromRequirement($query, $requirement);
|
return parent::decorateQueryFromRequirement($query, $requirement);
|
||||||
}
|
}
|
||||||
|
|
||||||
parent::decorateQueryFromRequirement($query, $requirement);
|
parent::decorateQueryFromRequirement($query, $requirement);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function findImpliedTags(Tag $tag)
|
private function findImpliedTags(Tag $tag)
|
||||||
{
|
{
|
||||||
return $this->findRelatedTagsByType($tag, self::TAG_RELATION_IMPLICATION);
|
return $this->findRelatedTagsByType($tag, self::TAG_RELATION_IMPLICATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function findSuggested(Tag $tag)
|
private function findSuggested(Tag $tag)
|
||||||
{
|
{
|
||||||
return $this->findRelatedTagsByType($tag, self::TAG_RELATION_SUGGESTION);
|
return $this->findRelatedTagsByType($tag, self::TAG_RELATION_SUGGESTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function syncImpliedTags($tag)
|
private function syncImpliedTags($tag)
|
||||||
{
|
{
|
||||||
$this->syncRelatedTagsByType($tag, $tag->getImpliedTags(), self::TAG_RELATION_IMPLICATION);
|
$this->syncRelatedTagsByType($tag, $tag->getImpliedTags(), self::TAG_RELATION_IMPLICATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function syncSuggestedTags($tag)
|
private function syncSuggestedTags($tag)
|
||||||
{
|
{
|
||||||
$this->syncRelatedTagsByType($tag, $tag->getSuggestedTags(), self::TAG_RELATION_SUGGESTION);
|
$this->syncRelatedTagsByType($tag, $tag->getSuggestedTags(), self::TAG_RELATION_SUGGESTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function syncRelatedTagsByType(Tag $tag, array $relatedTags, $type)
|
private function syncRelatedTagsByType(Tag $tag, array $relatedTags, $type)
|
||||||
{
|
{
|
||||||
$relatedTagIds = array_filter(array_unique(array_map(
|
$relatedTagIds = array_filter(array_unique(array_map(
|
||||||
function ($tag)
|
function ($tag)
|
||||||
{
|
{
|
||||||
if (!$tag->getId())
|
if (!$tag->getId())
|
||||||
throw new \RuntimeException('Unsaved entities found');
|
throw new \RuntimeException('Unsaved entities found');
|
||||||
return $tag->getId();
|
return $tag->getId();
|
||||||
},
|
},
|
||||||
$relatedTags)));
|
$relatedTags)));
|
||||||
|
|
||||||
$this->pdo->deleteFrom('tagRelations')
|
$this->pdo->deleteFrom('tagRelations')
|
||||||
->where('tag1id', $tag->getId())
|
->where('tag1id', $tag->getId())
|
||||||
->where('type', $type)
|
->where('type', $type)
|
||||||
->execute();
|
->execute();
|
||||||
|
|
||||||
foreach ($relatedTagIds as $tagId)
|
foreach ($relatedTagIds as $tagId)
|
||||||
{
|
{
|
||||||
$this->pdo
|
$this->pdo
|
||||||
->insertInto('tagRelations')
|
->insertInto('tagRelations')
|
||||||
->values([
|
->values([
|
||||||
'tag1id' => $tag->getId(),
|
'tag1id' => $tag->getId(),
|
||||||
'tag2id' => $tagId,
|
'tag2id' => $tagId,
|
||||||
'type' => $type])
|
'type' => $type])
|
||||||
->execute();
|
->execute();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function findRelatedTagsByType(Tag $tag, $type)
|
private function findRelatedTagsByType(Tag $tag, $type)
|
||||||
{
|
{
|
||||||
$tagId = $tag->getId();
|
$tagId = $tag->getId();
|
||||||
$query = $this->pdo->from($this->tableName)
|
$query = $this->pdo->from($this->tableName)
|
||||||
->innerJoin('tagRelations tr', 'tags.id = tr.tag2id')
|
->innerJoin('tagRelations tr', 'tags.id = tr.tag2id')
|
||||||
->where('tr.type', $type)
|
->where('tr.type', $type)
|
||||||
->where('tr.tag1id', $tagId);
|
->where('tr.tag1id', $tagId);
|
||||||
$arrayEntities = iterator_to_array($query);
|
$arrayEntities = iterator_to_array($query);
|
||||||
return $this->arrayToEntities($arrayEntities);
|
return $this->arrayToEntities($arrayEntities);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,39 +5,39 @@ use Szurubooru\DatabaseConnection;
|
||||||
|
|
||||||
class TokenDao extends AbstractDao
|
class TokenDao extends AbstractDao
|
||||||
{
|
{
|
||||||
public function __construct(DatabaseConnection $databaseConnection)
|
public function __construct(DatabaseConnection $databaseConnection)
|
||||||
{
|
{
|
||||||
parent::__construct(
|
parent::__construct(
|
||||||
$databaseConnection,
|
$databaseConnection,
|
||||||
'tokens',
|
'tokens',
|
||||||
new TokenEntityConverter());
|
new TokenEntityConverter());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findByName($tokenName)
|
public function findByName($tokenName)
|
||||||
{
|
{
|
||||||
return $this->findOneBy('name', $tokenName);
|
return $this->findOneBy('name', $tokenName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findByAdditionalDataAndPurpose($additionalData, $purpose)
|
public function findByAdditionalDataAndPurpose($additionalData, $purpose)
|
||||||
{
|
{
|
||||||
$query = $this->pdo->from($this->tableName)
|
$query = $this->pdo->from($this->tableName)
|
||||||
->where('additionalData', $additionalData)
|
->where('additionalData', $additionalData)
|
||||||
->where('purpose', $purpose);
|
->where('purpose', $purpose);
|
||||||
$arrayEntities = iterator_to_array($query);
|
$arrayEntities = iterator_to_array($query);
|
||||||
$entities = $this->arrayToEntities($arrayEntities);
|
$entities = $this->arrayToEntities($arrayEntities);
|
||||||
if (!$entities || !count($entities))
|
if (!$entities || !count($entities))
|
||||||
return null;
|
return null;
|
||||||
$entity = array_shift($entities);
|
$entity = array_shift($entities);
|
||||||
return $entity;
|
return $entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function deleteByName($tokenName)
|
public function deleteByName($tokenName)
|
||||||
{
|
{
|
||||||
return $this->deleteBy('name', $tokenName);
|
return $this->deleteBy('name', $tokenName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function deleteByAdditionalData($additionalData)
|
public function deleteByAdditionalData($additionalData)
|
||||||
{
|
{
|
||||||
return $this->deleteBy('additionalData', $additionalData);
|
return $this->deleteBy('additionalData', $additionalData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,40 +4,40 @@ use Szurubooru\DatabaseConnection;
|
||||||
|
|
||||||
class TransactionManager
|
class TransactionManager
|
||||||
{
|
{
|
||||||
private $databaseConnection;
|
private $databaseConnection;
|
||||||
|
|
||||||
public function __construct(DatabaseConnection $databaseConnection)
|
public function __construct(DatabaseConnection $databaseConnection)
|
||||||
{
|
{
|
||||||
$this->databaseConnection = $databaseConnection;
|
$this->databaseConnection = $databaseConnection;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function commit($callback)
|
public function commit($callback)
|
||||||
{
|
{
|
||||||
return $this->doInTransaction($callback, 'commit');
|
return $this->doInTransaction($callback, 'commit');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function rollback($callback)
|
public function rollback($callback)
|
||||||
{
|
{
|
||||||
return $this->doInTransaction($callback, 'rollBack');
|
return $this->doInTransaction($callback, 'rollBack');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function doInTransaction($callback, $operation)
|
public function doInTransaction($callback, $operation)
|
||||||
{
|
{
|
||||||
$pdo = $this->databaseConnection->getPDO();
|
$pdo = $this->databaseConnection->getPDO();
|
||||||
if ($pdo->inTransaction())
|
if ($pdo->inTransaction())
|
||||||
return $callback();
|
return $callback();
|
||||||
|
|
||||||
$pdo->beginTransaction();
|
$pdo->beginTransaction();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
$ret = $callback();
|
$ret = $callback();
|
||||||
$pdo->$operation();
|
$pdo->$operation();
|
||||||
return $ret;
|
return $ret;
|
||||||
}
|
}
|
||||||
catch (\Exception $e)
|
catch (\Exception $e)
|
||||||
{
|
{
|
||||||
$pdo->rollBack();
|
$pdo->rollBack();
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,78 +9,78 @@ use Szurubooru\Services\ThumbnailService;
|
||||||
|
|
||||||
class UserDao extends AbstractDao implements ICrudDao
|
class UserDao extends AbstractDao implements ICrudDao
|
||||||
{
|
{
|
||||||
const ORDER_NAME = 'name';
|
const ORDER_NAME = 'name';
|
||||||
const ORDER_REGISTRATION_TIME = 'registrationTime';
|
const ORDER_REGISTRATION_TIME = 'registrationTime';
|
||||||
|
|
||||||
private $fileDao;
|
private $fileDao;
|
||||||
private $thumbnailService;
|
private $thumbnailService;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
DatabaseConnection $databaseConnection,
|
DatabaseConnection $databaseConnection,
|
||||||
PublicFileDao $fileDao,
|
PublicFileDao $fileDao,
|
||||||
ThumbnailService $thumbnailService)
|
ThumbnailService $thumbnailService)
|
||||||
{
|
{
|
||||||
parent::__construct(
|
parent::__construct(
|
||||||
$databaseConnection,
|
$databaseConnection,
|
||||||
'users',
|
'users',
|
||||||
new UserEntityConverter());
|
new UserEntityConverter());
|
||||||
|
|
||||||
$this->fileDao = $fileDao;
|
$this->fileDao = $fileDao;
|
||||||
$this->thumbnailService = $thumbnailService;
|
$this->thumbnailService = $thumbnailService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findByName($userName)
|
public function findByName($userName)
|
||||||
{
|
{
|
||||||
return $this->findOneBy('name', $userName);
|
return $this->findOneBy('name', $userName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findByEmail($userEmail, $allowUnconfirmed = false)
|
public function findByEmail($userEmail, $allowUnconfirmed = false)
|
||||||
{
|
{
|
||||||
$result = $this->findOneBy('email', $userEmail);
|
$result = $this->findOneBy('email', $userEmail);
|
||||||
if (!$result && $allowUnconfirmed)
|
if (!$result && $allowUnconfirmed)
|
||||||
{
|
{
|
||||||
$result = $this->findOneBy('emailUnconfirmed', $userEmail);
|
$result = $this->findOneBy('emailUnconfirmed', $userEmail);
|
||||||
}
|
}
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function hasAnyUsers()
|
public function hasAnyUsers()
|
||||||
{
|
{
|
||||||
return $this->hasAnyRecords();
|
return $this->hasAnyRecords();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function deleteByName($userName)
|
public function deleteByName($userName)
|
||||||
{
|
{
|
||||||
$this->deleteBy('name', $userName);
|
$this->deleteBy('name', $userName);
|
||||||
$this->pdo->deleteFrom('tokens')->where('additionalData', $userName);
|
$this->pdo->deleteFrom('tokens')->where('additionalData', $userName);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function afterLoad(Entity $user)
|
protected function afterLoad(Entity $user)
|
||||||
{
|
{
|
||||||
$user->setLazyLoader(
|
$user->setLazyLoader(
|
||||||
User::LAZY_LOADER_CUSTOM_AVATAR_SOURCE_CONTENT,
|
User::LAZY_LOADER_CUSTOM_AVATAR_SOURCE_CONTENT,
|
||||||
function(User $user)
|
function(User $user)
|
||||||
{
|
{
|
||||||
$avatarSource = $user->getCustomAvatarSourceContentPath();
|
$avatarSource = $user->getCustomAvatarSourceContentPath();
|
||||||
return $this->fileDao->load($avatarSource);
|
return $this->fileDao->load($avatarSource);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function afterSave(Entity $user)
|
protected function afterSave(Entity $user)
|
||||||
{
|
{
|
||||||
$targetPath = $user->getCustomAvatarSourceContentPath();
|
$targetPath = $user->getCustomAvatarSourceContentPath();
|
||||||
$content = $user->getCustomAvatarSourceContent();
|
$content = $user->getCustomAvatarSourceContent();
|
||||||
if ($content)
|
if ($content)
|
||||||
$this->fileDao->save($targetPath, $content);
|
$this->fileDao->save($targetPath, $content);
|
||||||
else
|
else
|
||||||
$this->fileDao->delete($targetPath);
|
$this->fileDao->delete($targetPath);
|
||||||
$this->thumbnailService->deleteUsedThumbnails($targetPath);
|
$this->thumbnailService->deleteUsedThumbnails($targetPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function afterDelete(Entity $user)
|
protected function afterDelete(Entity $user)
|
||||||
{
|
{
|
||||||
$avatarSource = $user->getCustomAvatarSourceContentPath();
|
$avatarSource = $user->getCustomAvatarSourceContentPath();
|
||||||
$this->fileDao->delete($avatarSource);
|
$this->fileDao->delete($avatarSource);
|
||||||
$this->thumbnailService->deleteUsedThumbnails($avatarSource);
|
$this->thumbnailService->deleteUsedThumbnails($avatarSource);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,45 +5,45 @@ use Szurubooru\PDOEx\PDOEx;
|
||||||
|
|
||||||
class DatabaseConnection
|
class DatabaseConnection
|
||||||
{
|
{
|
||||||
private $pdo;
|
private $pdo;
|
||||||
private $config;
|
private $config;
|
||||||
|
|
||||||
public function __construct(Config $config)
|
public function __construct(Config $config)
|
||||||
{
|
{
|
||||||
$this->config = $config;
|
$this->config = $config;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPDO()
|
public function getPDO()
|
||||||
{
|
{
|
||||||
if (!$this->pdo)
|
if (!$this->pdo)
|
||||||
{
|
{
|
||||||
$this->createPDO();
|
$this->createPDO();
|
||||||
}
|
}
|
||||||
return $this->pdo;
|
return $this->pdo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDriver()
|
public function getDriver()
|
||||||
{
|
{
|
||||||
return $this->getPDO()->getAttribute(\PDO::ATTR_DRIVER_NAME);
|
return $this->getPDO()->getAttribute(\PDO::ATTR_DRIVER_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function close()
|
public function close()
|
||||||
{
|
{
|
||||||
$this->pdo = null;
|
$this->pdo = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function createPDO()
|
private function createPDO()
|
||||||
{
|
{
|
||||||
$cwd = getcwd();
|
$cwd = getcwd();
|
||||||
if ($this->config->getDataDirectory())
|
if ($this->config->getDataDirectory())
|
||||||
chdir($this->config->getDataDirectory());
|
chdir($this->config->getDataDirectory());
|
||||||
|
|
||||||
$this->pdo = new PDOEx(
|
$this->pdo = new PDOEx(
|
||||||
$this->config->database->dsn,
|
$this->config->database->dsn,
|
||||||
$this->config->database->user,
|
$this->config->database->user,
|
||||||
$this->config->database->password);
|
$this->config->database->password);
|
||||||
|
|
||||||
$this->pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
|
$this->pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
|
||||||
chdir($cwd);
|
chdir($cwd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,78 +10,78 @@ use Szurubooru\Services\TokenService;
|
||||||
|
|
||||||
final class Dispatcher
|
final class Dispatcher
|
||||||
{
|
{
|
||||||
private $router;
|
private $router;
|
||||||
private $config;
|
private $config;
|
||||||
private $databaseConnection;
|
private $databaseConnection;
|
||||||
private $authService;
|
private $authService;
|
||||||
private $tokenService;
|
private $tokenService;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
Router $router,
|
Router $router,
|
||||||
Config $config,
|
Config $config,
|
||||||
DatabaseConnection $databaseConnection,
|
DatabaseConnection $databaseConnection,
|
||||||
HttpHelper $httpHelper,
|
HttpHelper $httpHelper,
|
||||||
AuthService $authService,
|
AuthService $authService,
|
||||||
TokenService $tokenService,
|
TokenService $tokenService,
|
||||||
RouteRepository $routeRepository)
|
RouteRepository $routeRepository)
|
||||||
{
|
{
|
||||||
$this->router = $router;
|
$this->router = $router;
|
||||||
$this->config = $config;
|
$this->config = $config;
|
||||||
$this->databaseConnection = $databaseConnection;
|
$this->databaseConnection = $databaseConnection;
|
||||||
$this->httpHelper = $httpHelper;
|
$this->httpHelper = $httpHelper;
|
||||||
$this->authService = $authService;
|
$this->authService = $authService;
|
||||||
$this->tokenService = $tokenService;
|
$this->tokenService = $tokenService;
|
||||||
|
|
||||||
//if script fails prematurely, mark it as fail from advance
|
//if script fails prematurely, mark it as fail from advance
|
||||||
$this->httpHelper->setResponseCode(500);
|
$this->httpHelper->setResponseCode(500);
|
||||||
|
|
||||||
$routeRepository->injectRoutes($router);
|
$routeRepository->injectRoutes($router);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function run($requestMethod, $requestUri)
|
public function run($requestMethod, $requestUri)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
$code = 200;
|
$code = 200;
|
||||||
$this->authorizeFromRequestHeader();
|
$this->authorizeFromRequestHeader();
|
||||||
$json = (array) $this->router->handle($requestMethod, $requestUri);
|
$json = (array) $this->router->handle($requestMethod, $requestUri);
|
||||||
}
|
}
|
||||||
catch (\Exception $e)
|
catch (\Exception $e)
|
||||||
{
|
{
|
||||||
$code = 400;
|
$code = 400;
|
||||||
$trace = $e->getTrace();
|
$trace = $e->getTrace();
|
||||||
foreach ($trace as &$item)
|
foreach ($trace as &$item)
|
||||||
unset($item['args']);
|
unset($item['args']);
|
||||||
$json = [
|
$json = [
|
||||||
'error' => $e->getMessage(),
|
'error' => $e->getMessage(),
|
||||||
'trace' => $trace,
|
'trace' => $trace,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
$end = microtime(true);
|
$end = microtime(true);
|
||||||
$json['__time'] = $end - Bootstrap::getStartTime();
|
$json['__time'] = $end - Bootstrap::getStartTime();
|
||||||
if ($this->config->misc->dumpSqlIntoQueries)
|
if ($this->config->misc->dumpSqlIntoQueries)
|
||||||
{
|
{
|
||||||
$json['__queries'] = $this->databaseConnection->getPDO()->getQueryCount();
|
$json['__queries'] = $this->databaseConnection->getPDO()->getQueryCount();
|
||||||
$json['__statements'] = $this->databaseConnection->getPDO()->getStatements();
|
$json['__statements'] = $this->databaseConnection->getPDO()->getStatements();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$this->httpHelper->isRedirecting())
|
if (!$this->httpHelper->isRedirecting())
|
||||||
{
|
{
|
||||||
$this->httpHelper->setResponseCode($code);
|
$this->httpHelper->setResponseCode($code);
|
||||||
$this->httpHelper->setHeader('Content-Type', 'application/json');
|
$this->httpHelper->setHeader('Content-Type', 'application/json');
|
||||||
$this->httpHelper->outputJSON($json);
|
$this->httpHelper->outputJSON($json);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $json;
|
return $json;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function authorizeFromRequestHeader()
|
private function authorizeFromRequestHeader()
|
||||||
{
|
{
|
||||||
$loginTokenName = $this->httpHelper->getRequestHeader('X-Authorization-Token');
|
$loginTokenName = $this->httpHelper->getRequestHeader('X-Authorization-Token');
|
||||||
if ($loginTokenName)
|
if ($loginTokenName)
|
||||||
{
|
{
|
||||||
$token = $this->tokenService->getByName($loginTokenName);
|
$token = $this->tokenService->getByName($loginTokenName);
|
||||||
$this->authService->loginFromToken($token);
|
$this->authService->loginFromToken($token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,91 +5,91 @@ use Szurubooru\Entities\User;
|
||||||
|
|
||||||
final class Comment extends Entity
|
final class Comment extends Entity
|
||||||
{
|
{
|
||||||
private $postId;
|
private $postId;
|
||||||
private $userId;
|
private $userId;
|
||||||
private $creationTime;
|
private $creationTime;
|
||||||
private $lastEditTime;
|
private $lastEditTime;
|
||||||
private $text;
|
private $text;
|
||||||
|
|
||||||
const LAZY_LOADER_USER = 'user';
|
const LAZY_LOADER_USER = 'user';
|
||||||
const LAZY_LOADER_POST = 'post';
|
const LAZY_LOADER_POST = 'post';
|
||||||
|
|
||||||
const META_SCORE = 'score';
|
const META_SCORE = 'score';
|
||||||
|
|
||||||
public function getUserId()
|
public function getUserId()
|
||||||
{
|
{
|
||||||
return $this->userId;
|
return $this->userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setUserId($userId)
|
public function setUserId($userId)
|
||||||
{
|
{
|
||||||
$this->userId = $userId;
|
$this->userId = $userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPostId()
|
public function getPostId()
|
||||||
{
|
{
|
||||||
return $this->postId;
|
return $this->postId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setPostId($postId)
|
public function setPostId($postId)
|
||||||
{
|
{
|
||||||
$this->postId = $postId;
|
$this->postId = $postId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCreationTime()
|
public function getCreationTime()
|
||||||
{
|
{
|
||||||
return $this->creationTime;
|
return $this->creationTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setCreationTime($creationTime)
|
public function setCreationTime($creationTime)
|
||||||
{
|
{
|
||||||
$this->creationTime = $creationTime;
|
$this->creationTime = $creationTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getLastEditTime()
|
public function getLastEditTime()
|
||||||
{
|
{
|
||||||
return $this->lastEditTime;
|
return $this->lastEditTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setLastEditTime($lastEditTime)
|
public function setLastEditTime($lastEditTime)
|
||||||
{
|
{
|
||||||
$this->lastEditTime = $lastEditTime;
|
$this->lastEditTime = $lastEditTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getText()
|
public function getText()
|
||||||
{
|
{
|
||||||
return $this->text;
|
return $this->text;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setText($text)
|
public function setText($text)
|
||||||
{
|
{
|
||||||
$this->text = $text;
|
$this->text = $text;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUser()
|
public function getUser()
|
||||||
{
|
{
|
||||||
return $this->lazyLoad(self::LAZY_LOADER_USER, null);
|
return $this->lazyLoad(self::LAZY_LOADER_USER, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setUser(User $user = null)
|
public function setUser(User $user = null)
|
||||||
{
|
{
|
||||||
$this->lazySave(self::LAZY_LOADER_USER, $user);
|
$this->lazySave(self::LAZY_LOADER_USER, $user);
|
||||||
$this->userId = $user ? $user->getId() : null;
|
$this->userId = $user ? $user->getId() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPost()
|
public function getPost()
|
||||||
{
|
{
|
||||||
return $this->lazyLoad(self::LAZY_LOADER_POST, null);
|
return $this->lazyLoad(self::LAZY_LOADER_POST, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setPost(Post $post)
|
public function setPost(Post $post)
|
||||||
{
|
{
|
||||||
$this->lazySave(self::LAZY_LOADER_POST, $post);
|
$this->lazySave(self::LAZY_LOADER_POST, $post);
|
||||||
$this->postId = $post->getId();
|
$this->postId = $post->getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getScore()
|
public function getScore()
|
||||||
{
|
{
|
||||||
return $this->getMeta(self::META_SCORE, 0);
|
return $this->getMeta(self::META_SCORE, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,74 +3,74 @@ namespace Szurubooru\Entities;
|
||||||
|
|
||||||
abstract class Entity
|
abstract class Entity
|
||||||
{
|
{
|
||||||
protected $id = null;
|
protected $id = null;
|
||||||
private $lazyLoaders = [];
|
private $lazyLoaders = [];
|
||||||
private $lazyContainers = [];
|
private $lazyContainers = [];
|
||||||
private $meta;
|
private $meta;
|
||||||
|
|
||||||
public function __construct($id = null)
|
public function __construct($id = null)
|
||||||
{
|
{
|
||||||
$this->id = $id === null ? null : intval($id);
|
$this->id = $id === null ? null : intval($id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getId()
|
public function getId()
|
||||||
{
|
{
|
||||||
return $this->id;
|
return $this->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setId($id)
|
public function setId($id)
|
||||||
{
|
{
|
||||||
$this->id = $id;
|
$this->id = $id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getMeta($metaName, $default = null)
|
public function getMeta($metaName, $default = null)
|
||||||
{
|
{
|
||||||
if (!isset($this->meta[$metaName]))
|
if (!isset($this->meta[$metaName]))
|
||||||
return $default;
|
return $default;
|
||||||
return $this->meta[$metaName];
|
return $this->meta[$metaName];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setMeta($metaName, $value)
|
public function setMeta($metaName, $value)
|
||||||
{
|
{
|
||||||
$this->meta[$metaName] = $value;
|
$this->meta[$metaName] = $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function resetMeta()
|
public function resetMeta()
|
||||||
{
|
{
|
||||||
$this->meta = [];
|
$this->meta = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function resetLazyLoaders()
|
public function resetLazyLoaders()
|
||||||
{
|
{
|
||||||
$this->lazyLoaders = [];
|
$this->lazyLoaders = [];
|
||||||
$this->lazyContainers = [];
|
$this->lazyContainers = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setLazyLoader($lazyContainerName, $getter)
|
public function setLazyLoader($lazyContainerName, $getter)
|
||||||
{
|
{
|
||||||
$this->lazyLoaders[$lazyContainerName] = $getter;
|
$this->lazyLoaders[$lazyContainerName] = $getter;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function lazyLoad($lazyContainerName, $defaultValue)
|
protected function lazyLoad($lazyContainerName, $defaultValue)
|
||||||
{
|
{
|
||||||
if (!isset($this->lazyContainers[$lazyContainerName]))
|
if (!isset($this->lazyContainers[$lazyContainerName]))
|
||||||
{
|
{
|
||||||
if (!isset($this->lazyLoaders[$lazyContainerName]))
|
if (!isset($this->lazyLoaders[$lazyContainerName]))
|
||||||
{
|
{
|
||||||
return $defaultValue;
|
return $defaultValue;
|
||||||
}
|
}
|
||||||
$result = $this->lazyLoaders[$lazyContainerName]($this);
|
$result = $this->lazyLoaders[$lazyContainerName]($this);
|
||||||
$this->lazySave($lazyContainerName, $result);
|
$this->lazySave($lazyContainerName, $result);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$result = $this->lazyContainers[$lazyContainerName];
|
$result = $this->lazyContainers[$lazyContainerName];
|
||||||
}
|
}
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function lazySave($lazyContainerName, $value)
|
protected function lazySave($lazyContainerName, $value)
|
||||||
{
|
{
|
||||||
$this->lazyContainers[$lazyContainerName] = $value;
|
$this->lazyContainers[$lazyContainerName] = $value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,62 +5,62 @@ use Szurubooru\Entities\User;
|
||||||
|
|
||||||
final class Favorite extends Entity
|
final class Favorite extends Entity
|
||||||
{
|
{
|
||||||
private $postId;
|
private $postId;
|
||||||
private $userId;
|
private $userId;
|
||||||
private $time;
|
private $time;
|
||||||
|
|
||||||
const LAZY_LOADER_USER = 'user';
|
const LAZY_LOADER_USER = 'user';
|
||||||
const LAZY_LOADER_POST = 'post';
|
const LAZY_LOADER_POST = 'post';
|
||||||
|
|
||||||
public function getUserId()
|
public function getUserId()
|
||||||
{
|
{
|
||||||
return $this->userId;
|
return $this->userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setUserId($userId)
|
public function setUserId($userId)
|
||||||
{
|
{
|
||||||
$this->userId = $userId;
|
$this->userId = $userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPostId()
|
public function getPostId()
|
||||||
{
|
{
|
||||||
return $this->postId;
|
return $this->postId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setPostId($postId)
|
public function setPostId($postId)
|
||||||
{
|
{
|
||||||
$this->postId = $postId;
|
$this->postId = $postId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTime()
|
public function getTime()
|
||||||
{
|
{
|
||||||
return $this->time;
|
return $this->time;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setTime($time)
|
public function setTime($time)
|
||||||
{
|
{
|
||||||
$this->time = $time;
|
$this->time = $time;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUser()
|
public function getUser()
|
||||||
{
|
{
|
||||||
return $this->lazyLoad(self::LAZY_LOADER_USER, null);
|
return $this->lazyLoad(self::LAZY_LOADER_USER, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setUser(User $user)
|
public function setUser(User $user)
|
||||||
{
|
{
|
||||||
$this->lazySave(self::LAZY_LOADER_USER, $user);
|
$this->lazySave(self::LAZY_LOADER_USER, $user);
|
||||||
$this->userId = $user->getId();
|
$this->userId = $user->getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPost()
|
public function getPost()
|
||||||
{
|
{
|
||||||
return $this->lazyLoad(self::LAZY_LOADER_POST, null);
|
return $this->lazyLoad(self::LAZY_LOADER_POST, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setPost(Post $post)
|
public function setPost(Post $post)
|
||||||
{
|
{
|
||||||
$this->lazySave(self::LAZY_LOADER_POST, $post);
|
$this->lazySave(self::LAZY_LOADER_POST, $post);
|
||||||
$this->postId = $post->getId();
|
$this->postId = $post->getId();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,31 +3,31 @@ namespace Szurubooru\Entities;
|
||||||
|
|
||||||
final class GlobalParam extends Entity
|
final class GlobalParam extends Entity
|
||||||
{
|
{
|
||||||
const KEY_FEATURED_POST_USER = 'featuredPostUser';
|
const KEY_FEATURED_POST_USER = 'featuredPostUser';
|
||||||
const KEY_FEATURED_POST = 'featuredPost';
|
const KEY_FEATURED_POST = 'featuredPost';
|
||||||
const KEY_POST_SIZE = 'postSize';
|
const KEY_POST_SIZE = 'postSize';
|
||||||
const KEY_POST_COUNT = 'postCount';
|
const KEY_POST_COUNT = 'postCount';
|
||||||
|
|
||||||
private $key;
|
private $key;
|
||||||
private $value;
|
private $value;
|
||||||
|
|
||||||
public function getKey()
|
public function getKey()
|
||||||
{
|
{
|
||||||
return $this->key;
|
return $this->key;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setKey($key)
|
public function setKey($key)
|
||||||
{
|
{
|
||||||
$this->key = $key;
|
$this->key = $key;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getValue()
|
public function getValue()
|
||||||
{
|
{
|
||||||
return $this->value;
|
return $this->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setValue($value)
|
public function setValue($value)
|
||||||
{
|
{
|
||||||
$this->value = $value;
|
$this->value = $value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,290 +4,290 @@ use Szurubooru\Entities\User;
|
||||||
|
|
||||||
final class Post extends Entity
|
final class Post extends Entity
|
||||||
{
|
{
|
||||||
const POST_SAFETY_SAFE = 1;
|
const POST_SAFETY_SAFE = 1;
|
||||||
const POST_SAFETY_SKETCHY = 2;
|
const POST_SAFETY_SKETCHY = 2;
|
||||||
const POST_SAFETY_UNSAFE = 3;
|
const POST_SAFETY_UNSAFE = 3;
|
||||||
|
|
||||||
const POST_TYPE_IMAGE = 1;
|
const POST_TYPE_IMAGE = 1;
|
||||||
const POST_TYPE_FLASH = 2;
|
const POST_TYPE_FLASH = 2;
|
||||||
const POST_TYPE_VIDEO = 3;
|
const POST_TYPE_VIDEO = 3;
|
||||||
const POST_TYPE_YOUTUBE = 4;
|
const POST_TYPE_YOUTUBE = 4;
|
||||||
const POST_TYPE_ANIMATED_IMAGE = 5;
|
const POST_TYPE_ANIMATED_IMAGE = 5;
|
||||||
|
|
||||||
const FLAG_LOOP = 1;
|
const FLAG_LOOP = 1;
|
||||||
|
|
||||||
const LAZY_LOADER_USER = 'user';
|
const LAZY_LOADER_USER = 'user';
|
||||||
const LAZY_LOADER_TAGS = 'tags';
|
const LAZY_LOADER_TAGS = 'tags';
|
||||||
const LAZY_LOADER_CONTENT = 'content';
|
const LAZY_LOADER_CONTENT = 'content';
|
||||||
const LAZY_LOADER_THUMBNAIL_SOURCE_CONTENT = 'thumbnailSourceContent';
|
const LAZY_LOADER_THUMBNAIL_SOURCE_CONTENT = 'thumbnailSourceContent';
|
||||||
const LAZY_LOADER_RELATED_POSTS = 'relatedPosts';
|
const LAZY_LOADER_RELATED_POSTS = 'relatedPosts';
|
||||||
|
|
||||||
const META_TAG_COUNT = 'tagCount';
|
const META_TAG_COUNT = 'tagCount';
|
||||||
const META_FAV_COUNT = 'favCount';
|
const META_FAV_COUNT = 'favCount';
|
||||||
const META_COMMENT_COUNT = 'commentCount';
|
const META_COMMENT_COUNT = 'commentCount';
|
||||||
const META_SCORE = 'score';
|
const META_SCORE = 'score';
|
||||||
|
|
||||||
private $name;
|
private $name;
|
||||||
private $userId;
|
private $userId;
|
||||||
private $uploadTime;
|
private $uploadTime;
|
||||||
private $lastEditTime;
|
private $lastEditTime;
|
||||||
private $safety;
|
private $safety;
|
||||||
private $contentType;
|
private $contentType;
|
||||||
private $contentChecksum;
|
private $contentChecksum;
|
||||||
private $contentMimeType;
|
private $contentMimeType;
|
||||||
private $source;
|
private $source;
|
||||||
private $imageWidth;
|
private $imageWidth;
|
||||||
private $imageHeight;
|
private $imageHeight;
|
||||||
private $originalFileSize;
|
private $originalFileSize;
|
||||||
private $originalFileName;
|
private $originalFileName;
|
||||||
private $featureCount = 0;
|
private $featureCount = 0;
|
||||||
private $lastFeatureTime;
|
private $lastFeatureTime;
|
||||||
private $flags = 0;
|
private $flags = 0;
|
||||||
|
|
||||||
public function getIdMarkdown()
|
public function getIdMarkdown()
|
||||||
{
|
{
|
||||||
return '@' . $this->id;
|
return '@' . $this->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getName()
|
public function getName()
|
||||||
{
|
{
|
||||||
return $this->name;
|
return $this->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setName($name)
|
public function setName($name)
|
||||||
{
|
{
|
||||||
$this->name = $name;
|
$this->name = $name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUserId()
|
public function getUserId()
|
||||||
{
|
{
|
||||||
return $this->userId;
|
return $this->userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setUserId($userId)
|
public function setUserId($userId)
|
||||||
{
|
{
|
||||||
$this->userId = $userId;
|
$this->userId = $userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSafety()
|
public function getSafety()
|
||||||
{
|
{
|
||||||
return $this->safety;
|
return $this->safety;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setSafety($safety)
|
public function setSafety($safety)
|
||||||
{
|
{
|
||||||
$this->safety = $safety;
|
$this->safety = $safety;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUploadTime()
|
public function getUploadTime()
|
||||||
{
|
{
|
||||||
return $this->uploadTime;
|
return $this->uploadTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setUploadTime($uploadTime)
|
public function setUploadTime($uploadTime)
|
||||||
{
|
{
|
||||||
$this->uploadTime = $uploadTime;
|
$this->uploadTime = $uploadTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getLastEditTime()
|
public function getLastEditTime()
|
||||||
{
|
{
|
||||||
return $this->lastEditTime;
|
return $this->lastEditTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setLastEditTime($lastEditTime)
|
public function setLastEditTime($lastEditTime)
|
||||||
{
|
{
|
||||||
$this->lastEditTime = $lastEditTime;
|
$this->lastEditTime = $lastEditTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getContentType()
|
public function getContentType()
|
||||||
{
|
{
|
||||||
return $this->contentType;
|
return $this->contentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setContentType($contentType)
|
public function setContentType($contentType)
|
||||||
{
|
{
|
||||||
$this->contentType = $contentType;
|
$this->contentType = $contentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getContentChecksum()
|
public function getContentChecksum()
|
||||||
{
|
{
|
||||||
return $this->contentChecksum;
|
return $this->contentChecksum;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setContentChecksum($contentChecksum)
|
public function setContentChecksum($contentChecksum)
|
||||||
{
|
{
|
||||||
$this->contentChecksum = $contentChecksum;
|
$this->contentChecksum = $contentChecksum;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getContentMimeType()
|
public function getContentMimeType()
|
||||||
{
|
{
|
||||||
return $this->contentMimeType;
|
return $this->contentMimeType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setContentMimeType($contentMimeType)
|
public function setContentMimeType($contentMimeType)
|
||||||
{
|
{
|
||||||
$this->contentMimeType = $contentMimeType;
|
$this->contentMimeType = $contentMimeType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSource()
|
public function getSource()
|
||||||
{
|
{
|
||||||
return $this->source;
|
return $this->source;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setSource($source)
|
public function setSource($source)
|
||||||
{
|
{
|
||||||
$this->source = $source;
|
$this->source = $source;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getImageWidth()
|
public function getImageWidth()
|
||||||
{
|
{
|
||||||
return $this->imageWidth;
|
return $this->imageWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setImageWidth($imageWidth)
|
public function setImageWidth($imageWidth)
|
||||||
{
|
{
|
||||||
$this->imageWidth = $imageWidth;
|
$this->imageWidth = $imageWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getImageHeight()
|
public function getImageHeight()
|
||||||
{
|
{
|
||||||
return $this->imageHeight;
|
return $this->imageHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setImageHeight($imageHeight)
|
public function setImageHeight($imageHeight)
|
||||||
{
|
{
|
||||||
$this->imageHeight = $imageHeight;
|
$this->imageHeight = $imageHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getOriginalFileSize()
|
public function getOriginalFileSize()
|
||||||
{
|
{
|
||||||
return $this->originalFileSize;
|
return $this->originalFileSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setOriginalFileSize($originalFileSize)
|
public function setOriginalFileSize($originalFileSize)
|
||||||
{
|
{
|
||||||
$this->originalFileSize = $originalFileSize;
|
$this->originalFileSize = $originalFileSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getOriginalFileName()
|
public function getOriginalFileName()
|
||||||
{
|
{
|
||||||
return $this->originalFileName;
|
return $this->originalFileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setOriginalFileName($originalFileName)
|
public function setOriginalFileName($originalFileName)
|
||||||
{
|
{
|
||||||
$this->originalFileName = $originalFileName;
|
$this->originalFileName = $originalFileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFeatureCount()
|
public function getFeatureCount()
|
||||||
{
|
{
|
||||||
return $this->featureCount;
|
return $this->featureCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setFeatureCount($featureCount)
|
public function setFeatureCount($featureCount)
|
||||||
{
|
{
|
||||||
$this->featureCount = $featureCount;
|
$this->featureCount = $featureCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getLastFeatureTime()
|
public function getLastFeatureTime()
|
||||||
{
|
{
|
||||||
return $this->lastFeatureTime;
|
return $this->lastFeatureTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setLastFeatureTime($lastFeatureTime)
|
public function setLastFeatureTime($lastFeatureTime)
|
||||||
{
|
{
|
||||||
$this->lastFeatureTime = $lastFeatureTime;
|
$this->lastFeatureTime = $lastFeatureTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFlags()
|
public function getFlags()
|
||||||
{
|
{
|
||||||
return $this->flags;
|
return $this->flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setFlags($flags)
|
public function setFlags($flags)
|
||||||
{
|
{
|
||||||
$this->flags = $flags;
|
$this->flags = $flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTags()
|
public function getTags()
|
||||||
{
|
{
|
||||||
return $this->lazyLoad(self::LAZY_LOADER_TAGS, []);
|
return $this->lazyLoad(self::LAZY_LOADER_TAGS, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setTags(array $tags)
|
public function setTags(array $tags)
|
||||||
{
|
{
|
||||||
$this->lazySave(self::LAZY_LOADER_TAGS, $tags);
|
$this->lazySave(self::LAZY_LOADER_TAGS, $tags);
|
||||||
$this->setMeta(self::META_TAG_COUNT, count($tags));
|
$this->setMeta(self::META_TAG_COUNT, count($tags));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getRelatedPosts()
|
public function getRelatedPosts()
|
||||||
{
|
{
|
||||||
return $this->lazyLoad(self::LAZY_LOADER_RELATED_POSTS, []);
|
return $this->lazyLoad(self::LAZY_LOADER_RELATED_POSTS, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setRelatedPosts(array $relatedPosts)
|
public function setRelatedPosts(array $relatedPosts)
|
||||||
{
|
{
|
||||||
$this->lazySave(self::LAZY_LOADER_RELATED_POSTS, $relatedPosts);
|
$this->lazySave(self::LAZY_LOADER_RELATED_POSTS, $relatedPosts);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUser()
|
public function getUser()
|
||||||
{
|
{
|
||||||
return $this->lazyLoad(self::LAZY_LOADER_USER, null);
|
return $this->lazyLoad(self::LAZY_LOADER_USER, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setUser(User $user = null)
|
public function setUser(User $user = null)
|
||||||
{
|
{
|
||||||
$this->lazySave(self::LAZY_LOADER_USER, $user);
|
$this->lazySave(self::LAZY_LOADER_USER, $user);
|
||||||
$this->userId = $user ? $user->getId() : null;
|
$this->userId = $user ? $user->getId() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getContent()
|
public function getContent()
|
||||||
{
|
{
|
||||||
return $this->lazyLoad(self::LAZY_LOADER_CONTENT, null);
|
return $this->lazyLoad(self::LAZY_LOADER_CONTENT, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setContent($content)
|
public function setContent($content)
|
||||||
{
|
{
|
||||||
$this->lazySave(self::LAZY_LOADER_CONTENT, $content);
|
$this->lazySave(self::LAZY_LOADER_CONTENT, $content);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getThumbnailSourceContent()
|
public function getThumbnailSourceContent()
|
||||||
{
|
{
|
||||||
return $this->lazyLoad(self::LAZY_LOADER_THUMBNAIL_SOURCE_CONTENT, null);
|
return $this->lazyLoad(self::LAZY_LOADER_THUMBNAIL_SOURCE_CONTENT, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setThumbnailSourceContent($content)
|
public function setThumbnailSourceContent($content)
|
||||||
{
|
{
|
||||||
$this->lazySave(self::LAZY_LOADER_THUMBNAIL_SOURCE_CONTENT, $content);
|
$this->lazySave(self::LAZY_LOADER_THUMBNAIL_SOURCE_CONTENT, $content);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getContentPath()
|
public function getContentPath()
|
||||||
{
|
{
|
||||||
return 'posts' . DIRECTORY_SEPARATOR . $this->getName();
|
return 'posts' . DIRECTORY_SEPARATOR . $this->getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getThumbnailSourceContentPath()
|
public function getThumbnailSourceContentPath()
|
||||||
{
|
{
|
||||||
return 'posts' . DIRECTORY_SEPARATOR . $this->getName() . '-custom-thumb';
|
return 'posts' . DIRECTORY_SEPARATOR . $this->getName() . '-custom-thumb';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTagCount()
|
public function getTagCount()
|
||||||
{
|
{
|
||||||
return $this->getMeta(self::META_TAG_COUNT, 0);
|
return $this->getMeta(self::META_TAG_COUNT, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFavoriteCount()
|
public function getFavoriteCount()
|
||||||
{
|
{
|
||||||
return $this->getMeta(self::META_FAV_COUNT, 0);
|
return $this->getMeta(self::META_FAV_COUNT, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCommentCount()
|
public function getCommentCount()
|
||||||
{
|
{
|
||||||
return $this->getMeta(self::META_COMMENT_COUNT, 0);
|
return $this->getMeta(self::META_COMMENT_COUNT, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getScore()
|
public function getScore()
|
||||||
{
|
{
|
||||||
return $this->getMeta(self::META_SCORE, 0);
|
return $this->getMeta(self::META_SCORE, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,83 +3,83 @@ namespace Szurubooru\Entities;
|
||||||
|
|
||||||
final class PostNote extends Entity
|
final class PostNote extends Entity
|
||||||
{
|
{
|
||||||
private $postId;
|
private $postId;
|
||||||
private $left;
|
private $left;
|
||||||
private $top;
|
private $top;
|
||||||
private $width;
|
private $width;
|
||||||
private $height;
|
private $height;
|
||||||
private $text;
|
private $text;
|
||||||
|
|
||||||
const LAZY_LOADER_POST = 'post';
|
const LAZY_LOADER_POST = 'post';
|
||||||
|
|
||||||
public function getPostId()
|
public function getPostId()
|
||||||
{
|
{
|
||||||
return $this->postId;
|
return $this->postId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setPostId($postId)
|
public function setPostId($postId)
|
||||||
{
|
{
|
||||||
$this->postId = $postId;
|
$this->postId = $postId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getLeft()
|
public function getLeft()
|
||||||
{
|
{
|
||||||
return $this->left;
|
return $this->left;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setLeft($left)
|
public function setLeft($left)
|
||||||
{
|
{
|
||||||
$this->left = $left;
|
$this->left = $left;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTop()
|
public function getTop()
|
||||||
{
|
{
|
||||||
return $this->top;
|
return $this->top;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setTop($top)
|
public function setTop($top)
|
||||||
{
|
{
|
||||||
$this->top = $top;
|
$this->top = $top;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getWidth()
|
public function getWidth()
|
||||||
{
|
{
|
||||||
return $this->width;
|
return $this->width;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setWidth($width)
|
public function setWidth($width)
|
||||||
{
|
{
|
||||||
$this->width = $width;
|
$this->width = $width;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getHeight()
|
public function getHeight()
|
||||||
{
|
{
|
||||||
return $this->height;
|
return $this->height;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setHeight($height)
|
public function setHeight($height)
|
||||||
{
|
{
|
||||||
$this->height = $height;
|
$this->height = $height;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getText()
|
public function getText()
|
||||||
{
|
{
|
||||||
return $this->text;
|
return $this->text;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setText($text)
|
public function setText($text)
|
||||||
{
|
{
|
||||||
$this->text = $text;
|
$this->text = $text;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPost()
|
public function getPost()
|
||||||
{
|
{
|
||||||
return $this->lazyLoad(self::LAZY_LOADER_POST, null);
|
return $this->lazyLoad(self::LAZY_LOADER_POST, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setPost(Post $post)
|
public function setPost(Post $post)
|
||||||
{
|
{
|
||||||
$this->lazySave(self::LAZY_LOADER_POST, $post);
|
$this->lazySave(self::LAZY_LOADER_POST, $post);
|
||||||
$this->postId = $post->getId();
|
$this->postId = $post->getId();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,59 +3,59 @@ namespace Szurubooru\Entities;
|
||||||
|
|
||||||
final class Score extends Entity
|
final class Score extends Entity
|
||||||
{
|
{
|
||||||
private $postId;
|
private $postId;
|
||||||
private $commentId;
|
private $commentId;
|
||||||
private $score;
|
private $score;
|
||||||
private $time;
|
private $time;
|
||||||
private $userId;
|
private $userId;
|
||||||
|
|
||||||
public function getUserId()
|
public function getUserId()
|
||||||
{
|
{
|
||||||
return $this->userId;
|
return $this->userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setUserId($userId)
|
public function setUserId($userId)
|
||||||
{
|
{
|
||||||
$this->userId = $userId;
|
$this->userId = $userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPostId()
|
public function getPostId()
|
||||||
{
|
{
|
||||||
return $this->postId;
|
return $this->postId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setPostId($postId)
|
public function setPostId($postId)
|
||||||
{
|
{
|
||||||
$this->postId = $postId;
|
$this->postId = $postId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCommentId()
|
public function getCommentId()
|
||||||
{
|
{
|
||||||
return $this->commentId;
|
return $this->commentId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setCommentId($commentId)
|
public function setCommentId($commentId)
|
||||||
{
|
{
|
||||||
$this->commentId = $commentId;
|
$this->commentId = $commentId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTime()
|
public function getTime()
|
||||||
{
|
{
|
||||||
return $this->time;
|
return $this->time;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setTime($time)
|
public function setTime($time)
|
||||||
{
|
{
|
||||||
$this->time = $time;
|
$this->time = $time;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getScore()
|
public function getScore()
|
||||||
{
|
{
|
||||||
return $this->score;
|
return $this->score;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setScore($score)
|
public function setScore($score)
|
||||||
{
|
{
|
||||||
$this->score = $score;
|
$this->score = $score;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,101 +4,101 @@ use Szurubooru\Entities\User;
|
||||||
|
|
||||||
final class Snapshot extends Entity
|
final class Snapshot extends Entity
|
||||||
{
|
{
|
||||||
const TYPE_POST = 0;
|
const TYPE_POST = 0;
|
||||||
const TYPE_TAG = 1;
|
const TYPE_TAG = 1;
|
||||||
|
|
||||||
const OPERATION_CREATION = 0;
|
const OPERATION_CREATION = 0;
|
||||||
const OPERATION_CHANGE = 1;
|
const OPERATION_CHANGE = 1;
|
||||||
const OPERATION_DELETE = 2;
|
const OPERATION_DELETE = 2;
|
||||||
|
|
||||||
const LAZY_LOADER_USER = 'user';
|
const LAZY_LOADER_USER = 'user';
|
||||||
|
|
||||||
private $time;
|
private $time;
|
||||||
private $type;
|
private $type;
|
||||||
private $primaryKey;
|
private $primaryKey;
|
||||||
private $operation;
|
private $operation;
|
||||||
private $userId;
|
private $userId;
|
||||||
private $data;
|
private $data;
|
||||||
private $dataDifference;
|
private $dataDifference;
|
||||||
|
|
||||||
public function getTime()
|
public function getTime()
|
||||||
{
|
{
|
||||||
return $this->time;
|
return $this->time;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setTime($time)
|
public function setTime($time)
|
||||||
{
|
{
|
||||||
$this->time = $time;
|
$this->time = $time;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getType()
|
public function getType()
|
||||||
{
|
{
|
||||||
return $this->type;
|
return $this->type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setType($type)
|
public function setType($type)
|
||||||
{
|
{
|
||||||
$this->type = $type;
|
$this->type = $type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPrimaryKey()
|
public function getPrimaryKey()
|
||||||
{
|
{
|
||||||
return $this->primaryKey;
|
return $this->primaryKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setPrimaryKey($primaryKey)
|
public function setPrimaryKey($primaryKey)
|
||||||
{
|
{
|
||||||
$this->primaryKey = $primaryKey;
|
$this->primaryKey = $primaryKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getOperation()
|
public function getOperation()
|
||||||
{
|
{
|
||||||
return $this->operation;
|
return $this->operation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setOperation($operation)
|
public function setOperation($operation)
|
||||||
{
|
{
|
||||||
$this->operation = $operation;
|
$this->operation = $operation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUserId()
|
public function getUserId()
|
||||||
{
|
{
|
||||||
return $this->userId;
|
return $this->userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setUserId($userId)
|
public function setUserId($userId)
|
||||||
{
|
{
|
||||||
$this->userId = $userId;
|
$this->userId = $userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getData()
|
public function getData()
|
||||||
{
|
{
|
||||||
return $this->data;
|
return $this->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setData($data)
|
public function setData($data)
|
||||||
{
|
{
|
||||||
$this->data = $data;
|
$this->data = $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDataDifference()
|
public function getDataDifference()
|
||||||
{
|
{
|
||||||
return $this->dataDifference;
|
return $this->dataDifference;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setDataDifference($dataDifference)
|
public function setDataDifference($dataDifference)
|
||||||
{
|
{
|
||||||
$this->dataDifference = $dataDifference;
|
$this->dataDifference = $dataDifference;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUser()
|
public function getUser()
|
||||||
{
|
{
|
||||||
return $this->lazyLoad(self::LAZY_LOADER_USER, null);
|
return $this->lazyLoad(self::LAZY_LOADER_USER, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setUser(User $user = null)
|
public function setUser(User $user = null)
|
||||||
{
|
{
|
||||||
$this->lazySave(self::LAZY_LOADER_USER, $user);
|
$this->lazySave(self::LAZY_LOADER_USER, $user);
|
||||||
$this->userId = $user ? $user->getId() : null;
|
$this->userId = $user ? $user->getId() : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,78 +3,78 @@ namespace Szurubooru\Entities;
|
||||||
|
|
||||||
final class Tag extends Entity
|
final class Tag extends Entity
|
||||||
{
|
{
|
||||||
private $name;
|
private $name;
|
||||||
private $creationTime;
|
private $creationTime;
|
||||||
private $banned = false;
|
private $banned = false;
|
||||||
private $category = 'default';
|
private $category = 'default';
|
||||||
|
|
||||||
const LAZY_LOADER_IMPLIED_TAGS = 'implications';
|
const LAZY_LOADER_IMPLIED_TAGS = 'implications';
|
||||||
const LAZY_LOADER_SUGGESTED_TAGS = 'suggestions';
|
const LAZY_LOADER_SUGGESTED_TAGS = 'suggestions';
|
||||||
|
|
||||||
const META_USAGES = 'usages';
|
const META_USAGES = 'usages';
|
||||||
|
|
||||||
public function getName()
|
public function getName()
|
||||||
{
|
{
|
||||||
return $this->name;
|
return $this->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setName($name)
|
public function setName($name)
|
||||||
{
|
{
|
||||||
$this->name = $name;
|
$this->name = $name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCreationTime()
|
public function getCreationTime()
|
||||||
{
|
{
|
||||||
return $this->creationTime;
|
return $this->creationTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setCreationTime($creationTime)
|
public function setCreationTime($creationTime)
|
||||||
{
|
{
|
||||||
$this->creationTime = $creationTime;
|
$this->creationTime = $creationTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isBanned()
|
public function isBanned()
|
||||||
{
|
{
|
||||||
return $this->banned;
|
return $this->banned;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setBanned($banned)
|
public function setBanned($banned)
|
||||||
{
|
{
|
||||||
$this->banned = boolval($banned);
|
$this->banned = boolval($banned);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCategory()
|
public function getCategory()
|
||||||
{
|
{
|
||||||
return $this->category;
|
return $this->category;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setCategory($category)
|
public function setCategory($category)
|
||||||
{
|
{
|
||||||
$this->category = $category;
|
$this->category = $category;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUsages()
|
public function getUsages()
|
||||||
{
|
{
|
||||||
return $this->getMeta(self::META_USAGES);
|
return $this->getMeta(self::META_USAGES);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getImpliedTags()
|
public function getImpliedTags()
|
||||||
{
|
{
|
||||||
return $this->lazyLoad(self::LAZY_LOADER_IMPLIED_TAGS, []);
|
return $this->lazyLoad(self::LAZY_LOADER_IMPLIED_TAGS, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setImpliedTags(array $impliedTags)
|
public function setImpliedTags(array $impliedTags)
|
||||||
{
|
{
|
||||||
$this->lazySave(self::LAZY_LOADER_IMPLIED_TAGS, $impliedTags);
|
$this->lazySave(self::LAZY_LOADER_IMPLIED_TAGS, $impliedTags);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSuggestedTags()
|
public function getSuggestedTags()
|
||||||
{
|
{
|
||||||
return $this->lazyLoad(self::LAZY_LOADER_SUGGESTED_TAGS, []);
|
return $this->lazyLoad(self::LAZY_LOADER_SUGGESTED_TAGS, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setSuggestedTags(array $suggestedTags)
|
public function setSuggestedTags(array $suggestedTags)
|
||||||
{
|
{
|
||||||
$this->lazySave(self::LAZY_LOADER_SUGGESTED_TAGS, $suggestedTags);
|
$this->lazySave(self::LAZY_LOADER_SUGGESTED_TAGS, $suggestedTags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,41 +3,41 @@ namespace Szurubooru\Entities;
|
||||||
|
|
||||||
final class Token extends Entity
|
final class Token extends Entity
|
||||||
{
|
{
|
||||||
const PURPOSE_LOGIN = 1;
|
const PURPOSE_LOGIN = 1;
|
||||||
const PURPOSE_ACTIVATE = 2;
|
const PURPOSE_ACTIVATE = 2;
|
||||||
const PURPOSE_PASSWORD_RESET = 3;
|
const PURPOSE_PASSWORD_RESET = 3;
|
||||||
|
|
||||||
private $name;
|
private $name;
|
||||||
private $purpose;
|
private $purpose;
|
||||||
private $additionalData;
|
private $additionalData;
|
||||||
|
|
||||||
public function getName()
|
public function getName()
|
||||||
{
|
{
|
||||||
return $this->name;
|
return $this->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setName($name)
|
public function setName($name)
|
||||||
{
|
{
|
||||||
$this->name = $name;
|
$this->name = $name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPurpose()
|
public function getPurpose()
|
||||||
{
|
{
|
||||||
return $this->purpose;
|
return $this->purpose;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setPurpose($purpose)
|
public function setPurpose($purpose)
|
||||||
{
|
{
|
||||||
$this->purpose = intval($purpose);
|
$this->purpose = intval($purpose);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAdditionalData()
|
public function getAdditionalData()
|
||||||
{
|
{
|
||||||
return $this->additionalData;
|
return $this->additionalData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setAdditionalData($additionalData)
|
public function setAdditionalData($additionalData)
|
||||||
{
|
{
|
||||||
$this->additionalData = $additionalData;
|
$this->additionalData = $additionalData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,165 +3,165 @@ namespace Szurubooru\Entities;
|
||||||
|
|
||||||
final class User extends Entity
|
final class User extends Entity
|
||||||
{
|
{
|
||||||
const ACCESS_RANK_NOBODY = 0;
|
const ACCESS_RANK_NOBODY = 0;
|
||||||
const ACCESS_RANK_ANONYMOUS = 1;
|
const ACCESS_RANK_ANONYMOUS = 1;
|
||||||
const ACCESS_RANK_RESTRICTED_USER = 2;
|
const ACCESS_RANK_RESTRICTED_USER = 2;
|
||||||
const ACCESS_RANK_REGULAR_USER = 3;
|
const ACCESS_RANK_REGULAR_USER = 3;
|
||||||
const ACCESS_RANK_POWER_USER = 4;
|
const ACCESS_RANK_POWER_USER = 4;
|
||||||
const ACCESS_RANK_MODERATOR = 5;
|
const ACCESS_RANK_MODERATOR = 5;
|
||||||
const ACCESS_RANK_ADMINISTRATOR = 6;
|
const ACCESS_RANK_ADMINISTRATOR = 6;
|
||||||
|
|
||||||
const AVATAR_STYLE_GRAVATAR = 1;
|
const AVATAR_STYLE_GRAVATAR = 1;
|
||||||
const AVATAR_STYLE_MANUAL = 2;
|
const AVATAR_STYLE_MANUAL = 2;
|
||||||
const AVATAR_STYLE_BLANK = 3;
|
const AVATAR_STYLE_BLANK = 3;
|
||||||
|
|
||||||
const LAZY_LOADER_CUSTOM_AVATAR_SOURCE_CONTENT = 'customAvatarContent';
|
const LAZY_LOADER_CUSTOM_AVATAR_SOURCE_CONTENT = 'customAvatarContent';
|
||||||
|
|
||||||
private $name;
|
private $name;
|
||||||
private $email;
|
private $email;
|
||||||
private $emailUnconfirmed;
|
private $emailUnconfirmed;
|
||||||
private $passwordHash;
|
private $passwordHash;
|
||||||
private $passwordSalt;
|
private $passwordSalt;
|
||||||
private $accessRank;
|
private $accessRank;
|
||||||
private $registrationTime;
|
private $registrationTime;
|
||||||
private $lastLoginTime;
|
private $lastLoginTime;
|
||||||
private $avatarStyle;
|
private $avatarStyle;
|
||||||
private $browsingSettings;
|
private $browsingSettings;
|
||||||
private $accountConfirmed = false;
|
private $accountConfirmed = false;
|
||||||
private $banned = false;
|
private $banned = false;
|
||||||
|
|
||||||
public function getName()
|
public function getName()
|
||||||
{
|
{
|
||||||
return $this->name;
|
return $this->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setName($name)
|
public function setName($name)
|
||||||
{
|
{
|
||||||
$this->name = $name;
|
$this->name = $name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getEmail()
|
public function getEmail()
|
||||||
{
|
{
|
||||||
return $this->email;
|
return $this->email;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setEmail($email)
|
public function setEmail($email)
|
||||||
{
|
{
|
||||||
$this->email = $email;
|
$this->email = $email;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getEmailUnconfirmed()
|
public function getEmailUnconfirmed()
|
||||||
{
|
{
|
||||||
return $this->emailUnconfirmed;
|
return $this->emailUnconfirmed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setEmailUnconfirmed($emailUnconfirmed)
|
public function setEmailUnconfirmed($emailUnconfirmed)
|
||||||
{
|
{
|
||||||
$this->emailUnconfirmed = $emailUnconfirmed;
|
$this->emailUnconfirmed = $emailUnconfirmed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isBanned()
|
public function isBanned()
|
||||||
{
|
{
|
||||||
return $this->banned;
|
return $this->banned;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setBanned($banned)
|
public function setBanned($banned)
|
||||||
{
|
{
|
||||||
$this->banned = boolval($banned);
|
$this->banned = boolval($banned);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isAccountConfirmed()
|
public function isAccountConfirmed()
|
||||||
{
|
{
|
||||||
return $this->accountConfirmed;
|
return $this->accountConfirmed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setAccountConfirmed($accountConfirmed)
|
public function setAccountConfirmed($accountConfirmed)
|
||||||
{
|
{
|
||||||
$this->accountConfirmed = boolval($accountConfirmed);
|
$this->accountConfirmed = boolval($accountConfirmed);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPasswordHash()
|
public function getPasswordHash()
|
||||||
{
|
{
|
||||||
return $this->passwordHash;
|
return $this->passwordHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setPasswordHash($passwordHash)
|
public function setPasswordHash($passwordHash)
|
||||||
{
|
{
|
||||||
$this->passwordHash = $passwordHash;
|
$this->passwordHash = $passwordHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPasswordSalt()
|
public function getPasswordSalt()
|
||||||
{
|
{
|
||||||
return $this->passwordSalt;
|
return $this->passwordSalt;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setPasswordSalt($passwordSalt)
|
public function setPasswordSalt($passwordSalt)
|
||||||
{
|
{
|
||||||
$this->passwordSalt = $passwordSalt;
|
$this->passwordSalt = $passwordSalt;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAccessRank()
|
public function getAccessRank()
|
||||||
{
|
{
|
||||||
return $this->accessRank;
|
return $this->accessRank;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setAccessRank($accessRank)
|
public function setAccessRank($accessRank)
|
||||||
{
|
{
|
||||||
$this->accessRank = $accessRank;
|
$this->accessRank = $accessRank;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getRegistrationTime()
|
public function getRegistrationTime()
|
||||||
{
|
{
|
||||||
return $this->registrationTime;
|
return $this->registrationTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setRegistrationTime($registrationTime)
|
public function setRegistrationTime($registrationTime)
|
||||||
{
|
{
|
||||||
$this->registrationTime = $registrationTime;
|
$this->registrationTime = $registrationTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getLastLoginTime()
|
public function getLastLoginTime()
|
||||||
{
|
{
|
||||||
return $this->lastLoginTime;
|
return $this->lastLoginTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setLastLoginTime($lastLoginTime)
|
public function setLastLoginTime($lastLoginTime)
|
||||||
{
|
{
|
||||||
$this->lastLoginTime = $lastLoginTime;
|
$this->lastLoginTime = $lastLoginTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAvatarStyle()
|
public function getAvatarStyle()
|
||||||
{
|
{
|
||||||
return $this->avatarStyle;
|
return $this->avatarStyle;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setAvatarStyle($avatarStyle)
|
public function setAvatarStyle($avatarStyle)
|
||||||
{
|
{
|
||||||
$this->avatarStyle = $avatarStyle;
|
$this->avatarStyle = $avatarStyle;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getBrowsingSettings()
|
public function getBrowsingSettings()
|
||||||
{
|
{
|
||||||
return $this->browsingSettings;
|
return $this->browsingSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setBrowsingSettings($browsingSettings)
|
public function setBrowsingSettings($browsingSettings)
|
||||||
{
|
{
|
||||||
$this->browsingSettings = $browsingSettings;
|
$this->browsingSettings = $browsingSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCustomAvatarSourceContent()
|
public function getCustomAvatarSourceContent()
|
||||||
{
|
{
|
||||||
return $this->lazyLoad(self::LAZY_LOADER_CUSTOM_AVATAR_SOURCE_CONTENT, null);
|
return $this->lazyLoad(self::LAZY_LOADER_CUSTOM_AVATAR_SOURCE_CONTENT, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setCustomAvatarSourceContent($content)
|
public function setCustomAvatarSourceContent($content)
|
||||||
{
|
{
|
||||||
$this->lazySave(self::LAZY_LOADER_CUSTOM_AVATAR_SOURCE_CONTENT, $content);
|
$this->lazySave(self::LAZY_LOADER_CUSTOM_AVATAR_SOURCE_CONTENT, $content);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCustomAvatarSourceContentPath()
|
public function getCustomAvatarSourceContentPath()
|
||||||
{
|
{
|
||||||
return 'avatars' . DIRECTORY_SEPARATOR . $this->getId();
|
return 'avatars' . DIRECTORY_SEPARATOR . $this->getId();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,19 +5,19 @@ use Szurubooru\Validator;
|
||||||
|
|
||||||
class LoginFormData implements IValidatable
|
class LoginFormData implements IValidatable
|
||||||
{
|
{
|
||||||
public $userNameOrEmail;
|
public $userNameOrEmail;
|
||||||
public $password;
|
public $password;
|
||||||
|
|
||||||
public function __construct($inputReader = null)
|
public function __construct($inputReader = null)
|
||||||
{
|
{
|
||||||
if ($inputReader !== null)
|
if ($inputReader !== null)
|
||||||
{
|
{
|
||||||
$this->userNameOrEmail = trim($inputReader->userNameOrEmail);
|
$this->userNameOrEmail = trim($inputReader->userNameOrEmail);
|
||||||
$this->password = $inputReader->password;
|
$this->password = $inputReader->password;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function validate(Validator $validator)
|
public function validate(Validator $validator)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,46 +6,46 @@ use Szurubooru\Validator;
|
||||||
|
|
||||||
class PostEditFormData implements IValidatable
|
class PostEditFormData implements IValidatable
|
||||||
{
|
{
|
||||||
public $content;
|
public $content;
|
||||||
public $thumbnail;
|
public $thumbnail;
|
||||||
public $safety;
|
public $safety;
|
||||||
public $source;
|
public $source;
|
||||||
public $tags;
|
public $tags;
|
||||||
public $relations;
|
public $relations;
|
||||||
public $flags;
|
public $flags;
|
||||||
|
|
||||||
public $seenEditTime;
|
public $seenEditTime;
|
||||||
|
|
||||||
public function __construct($inputReader = null)
|
public function __construct($inputReader = null)
|
||||||
{
|
{
|
||||||
if ($inputReader !== null)
|
if ($inputReader !== null)
|
||||||
{
|
{
|
||||||
$this->content = $inputReader->readFile('content');
|
$this->content = $inputReader->readFile('content');
|
||||||
$this->thumbnail = $inputReader->readFile('thumbnail');
|
$this->thumbnail = $inputReader->readFile('thumbnail');
|
||||||
if ($inputReader->safety)
|
if ($inputReader->safety)
|
||||||
$this->safety = EnumHelper::postSafetyFromString($inputReader->safety);
|
$this->safety = EnumHelper::postSafetyFromString($inputReader->safety);
|
||||||
if ($inputReader->source !== null)
|
if ($inputReader->source !== null)
|
||||||
$this->source = $inputReader->source;
|
$this->source = $inputReader->source;
|
||||||
$this->tags = preg_split('/[\s+]/', $inputReader->tags);
|
$this->tags = preg_split('/[\s+]/', $inputReader->tags);
|
||||||
if ($inputReader->relations !== null)
|
if ($inputReader->relations !== null)
|
||||||
$this->relations = array_filter(preg_split('/[\s+]/', $inputReader->relations));
|
$this->relations = array_filter(preg_split('/[\s+]/', $inputReader->relations));
|
||||||
$this->seenEditTime = $inputReader->seenEditTime;
|
$this->seenEditTime = $inputReader->seenEditTime;
|
||||||
$this->flags = new \StdClass;
|
$this->flags = new \StdClass;
|
||||||
$this->flags->loop = !empty($inputReader->loop);
|
$this->flags->loop = !empty($inputReader->loop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function validate(Validator $validator)
|
public function validate(Validator $validator)
|
||||||
{
|
{
|
||||||
$validator->validatePostTags($this->tags);
|
$validator->validatePostTags($this->tags);
|
||||||
|
|
||||||
if ($this->source !== null)
|
if ($this->source !== null)
|
||||||
$validator->validatePostSource($this->source);
|
$validator->validatePostSource($this->source);
|
||||||
|
|
||||||
if ($this->relations)
|
if ($this->relations)
|
||||||
{
|
{
|
||||||
foreach ($this->relations as $relatedPostId)
|
foreach ($this->relations as $relatedPostId)
|
||||||
$validator->validateNumber($relatedPostId);
|
$validator->validateNumber($relatedPostId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,26 +5,26 @@ use Szurubooru\Validator;
|
||||||
|
|
||||||
class PostNoteFormData implements IValidatable
|
class PostNoteFormData implements IValidatable
|
||||||
{
|
{
|
||||||
public $left;
|
public $left;
|
||||||
public $top;
|
public $top;
|
||||||
public $width;
|
public $width;
|
||||||
public $height;
|
public $height;
|
||||||
public $text;
|
public $text;
|
||||||
|
|
||||||
public function __construct($inputReader = null)
|
public function __construct($inputReader = null)
|
||||||
{
|
{
|
||||||
if ($inputReader !== null)
|
if ($inputReader !== null)
|
||||||
{
|
{
|
||||||
$this->left = floatval($inputReader->left);
|
$this->left = floatval($inputReader->left);
|
||||||
$this->top = floatval($inputReader->top);
|
$this->top = floatval($inputReader->top);
|
||||||
$this->width = floatval($inputReader->width);
|
$this->width = floatval($inputReader->width);
|
||||||
$this->height = floatval($inputReader->height);
|
$this->height = floatval($inputReader->height);
|
||||||
$this->text = trim($inputReader->text);
|
$this->text = trim($inputReader->text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function validate(Validator $validator)
|
public function validate(Validator $validator)
|
||||||
{
|
{
|
||||||
$validator->validateMinLength($this->text, 3, 'Post note content');
|
$validator->validateMinLength($this->text, 3, 'Post note content');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,24 +5,24 @@ use Szurubooru\Validator;
|
||||||
|
|
||||||
class RegistrationFormData implements IValidatable
|
class RegistrationFormData implements IValidatable
|
||||||
{
|
{
|
||||||
public $userName;
|
public $userName;
|
||||||
public $password;
|
public $password;
|
||||||
public $email;
|
public $email;
|
||||||
|
|
||||||
public function __construct($inputReader = null)
|
public function __construct($inputReader = null)
|
||||||
{
|
{
|
||||||
if ($inputReader !== null)
|
if ($inputReader !== null)
|
||||||
{
|
{
|
||||||
$this->userName = trim($inputReader->userName);
|
$this->userName = trim($inputReader->userName);
|
||||||
$this->password = $inputReader->password;
|
$this->password = $inputReader->password;
|
||||||
$this->email = trim($inputReader->email);
|
$this->email = trim($inputReader->email);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function validate(Validator $validator)
|
public function validate(Validator $validator)
|
||||||
{
|
{
|
||||||
$validator->validateUserName($this->userName);
|
$validator->validateUserName($this->userName);
|
||||||
$validator->validatePassword($this->password);
|
$validator->validatePassword($this->password);
|
||||||
$validator->validateEmail($this->email);
|
$validator->validateEmail($this->email);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,40 +5,40 @@ use Szurubooru\Validator;
|
||||||
|
|
||||||
class TagEditFormData implements IValidatable
|
class TagEditFormData implements IValidatable
|
||||||
{
|
{
|
||||||
public $name;
|
public $name;
|
||||||
public $banned;
|
public $banned;
|
||||||
public $category;
|
public $category;
|
||||||
public $implications;
|
public $implications;
|
||||||
public $suggestions;
|
public $suggestions;
|
||||||
|
|
||||||
public function __construct($inputReader = null)
|
public function __construct($inputReader = null)
|
||||||
{
|
{
|
||||||
if ($inputReader !== null)
|
if ($inputReader !== null)
|
||||||
{
|
{
|
||||||
$this->name = trim($inputReader->name);
|
$this->name = trim($inputReader->name);
|
||||||
$this->category = strtolower(trim($inputReader->category));
|
$this->category = strtolower(trim($inputReader->category));
|
||||||
|
|
||||||
if ($inputReader->banned !== null)
|
if ($inputReader->banned !== null)
|
||||||
$this->banned = boolval($inputReader->banned);
|
$this->banned = boolval($inputReader->banned);
|
||||||
|
|
||||||
$this->implications = array_filter(array_unique(preg_split('/[\s+]/', $inputReader->implications)));
|
$this->implications = array_filter(array_unique(preg_split('/[\s+]/', $inputReader->implications)));
|
||||||
$this->suggestions = array_filter(array_unique(preg_split('/[\s+]/', $inputReader->suggestions)));
|
$this->suggestions = array_filter(array_unique(preg_split('/[\s+]/', $inputReader->suggestions)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function validate(Validator $validator)
|
public function validate(Validator $validator)
|
||||||
{
|
{
|
||||||
if ($this->category !== null)
|
if ($this->category !== null)
|
||||||
$validator->validateLength($this->category, 1, 25, 'Tag category');
|
$validator->validateLength($this->category, 1, 25, 'Tag category');
|
||||||
|
|
||||||
if ($this->name !== null)
|
if ($this->name !== null)
|
||||||
$validator->validatePostTags([$this->name]);
|
$validator->validatePostTags([$this->name]);
|
||||||
|
|
||||||
if (!empty($this->implications))
|
if (!empty($this->implications))
|
||||||
$validator->validatePostTags($this->implications);
|
$validator->validatePostTags($this->implications);
|
||||||
|
|
||||||
if (!empty($this->suggestions))
|
if (!empty($this->suggestions))
|
||||||
$validator->validatePostTags($this->suggestions);
|
$validator->validatePostTags($this->suggestions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,37 +6,37 @@ use Szurubooru\Validator;
|
||||||
|
|
||||||
class UploadFormData implements IValidatable
|
class UploadFormData implements IValidatable
|
||||||
{
|
{
|
||||||
public $contentFileName;
|
public $contentFileName;
|
||||||
public $content;
|
public $content;
|
||||||
public $url;
|
public $url;
|
||||||
public $anonymous;
|
public $anonymous;
|
||||||
public $safety;
|
public $safety;
|
||||||
public $source;
|
public $source;
|
||||||
public $tags;
|
public $tags;
|
||||||
|
|
||||||
public function __construct($inputReader = null)
|
public function __construct($inputReader = null)
|
||||||
{
|
{
|
||||||
if ($inputReader !== null)
|
if ($inputReader !== null)
|
||||||
{
|
{
|
||||||
$this->contentFileName = $inputReader->contentFileName;
|
$this->contentFileName = $inputReader->contentFileName;
|
||||||
$this->content = $inputReader->readFile('content');
|
$this->content = $inputReader->readFile('content');
|
||||||
$this->url = $inputReader->url;
|
$this->url = $inputReader->url;
|
||||||
$this->anonymous = $inputReader->anonymous;
|
$this->anonymous = $inputReader->anonymous;
|
||||||
$this->safety = EnumHelper::postSafetyFromString($inputReader->safety);
|
$this->safety = EnumHelper::postSafetyFromString($inputReader->safety);
|
||||||
$this->source = $inputReader->source;
|
$this->source = $inputReader->source;
|
||||||
$this->tags = preg_split('/[\s+]/', $inputReader->tags);
|
$this->tags = preg_split('/[\s+]/', $inputReader->tags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function validate(Validator $validator)
|
public function validate(Validator $validator)
|
||||||
{
|
{
|
||||||
if ($this->content === null && $this->url === null)
|
if ($this->content === null && $this->url === null)
|
||||||
throw new \DomainException('Neither data or URL provided.');
|
throw new \DomainException('Neither data or URL provided.');
|
||||||
|
|
||||||
$validator->validatePostTags($this->tags);
|
$validator->validatePostTags($this->tags);
|
||||||
|
|
||||||
if ($this->source !== null)
|
if ($this->source !== null)
|
||||||
$validator->validatePostSource($this->source);
|
$validator->validatePostSource($this->source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,60 +7,60 @@ use Szurubooru\Validator;
|
||||||
|
|
||||||
class UserEditFormData implements IValidatable
|
class UserEditFormData implements IValidatable
|
||||||
{
|
{
|
||||||
public $userName;
|
public $userName;
|
||||||
public $email;
|
public $email;
|
||||||
public $password;
|
public $password;
|
||||||
public $accessRank;
|
public $accessRank;
|
||||||
public $avatarStyle;
|
public $avatarStyle;
|
||||||
public $avatarContent;
|
public $avatarContent;
|
||||||
public $browsingSettings;
|
public $browsingSettings;
|
||||||
public $banned;
|
public $banned;
|
||||||
|
|
||||||
public function __construct($inputReader = null)
|
public function __construct($inputReader = null)
|
||||||
{
|
{
|
||||||
if ($inputReader !== null)
|
if ($inputReader !== null)
|
||||||
{
|
{
|
||||||
$this->userName = $inputReader->userName;
|
$this->userName = $inputReader->userName;
|
||||||
$this->email = $inputReader->email;
|
$this->email = $inputReader->email;
|
||||||
$this->password = $inputReader->password;
|
$this->password = $inputReader->password;
|
||||||
if ($inputReader->accessRank !== null)
|
if ($inputReader->accessRank !== null)
|
||||||
$this->accessRank = EnumHelper::accessRankFromString($inputReader->accessRank);
|
$this->accessRank = EnumHelper::accessRankFromString($inputReader->accessRank);
|
||||||
if ($inputReader->avatarStyle !== null)
|
if ($inputReader->avatarStyle !== null)
|
||||||
$this->avatarStyle = EnumHelper::avatarStyleFromString($inputReader->avatarStyle);
|
$this->avatarStyle = EnumHelper::avatarStyleFromString($inputReader->avatarStyle);
|
||||||
$this->avatarContent = $inputReader->readFile('avatarContent');
|
$this->avatarContent = $inputReader->readFile('avatarContent');
|
||||||
$this->browsingSettings = json_decode($inputReader->browsingSettings);
|
$this->browsingSettings = json_decode($inputReader->browsingSettings);
|
||||||
if ($inputReader->banned !== null)
|
if ($inputReader->banned !== null)
|
||||||
$this->banned = boolval($inputReader->banned);
|
$this->banned = boolval($inputReader->banned);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function validate(Validator $validator)
|
public function validate(Validator $validator)
|
||||||
{
|
{
|
||||||
if ($this->userName !== null)
|
if ($this->userName !== null)
|
||||||
$validator->validateUserName($this->userName);
|
$validator->validateUserName($this->userName);
|
||||||
|
|
||||||
if ($this->password !== null)
|
if ($this->password !== null)
|
||||||
$validator->validatePassword($this->password);
|
$validator->validatePassword($this->password);
|
||||||
|
|
||||||
if ($this->email !== null)
|
if ($this->email !== null)
|
||||||
$validator->validateEmail($this->email);
|
$validator->validateEmail($this->email);
|
||||||
|
|
||||||
if (strlen($this->avatarContent) > 1024 * 512)
|
if (strlen($this->avatarContent) > 1024 * 512)
|
||||||
throw new \DomainException('Avatar content must have at most 512 kilobytes.');
|
throw new \DomainException('Avatar content must have at most 512 kilobytes.');
|
||||||
|
|
||||||
if ($this->avatarContent)
|
if ($this->avatarContent)
|
||||||
{
|
{
|
||||||
$avatarContentMimeType = MimeHelper::getMimeTypeFromBuffer($this->avatarContent);
|
$avatarContentMimeType = MimeHelper::getMimeTypeFromBuffer($this->avatarContent);
|
||||||
if (!MimeHelper::isImage($avatarContentMimeType))
|
if (!MimeHelper::isImage($avatarContentMimeType))
|
||||||
throw new \DomainException('Avatar must be an image (detected: ' . $avatarContentMimeType . ').');
|
throw new \DomainException('Avatar must be an image (detected: ' . $avatarContentMimeType . ').');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->browsingSettings !== null)
|
if ($this->browsingSettings !== null)
|
||||||
{
|
{
|
||||||
if (!is_object($this->browsingSettings))
|
if (!is_object($this->browsingSettings))
|
||||||
throw new \InvalidArgumentException('Browsing settings must be valid JSON.');
|
throw new \InvalidArgumentException('Browsing settings must be valid JSON.');
|
||||||
else if (strlen(json_encode($this->browsingSettings)) > 300)
|
else if (strlen(json_encode($this->browsingSettings)) > 300)
|
||||||
throw new \InvalidArgumentException('Stringified browsing settings can have at most 300 characters.');
|
throw new \InvalidArgumentException('Stringified browsing settings can have at most 300 characters.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,111 +6,111 @@ use Szurubooru\Entities\User;
|
||||||
|
|
||||||
class EnumHelper
|
class EnumHelper
|
||||||
{
|
{
|
||||||
private static $accessRankMap =
|
private static $accessRankMap =
|
||||||
[
|
[
|
||||||
'anonymous' => User::ACCESS_RANK_ANONYMOUS,
|
'anonymous' => User::ACCESS_RANK_ANONYMOUS,
|
||||||
'restrictedUser' => User::ACCESS_RANK_RESTRICTED_USER,
|
'restrictedUser' => User::ACCESS_RANK_RESTRICTED_USER,
|
||||||
'regularUser' => User::ACCESS_RANK_REGULAR_USER,
|
'regularUser' => User::ACCESS_RANK_REGULAR_USER,
|
||||||
'powerUser' => User::ACCESS_RANK_POWER_USER,
|
'powerUser' => User::ACCESS_RANK_POWER_USER,
|
||||||
'moderator' => User::ACCESS_RANK_MODERATOR,
|
'moderator' => User::ACCESS_RANK_MODERATOR,
|
||||||
'administrator' => User::ACCESS_RANK_ADMINISTRATOR,
|
'administrator' => User::ACCESS_RANK_ADMINISTRATOR,
|
||||||
];
|
];
|
||||||
|
|
||||||
private static $avatarStyleMap =
|
private static $avatarStyleMap =
|
||||||
[
|
[
|
||||||
'gravatar' => User::AVATAR_STYLE_GRAVATAR,
|
'gravatar' => User::AVATAR_STYLE_GRAVATAR,
|
||||||
'manual' => User::AVATAR_STYLE_MANUAL,
|
'manual' => User::AVATAR_STYLE_MANUAL,
|
||||||
'none' => User::AVATAR_STYLE_BLANK,
|
'none' => User::AVATAR_STYLE_BLANK,
|
||||||
'blank' => User::AVATAR_STYLE_BLANK,
|
'blank' => User::AVATAR_STYLE_BLANK,
|
||||||
];
|
];
|
||||||
|
|
||||||
private static $postSafetyMap =
|
private static $postSafetyMap =
|
||||||
[
|
[
|
||||||
'safe' => Post::POST_SAFETY_SAFE,
|
'safe' => Post::POST_SAFETY_SAFE,
|
||||||
'sketchy' => Post::POST_SAFETY_SKETCHY,
|
'sketchy' => Post::POST_SAFETY_SKETCHY,
|
||||||
'unsafe' => Post::POST_SAFETY_UNSAFE,
|
'unsafe' => Post::POST_SAFETY_UNSAFE,
|
||||||
];
|
];
|
||||||
|
|
||||||
private static $postTypeMap =
|
private static $postTypeMap =
|
||||||
[
|
[
|
||||||
'image' => Post::POST_TYPE_IMAGE,
|
'image' => Post::POST_TYPE_IMAGE,
|
||||||
'video' => Post::POST_TYPE_VIDEO,
|
'video' => Post::POST_TYPE_VIDEO,
|
||||||
'flash' => Post::POST_TYPE_FLASH,
|
'flash' => Post::POST_TYPE_FLASH,
|
||||||
'youtube' => Post::POST_TYPE_YOUTUBE,
|
'youtube' => Post::POST_TYPE_YOUTUBE,
|
||||||
'animation' => Post::POST_TYPE_ANIMATED_IMAGE,
|
'animation' => Post::POST_TYPE_ANIMATED_IMAGE,
|
||||||
];
|
];
|
||||||
|
|
||||||
private static $snapshotTypeMap =
|
private static $snapshotTypeMap =
|
||||||
[
|
[
|
||||||
'post' => Snapshot::TYPE_POST,
|
'post' => Snapshot::TYPE_POST,
|
||||||
];
|
];
|
||||||
|
|
||||||
public static function accessRankToString($accessRank)
|
public static function accessRankToString($accessRank)
|
||||||
{
|
{
|
||||||
return self::enumToString(self::$accessRankMap, $accessRank);
|
return self::enumToString(self::$accessRankMap, $accessRank);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function accessRankFromString($accessRankString)
|
public static function accessRankFromString($accessRankString)
|
||||||
{
|
{
|
||||||
return self::stringToEnum(self::$accessRankMap, $accessRankString);
|
return self::stringToEnum(self::$accessRankMap, $accessRankString);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function avatarStyleToString($avatarStyle)
|
public static function avatarStyleToString($avatarStyle)
|
||||||
{
|
{
|
||||||
return self::enumToString(self::$avatarStyleMap, $avatarStyle);
|
return self::enumToString(self::$avatarStyleMap, $avatarStyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function avatarStyleFromString($avatarStyleString)
|
public static function avatarStyleFromString($avatarStyleString)
|
||||||
{
|
{
|
||||||
return self::stringToEnum(self::$avatarStyleMap, $avatarStyleString);
|
return self::stringToEnum(self::$avatarStyleMap, $avatarStyleString);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function postSafetyToString($postSafety)
|
public static function postSafetyToString($postSafety)
|
||||||
{
|
{
|
||||||
return self::enumToString(self::$postSafetyMap, $postSafety);
|
return self::enumToString(self::$postSafetyMap, $postSafety);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function postSafetyFromString($postSafetyString)
|
public static function postSafetyFromString($postSafetyString)
|
||||||
{
|
{
|
||||||
return self::stringToEnum(self::$postSafetyMap, $postSafetyString);
|
return self::stringToEnum(self::$postSafetyMap, $postSafetyString);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function postTypeToString($postType)
|
public static function postTypeToString($postType)
|
||||||
{
|
{
|
||||||
return self::enumToString(self::$postTypeMap, $postType);
|
return self::enumToString(self::$postTypeMap, $postType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function postTypeFromString($postTypeString)
|
public static function postTypeFromString($postTypeString)
|
||||||
{
|
{
|
||||||
return self::stringToEnum(self::$postTypeMap, $postTypeString);
|
return self::stringToEnum(self::$postTypeMap, $postTypeString);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function snapshotTypeFromString($snapshotTypeString)
|
public static function snapshotTypeFromString($snapshotTypeString)
|
||||||
{
|
{
|
||||||
return self::stringToEnum(self::$snapshotTypeMap, $snapshotTypeString);
|
return self::stringToEnum(self::$snapshotTypeMap, $snapshotTypeString);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function enumToString($enumMap, $enumValue)
|
private static function enumToString($enumMap, $enumValue)
|
||||||
{
|
{
|
||||||
$reverseMap = array_flip($enumMap);
|
$reverseMap = array_flip($enumMap);
|
||||||
if (!isset($reverseMap[$enumValue]))
|
if (!isset($reverseMap[$enumValue]))
|
||||||
throw new \RuntimeException('Invalid value!');
|
throw new \RuntimeException('Invalid value!');
|
||||||
|
|
||||||
return $reverseMap[$enumValue];
|
return $reverseMap[$enumValue];
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function stringToEnum($enumMap, $enumString)
|
private static function stringToEnum($enumMap, $enumString)
|
||||||
{
|
{
|
||||||
$key = trim(strtolower($enumString));
|
$key = trim(strtolower($enumString));
|
||||||
$lowerEnumMap = array_change_key_case($enumMap, \CASE_LOWER);
|
$lowerEnumMap = array_change_key_case($enumMap, \CASE_LOWER);
|
||||||
if (!isset($lowerEnumMap[$key]))
|
if (!isset($lowerEnumMap[$key]))
|
||||||
{
|
{
|
||||||
throw new \DomainException(sprintf(
|
throw new \DomainException(sprintf(
|
||||||
'Unrecognized value: %s.' . PHP_EOL . 'Possible values: %s',
|
'Unrecognized value: %s.' . PHP_EOL . 'Possible values: %s',
|
||||||
$enumString,
|
$enumString,
|
||||||
join(', ', array_keys($lowerEnumMap))));
|
join(', ', array_keys($lowerEnumMap))));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $lowerEnumMap[$key];
|
return $lowerEnumMap[$key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,89 +3,89 @@ namespace Szurubooru\Helpers;
|
||||||
|
|
||||||
class HttpHelper
|
class HttpHelper
|
||||||
{
|
{
|
||||||
private $redirected = false;
|
private $redirected = false;
|
||||||
|
|
||||||
public function setResponseCode($code)
|
public function setResponseCode($code)
|
||||||
{
|
{
|
||||||
http_response_code($code);
|
http_response_code($code);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setHeader($key, $value)
|
public function setHeader($key, $value)
|
||||||
{
|
{
|
||||||
header($key . ': ' . $value);
|
header($key . ': ' . $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function outputJSON($data)
|
public function outputJSON($data)
|
||||||
{
|
{
|
||||||
$encodedJson = json_encode((array) $data);
|
$encodedJson = json_encode((array) $data);
|
||||||
$lastError = json_last_error();
|
$lastError = json_last_error();
|
||||||
if ($lastError !== JSON_ERROR_NONE)
|
if ($lastError !== JSON_ERROR_NONE)
|
||||||
$this->output('Fatal error while encoding JSON: ' . $lastError . PHP_EOL . PHP_EOL . print_r($data, true));
|
$this->output('Fatal error while encoding JSON: ' . $lastError . PHP_EOL . PHP_EOL . print_r($data, true));
|
||||||
else
|
else
|
||||||
$this->output($encodedJson);
|
$this->output($encodedJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function output($data)
|
public function output($data)
|
||||||
{
|
{
|
||||||
echo $data;
|
echo $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getRequestHeaders()
|
public function getRequestHeaders()
|
||||||
{
|
{
|
||||||
if (function_exists('getallheaders'))
|
if (function_exists('getallheaders'))
|
||||||
{
|
{
|
||||||
return getallheaders();
|
return getallheaders();
|
||||||
}
|
}
|
||||||
$result = [];
|
$result = [];
|
||||||
foreach ($_SERVER as $key => $value)
|
foreach ($_SERVER as $key => $value)
|
||||||
{
|
{
|
||||||
if (substr($key, 0, 5) == "HTTP_")
|
if (substr($key, 0, 5) == "HTTP_")
|
||||||
{
|
{
|
||||||
$key = str_replace(" ", "-", ucwords(strtolower(str_replace("_", " ", substr($key, 5)))));
|
$key = str_replace(" ", "-", ucwords(strtolower(str_replace("_", " ", substr($key, 5)))));
|
||||||
$result[$key] = $value;
|
$result[$key] = $value;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$result[$key] = $value;
|
$result[$key] = $value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getRequestHeader($key)
|
public function getRequestHeader($key)
|
||||||
{
|
{
|
||||||
$headers = $this->getRequestHeaders();
|
$headers = $this->getRequestHeaders();
|
||||||
return isset($headers[$key]) ? $headers[$key] : null;
|
return isset($headers[$key]) ? $headers[$key] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getRequestMethod()
|
public function getRequestMethod()
|
||||||
{
|
{
|
||||||
return $_SERVER['REQUEST_METHOD'];
|
return $_SERVER['REQUEST_METHOD'];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getRequestUri()
|
public function getRequestUri()
|
||||||
{
|
{
|
||||||
$requestUri = $_SERVER['REQUEST_URI'];
|
$requestUri = $_SERVER['REQUEST_URI'];
|
||||||
$requestUri = preg_replace('/\?.*$/', '', $requestUri);
|
$requestUri = preg_replace('/\?.*$/', '', $requestUri);
|
||||||
return $requestUri;
|
return $requestUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function redirect($destination)
|
public function redirect($destination)
|
||||||
{
|
{
|
||||||
$this->setResponseCode(307);
|
$this->setResponseCode(307);
|
||||||
$this->setHeader('Location', $destination);
|
$this->setHeader('Location', $destination);
|
||||||
$this->redirected = true;
|
$this->redirected = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function nonCachedRedirect($destination)
|
public function nonCachedRedirect($destination)
|
||||||
{
|
{
|
||||||
$this->setResponseCode(303);
|
$this->setResponseCode(303);
|
||||||
$this->setHeader('Location', $destination);
|
$this->setHeader('Location', $destination);
|
||||||
$this->redirected = true;
|
$this->redirected = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isRedirecting()
|
public function isRedirecting()
|
||||||
{
|
{
|
||||||
return $this->redirected;
|
return $this->redirected;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,36 +3,36 @@ namespace Szurubooru\Helpers;
|
||||||
|
|
||||||
final class InputReader extends \ArrayObject
|
final class InputReader extends \ArrayObject
|
||||||
{
|
{
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
parent::setFlags(parent::ARRAY_AS_PROPS | parent::STD_PROP_LIST);
|
parent::setFlags(parent::ARRAY_AS_PROPS | parent::STD_PROP_LIST);
|
||||||
|
|
||||||
$_PUT = [];
|
$_PUT = [];
|
||||||
if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PUT')
|
if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PUT')
|
||||||
parse_str(file_get_contents('php://input'), $_PUT);
|
parse_str(file_get_contents('php://input'), $_PUT);
|
||||||
|
|
||||||
foreach ([$_GET, $_POST, $_PUT] as $source)
|
foreach ([$_GET, $_POST, $_PUT] as $source)
|
||||||
{
|
{
|
||||||
foreach ($source as $key => $value)
|
foreach ($source as $key => $value)
|
||||||
$this->offsetSet($key, $value);
|
$this->offsetSet($key, $value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function offsetGet($index)
|
public function offsetGet($index)
|
||||||
{
|
{
|
||||||
if (!parent::offsetExists($index))
|
if (!parent::offsetExists($index))
|
||||||
return null;
|
return null;
|
||||||
return parent::offsetGet($index);
|
return parent::offsetGet($index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function readFile($fileName)
|
public function readFile($fileName)
|
||||||
{
|
{
|
||||||
if (!isset($_FILES[$fileName]))
|
if (!isset($_FILES[$fileName]))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
if (!$_FILES[$fileName]['tmp_name'])
|
if (!$_FILES[$fileName]['tmp_name'])
|
||||||
throw new \Exception('File is probably too big.');
|
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
Loading…
Reference in a new issue