Merge remote-tracking branch 'origin/master' into develop

v1.18.x
Julian Lam 8 years ago
commit f7f5b2c8d9

@ -52,7 +52,7 @@
"morgan": "^1.3.2",
"mousetrap": "^1.5.3",
"nconf": "~0.8.2",
"nodebb-plugin-composer-default": "4.4.0",
"nodebb-plugin-composer-default": "4.4.1",
"nodebb-plugin-dbsearch": "2.0.2",
"nodebb-plugin-emoji-extended": "1.1.1",
"nodebb-plugin-emoji-one": "1.1.5",
@ -62,7 +62,7 @@
"nodebb-plugin-spam-be-gone": "0.4.10",
"nodebb-rewards-essentials": "0.0.9",
"nodebb-theme-lavender": "3.0.15",
"nodebb-theme-persona": "4.2.2",
"nodebb-theme-persona": "4.2.4",
"nodebb-theme-vanilla": "5.2.0",
"nodebb-widget-essentials": "2.0.13",
"nodemailer": "2.6.4",

@ -8,7 +8,7 @@
"clear-error-log": "Cerrar Log de Error",
"route": "Ruta",
"count": "Contar",
"no-routes-not-found": "Hooray! No 404 errors!",
"no-routes-not-found": "¡Hurra! ¡No hay errores 404!",
"clear404-confirm": "¿Estas seguro que desea borrar los registros de errores 404?",
"clear404-success": "\"404 no encontrado\" Errores borrados"
}

@ -1,5 +1,5 @@
{
"installed": "Installed",
"installed": "Instalado",
"active": "Active",
"inactive": "Inactive",
"out-of-date": "Out of Date",

@ -1,5 +1,5 @@
{
"rewards": "Rewards",
"rewards": "Recompensas",
"condition-if-users": "If User's",
"condition-is": "Is:",
"condition-then": "Then:",

@ -1,5 +1,5 @@
{
"icon": "Icon:",
"icon": "Icono:",
"change-icon": "change",
"route": "Route:",
"tooltip": "Tooltip:",

@ -1,5 +1,5 @@
{
"notifications": "Notifications",
"notifications": "Notificaciones",
"chat-messages": "Chat Messages",
"play-sound": "Play",
"incoming-message": "Incoming Message",

@ -1,5 +1,5 @@
{
"queue": "Queue",
"queue": "Cola",
"description": "There are no users in the registration queue. <br> To enable this feature, go to <a href=\"%1\">Settings &rarr; User &rarr; User Registration</a> and set <strong>Registration Type</strong> to \"Admin Approval\".",
"list.name": "Name",

@ -1,5 +1,5 @@
{
"users": "Users",
"users": "Usuarios",
"edit": "Edit",
"make-admin": "Make Admin",
"remove-admin": "Remove Admin",
@ -76,14 +76,14 @@
"alerts.validate-email-success": "Emails validated",
"alerts.password-reset-confirm": "Do you want to send password reset email(s) to these user(s)?",
"alerts.confirm-delete": "<b>Warning!</b><br/>Do you really want to delete user(s)?<br/> This action is not reversable! Only the user account will be deleted, their posts and topics will remain.",
"alerts.delete-success": "User(s) Deleted!",
"alerts.delete-success": "¡Usuario(s) Borrado(s)!",
"alerts.confirm-purge": "<b>Warning!</b><br/>Do you really want to delete user(s) and their content?<br/> This action is not reversable! All user data and content will be erased!",
"alerts.create": "Create User",
"alerts.button-create": "Create",
"alerts.button-cancel": "Cancel",
"alerts.create": "Crear Usuario",
"alerts.button-create": "Crear",
"alerts.button-cancel": "Cancelar",
"alerts.error-passwords-different": "Passwords must match!",
"alerts.error-x": "<strong>Error</strong><p>%1</p>",
"alerts.create-success": "User created!",
"alerts.create-success": "¡Usuario creado!",
"alerts.prompt-email": "Email: ",
"alerts.email-sent-to": "An invitation email has been sent to %1",

@ -1,5 +1,5 @@
{
"maintenance-mode": "Maintenance Mode",
"maintenance-mode": "Modo de Mantenimiento",
"maintenance-mode.help": "When the forum is in maintenance mode, all requests will be redirected to a static holding page. Administrators are exempt from this redirection, and are able to access the site normally.",
"maintenance-mode.message": "Maintenance Message",
"headers": "Headers",

@ -1,5 +1,5 @@
{
"notifications": "Notifications",
"notifications": "Notificaciones",
"welcome-notification": "Welcome Notification",
"welcome-notification-link": "Welcome Notification Link"
}

@ -1,5 +1,5 @@
{
"posts": "Posts",
"posts": "Mensajes",
"allow-files": "Allow users to upload regular files",
"private": "Make uploaded files private",
"max-image-width": "Resize images down to specified width (in pixels)",

@ -1,5 +1,5 @@
{
"authentication": "Authentication",
"authentication": "Autentificación",
"allow-local-login": "Allow local login",
"require-email-confirmation": "Require Email Confirmation",
"email-confirm-interval": "User may not resend a confirmation email until",

@ -103,5 +103,5 @@
"cookies.message": "Esta web usa cookies para asegurar que usted recibe la mejor experiencia de navegación.",
"cookies.accept": "De Acuerdo!",
"cookies.learn_more": "Quiero saber más",
"edited": "Edited"
"edited": "Editado"
}

@ -1,7 +1,7 @@
{
"alert.confirm-reload": "Are you sure you wish to reload NodeBB?",
"alert.confirm-restart": "Are you sure you wish to restart NodeBB?",
"alert.confirm-reload": "Weet u zeker dat u NodeBB wilt herladen?",
"alert.confirm-restart": "Weet u zeker dat u NodeBB opnieuw wilt opstarten?",
"acp-title": "%1 | NodeBB Admin Control Panel",
"settings-header-contents": "Contents"
"acp-title": "%1 | NodeBB Administratiepaneel",
"settings-header-contents": "Inhoud"
}

@ -8,11 +8,11 @@
"posted-by": "Geplaatst door",
"in-categories": "In categorieën",
"search-child-categories": "Doorzoek subcategorieën ",
"has-tags": "Has tags",
"has-tags": "Is getagged",
"reply-count": "Aantal reacties",
"at-least": "op zijn minst",
"at-most": "op zijn meest",
"relevance": "Relevance",
"relevance": "Relevantie",
"post-time": "Geplaatst op",
"newer-than": "Nieuwer dan",
"older-than": "Ouder dan",

@ -13,8 +13,8 @@
"notify_me": "Krijg een melding wanneer nieuwe reacties volgen",
"quote": "Citeren",
"reply": "Reageren",
"replies_to_this_post": "%1 Replies",
"last_reply_time": "Last reply",
"replies_to_this_post": "%1 Antwoorden",
"last_reply_time": "Laatste antwoord",
"reply-as-topic": "Reageren als onderwerp",
"guest-login-reply": "Aanmelden om te reageren",
"edit": "Aanpassen",

@ -33,7 +33,7 @@
"chat": "Chat",
"chat_with": "Chat verder met %1",
"new_chat_with": "Begin een chat met %1",
"flag-profile": "Flag Profile",
"flag-profile": "Profiel vlaggen",
"follow": "Volgen",
"unfollow": "Ontvolgen",
"more": "Meer",
@ -64,9 +64,9 @@
"upload_a_picture": "Upload een afbeelding",
"remove_uploaded_picture": "Verwijder gëuploade foto",
"upload_cover_picture": "Upload je coverafbeelding",
"remove_cover_picture_confirm": "Are you sure you want to remove the cover picture?",
"crop_picture": "Crop picture",
"upload_cropped_picture": "Crop and upload",
"remove_cover_picture_confirm": "Weet u zeker dat u de cover foto wilt verwijderen?",
"crop_picture": "Foto bijsnijden",
"upload_cropped_picture": "Bijsnijden en uploaden",
"settings": "Instellingen",
"show_email": "E-mailadres weergeven",
"show_fullname": "Laat mijn volledige naam zien",

@ -1,9 +1,9 @@
{
"custom-css": "Özel CSS",
"custom-css.description": "Enter your own CSS declarations here, which will be applied after all other styles.",
"custom-css.enable": "Enable Custom CSS",
"custom-css.enable": "Özel CSS Aktif",
"custom-header": "Custom Header",
"custom-header": "Özel Header",
"custom-header.description": "Enter custom HTML here (ex. JavaScript, Meta Tags, etc.), which will be appended to the <code>&lt;head&gt;</code> section of your forum's markup.",
"custom-header.enable": "Enable Custom Header"
}

@ -15,49 +15,49 @@
"stats.all": "Tüm Zamanlar",
"updates": "Güncellemeler",
"running-version": "You are running <strong>NodeBB v<span id=\"version\">%1</span></strong>.",
"keep-updated": "Always make sure that your NodeBB is up to date for the latest security patches and bug fixes.",
"running-version": "<strong>NodeBB v<span id=\"version\">%1</span></strong> çalışıyor.",
"keep-updated": "En son güvenlik değişiklikleri ve hata düzeltmeleri için NodeBB güncel olduğundan emin olun.",
"up-to-date": "<p>You are <strong>up-to-date</strong> <i class=\"fa fa-check\"></i></p>",
"upgrade-available": "<p>A new version (v%1) has been released. Consider <a href=\"https://docs.nodebb.org/en/latest/upgrading/index.html\">upgrading your NodeBB</a>.</p>",
"prerelease-upgrade-available": "<p>This is an outdated pre-release version of NodeBB. A new version (v%1) has been released. Consider <a href=\"https://docs.nodebb.org/en/latest/upgrading/index.html\">upgrading your NodeBB</a>.</p>",
"prerelease-warning": "<p>This is a <strong>pre-release</strong> version of NodeBB. Unintended bugs may occur. <i class=\"fa fa-exclamation-triangle\"></i></p>",
"notices": "Notices",
"restart-not-required": "Restart not required",
"restart-required": "Restart required",
"search-plugin-installed": "Search Plugin installed",
"search-plugin-not-installed": "Search Plugin not installed",
"notices": "Bildirimler",
"restart-not-required": "Yeniden başlatma gerekmiyor",
"restart-required": "Yeniden başlatma gerekiyor",
"search-plugin-installed": "Arama Eklentisi yüklendi",
"search-plugin-not-installed": "Arama Eklentisi yüklenmedi",
"search-plugin-tooltip": "Install a search plugin from the plugin page in order to activate search functionality",
"control-panel": "System Control",
"reload": "Reload",
"restart": "Restart",
"control-panel": "Sistem Kontrol",
"reload": "Tekrar Yükle",
"restart": "Yeniden Başlat",
"restart-warning": "Reloading or Restarting your NodeBB will drop all existing connections for a few seconds.",
"maintenance-mode": "Bakım Modu",
"maintenance-mode-title": "Click here to set up maintenance mode for NodeBB",
"realtime-chart-updates": "Realtime Chart Updates",
"active-users": "Active Users",
"active-users.users": "Users",
"active-users.guests": "Guests",
"active-users.total": "Total",
"active-users.connections": "Connections",
"anonymous-registered-users": "Anonymous vs Registered Users",
"anonymous": "Anonymous",
"registered": "Registered",
"user-presence": "User Presence",
"on-categories": "On categories list",
"reading-posts": "Reading posts",
"browsing-topics": "Browsing topics",
"recent": "Recent",
"unread": "Unread",
"maintenance-mode-title": "NodeBB için bakım modunu ayarlamak için buraya tıklayın",
"realtime-chart-updates": "Gerçek Zamanlı Grafik Güncellemeleri",
"active-users": "Aktif Kullanıcılar",
"active-users.users": "Kullanıcılar",
"active-users.guests": "Ziyaretçiler",
"active-users.total": "Genel Toplam",
"active-users.connections": "Bağlantılar",
"anonymous-registered-users": "Anonim vs Kayıtlı Kullanıcılar",
"anonymous": "Anonim",
"registered": "Kayıtlı",
"user-presence": "Kullanıcı Durumları",
"on-categories": "Kategoriler listesinde",
"reading-posts": "Okunan İletiler",
"browsing-topics": "Gözden Geçirilen Başlıklar",
"recent": "Yeni",
"unread": "Okunmamış",
"high-presence-topics": "High Presence Topics",
"graphs.page-views": "Page Views",
"graphs.unique-visitors": "Unique Visitors",
"graphs.registered-users": "Registered Users",
"graphs.anonymous-users": "Anonymous Users"
"graphs.page-views": "Sayfa Gösterimi",
"graphs.unique-visitors": "Benzersiz Ziyaretçiler",
"graphs.registered-users": "Kayıtlı Kullanıcılar",
"graphs.anonymous-users": "Anonim Kullanıcılar"
}

@ -19,9 +19,9 @@
"user_flagged_post_in": "<strong>%1</strong> bir iletiyi bayrakladı. <strong>%2</strong>",
"user_flagged_post_in_dual": " <strong>%1</strong> ve <strong>%2</strong> <strong>%3</strong> gönderini bayrakladı",
"user_flagged_post_in_multiple": "<strong>%1</strong> ve %2 kişi daha <strong>%3</strong> gönderini bayrakladı",
"user_flagged_user": "<strong>%1</strong> flagged a user profile (%2)",
"user_flagged_user_dual": "<strong>%1</strong> and <strong>%2</strong> flagged a user profile (%3)",
"user_flagged_user_multiple": "<strong>%1</strong> and %2 others flagged a user profile (%3)",
"user_flagged_user": "<strong>%1</strong> bayraklanan bir kullanıcı profili (%2)",
"user_flagged_user_dual": "<strong>%1</strong> ve <strong>%2</strong> bayraklanan kullanıcı profili (%3)",
"user_flagged_user_multiple": "<strong>%1</strong> ve %2 diğer bayraklanan kullanıcı profili (%3)",
"user_posted_to": "<strong>%1</strong> <strong>%2</strong> başlığına bir ileti gönderdi.",
"user_posted_to_dual": "<strong>%1</strong> ve <strong>%2</strong> gönderine cevap verdi: <strong>%3</strong>",
"user_posted_to_multiple": "<strong>%1</strong> ve %2 kişi daha gönderine cevap verdi: <strong>%3</strong>",

@ -8,11 +8,11 @@
"posted-by": "Gönderen",
"in-categories": "Kategorilerde",
"search-child-categories": "Alt kategorilerde arat",
"has-tags": "Has tags",
"has-tags": "Etiketler",
"reply-count": "Cevap Sayısı",
"at-least": "En az",
"at-most": "En fazla",
"relevance": "Relevance",
"relevance": "İlgi",
"post-time": "Yayınlama zamanı",
"newer-than": "Daha yeni",
"older-than": "Daha eski",

@ -13,8 +13,8 @@
"notify_me": "Bu konudaki cevaplardan haberdar ol",
"quote": "Alıntı",
"reply": "Cevap",
"replies_to_this_post": "%1 Replies",
"last_reply_time": "Last reply",
"replies_to_this_post": "%1 Cevap",
"last_reply_time": "Son cevap",
"reply-as-topic": "İletiye Cevap Ver",
"guest-login-reply": "Cevaplamak için giriş yapın",
"edit": "Düzenle",

@ -249,48 +249,37 @@ $(document).ready(function () {
$(window).trigger('action:script.load', data);
// Require and parse modules
var outstanding = 0;
var onReady = function () {
if (outstanding) {
return setTimeout(onReady, 100);
var outstanding = data.scripts.length;
data.scripts.map(function (script) {
if (typeof script === 'function') {
return function (next) {
script();
next();
};
}
data.scripts = data.scripts.filter(Boolean);
data.scripts.forEach(function (functionRef) {
functionRef();
});
callback();
};
data.scripts.forEach(function (script, idx) {
switch (typeof script) {
case 'string':
++outstanding;
(function (idx) {
require([script], function (script) {
if (script && script.init) {
data.scripts[idx] = script.init;
} else {
data.scripts[idx] = null;
}
--outstanding;
});
}(idx));
break;
case 'function':
// No changes needed
break;
default:
// Neither? No comprende
data.scripts[idx] = undefined;
break;
if (typeof script === 'string') {
return function (next) {
require([script], function (script) {
if (script && script.init) {
script.init();
}
next();
}, function () {
// ignore 404 error
next();
});
};
}
return null;
}).filter(Boolean).forEach(function (fn) {
fn(function () {
outstanding -= 1;
if (outstanding === 0) {
callback();
}
});
});
onReady();
};
ajaxify.loadData = function (url, callback) {

@ -2,7 +2,7 @@
/* globals define, ajaxify, socket, app, config, templates, bootbox */
define('forum/account/edit', ['forum/account/header', 'uploader', 'translator', 'components', 'cropper'], function (header, uploader, translator, components, cropper) {
define('forum/account/edit', ['forum/account/header', 'translator', 'components', 'pictureCropper'], function (header, translator, components, pictureCropper) {
var AccountEdit = {};
AccountEdit.init = function () {
@ -210,86 +210,21 @@ define('forum/account/edit', ['forum/account/header', 'uploader', 'translator',
updateHeader();
}
}
function handleImageCrop(data) {
$('#crop-picture-modal').remove();
templates.parse('modals/crop_picture', {url: data.url}, function (cropperHtml) {
translator.translate(cropperHtml, function (translated) {
var cropperModal = $(translated);
cropperModal.modal('show');
var img = document.getElementById('cropped-image');
var cropperTool = new cropper.default(img, {
aspectRatio: 1 / 1,
viewMode: 1
});
cropperModal.find('.rotate').on('click', function () {
var degrees = this.getAttribute("data-degrees");
cropperTool.rotate(degrees);
});
cropperModal.find('.flip').on('click', function () {
var option = this.getAttribute("data-option");
var method = this.getAttribute("data-method");
method === 'scaleX' ? cropperTool.scaleX(option) : cropperTool.scaleY(option);
this.setAttribute("data-option", option * -1);
});
cropperModal.find('.reset').on('click', function () {
cropperTool.reset();
});
cropperModal.find('.crop-btn').on('click', function () {
$(this).addClass('disabled');
var imageData = data.imageType ? cropperTool.getCroppedCanvas().toDataURL(data.imageType) : cropperTool.getCroppedCanvas().toDataURL();
cropperModal.find('#upload-progress-bar').css('width', '100%');
cropperModal.find('#upload-progress-box').show().removeClass('hide');
socket.emit('user.uploadCroppedPicture', {
uid: ajaxify.data.theirid,
imageData: imageData
}, function (err, imageData) {
if (err) {
cropperModal.find('#upload-progress-box').hide();
cropperModal.find('.upload-btn').removeClass('disabled');
cropperModal.find('.crop-btn').removeClass('disabled');
app.alertError(err.message);
}
onUploadComplete(imageData.url);
cropperModal.modal('hide');
});
});
cropperModal.find('.upload-btn').on('click', function () {
$(this).addClass('disabled');
cropperTool.destroy();
cropperTool = new cropper.default(img, {
viewMode: 1,
autoCropArea: 1
});
cropperModal.find('.crop-btn').trigger('click');
});
});
});
}
modal.find('[data-action="upload"]').on('click', function () {
modal.modal('hide');
uploader.show({
route: config.relative_path + '/api/user/' + ajaxify.data.userslug + '/uploadpicture',
params: {},
pictureCropper.show({
socketMethod: 'user.uploadCroppedPicture',
aspectRatio: '1 / 1',
paramName: 'uid',
paramValue: ajaxify.data.theirid,
fileSize: ajaxify.data.maximumProfileImageSize,
title: '[[user:upload_picture]]',
description: '[[user:upload_a_picture]]',
accept: '.png,.jpg,.bmp'
}, function (data) {
handleImageCrop(data);
}, function (url) {
onUploadComplete(url);
});
return false;
@ -309,7 +244,14 @@ define('forum/account/edit', ['forum/account/header', 'uploader', 'translator',
}
uploadModal.modal('hide');
handleImageCrop({url: url});
pictureCropper.handleImageCrop({
url: url,
socketMethod: 'user.uploadCroppedPicture',
aspectRatio: '1 / 1',
paramName: 'uid',
paramValue: ajaxify.data.theirid,
}, onUploadComplete);
return false;
});

@ -3,10 +3,10 @@
define('forum/account/header', [
'coverPhoto',
'uploader',
'pictureCropper',
'components',
'translator'
], function (coverPhoto, uploader, components, translator) {
], function (coverPhoto, pictureCropper, components, translator) {
var AccountHeader = {};
var isAdminOrSelfOrGlobalMod;
@ -42,7 +42,9 @@ define('forum/account/header', [
});
components.get('account/new-chat').on('click', function () {
app.newChat(ajaxify.data.uid);
app.newChat(ajaxify.data.uid, function () {
components.get('account/chat').parent().removeClass('hidden');
});
});
@ -79,10 +81,12 @@ define('forum/account/header', [
}, callback);
},
function () {
uploader.show({
pictureCropper.show({
title: '[[user:upload_cover_picture]]',
route: config.relative_path + '/api/user/' + ajaxify.data.userslug + '/uploadcover',
params: {uid: ajaxify.data.uid },
socketMethod: 'user.updateCover',
aspectRatio: '16 / 9',
paramName: 'uid',
paramValue: ajaxify.data.theirid,
accept: '.png,.jpg,.bmp'
}, function (imageUrlOnServer) {
components.get('account/cover').css('background-image', 'url(' + imageUrlOnServer + '?' + config['cache-buster'] + ')');
@ -183,7 +187,7 @@ define('forum/account/header', [
if (!confirm) {
return;
}
socket.emit('user.removeCover', {
uid: ajaxify.data.uid
}, function (err) {

@ -58,12 +58,25 @@ define('forum/category', [
});
});
handleScrollToTopicIndex();
handleIgnoreWatch(cid);
$(window).trigger('action:topics.loaded', {topics: ajaxify.data.topics});
$(window).trigger('action:category.loaded', {cid: ajaxify.data.cid});
};
function handleScrollToTopicIndex() {
var parts = window.location.pathname.split('/');
var topicIndex = parts[parts.length - 1];
if (topicIndex && utils.isNumber(topicIndex)) {
topicIndex = Math.max(0, parseInt(topicIndex, 10) - 1);
if (topicIndex && window.location.search.indexOf('page=') === -1) {
navigator.scrollToElement($('[component="category/topic"][data-index="' + topicIndex + '"]'), true, 0);
}
}
}
function handleIgnoreWatch(cid) {
$('[component="category/watching"], [component="category/ignoring"]').on('click', function () {
var $this = $(this);
@ -104,14 +117,10 @@ define('forum/category', [
};
$(window).on('action:ajaxify.contentLoaded', function (ev, data) {
if (ajaxify.data.template.category) {
var cid = ajaxify.data.cid;
if (!cid) {
return;
}
if (ajaxify.data.template.category && ajaxify.data.cid) {
var bookmarkIndex = localStorage.getItem('category:' + cid + ':bookmark');
var clickedIndex = localStorage.getItem('category:' + cid + ':bookmark:clicked');
var bookmarkIndex = localStorage.getItem('category:' + ajaxify.data.cid + ':bookmark');
var clickedIndex = localStorage.getItem('category:' + ajaxify.data.cid + ':bookmark:clicked');
bookmarkIndex = Math.max(0, parseInt(bookmarkIndex, 10) || 0);
clickedIndex = Math.max(0, parseInt(clickedIndex, 10) || 0);

@ -6,10 +6,10 @@ define('forum/groups/details', [
'iconSelect',
'components',
'coverPhoto',
'uploader',
'pictureCropper',
'translator',
'vendor/colorpicker/colorpicker'
], function (memberList, iconSelect, components, coverPhoto, uploader, translator) {
], function (memberList, iconSelect, components, coverPhoto, pictureCropper, translator) {
var Details = {};
var groupName;
@ -31,10 +31,12 @@ define('forum/groups/details', [
}, callback);
},
function () {
uploader.show({
pictureCropper.show({
title: '[[groups:upload-group-cover]]',
route: config.relative_path + '/api/groups/uploadpicture',
params: {groupName: groupName}
socketMethod: 'groups.cover.update',
aspectRatio: '16 / 9',
paramName: 'groupName',
paramValue: groupName
}, function (imageUrlOnServer) {
components.get('groups/cover').css('background-image', 'url(' + imageUrlOnServer + ')');
});

@ -198,7 +198,7 @@ define('forum/topic/postTools', [
}
function onReplyClicked(button, tid) {
var selectedText = getSelectedText(button);
var selectedNode = getSelectedNode();
showStaleWarning(function () {
var username = getUserName(button);
@ -208,15 +208,15 @@ define('forum/topic/postTools', [
var toPid = button.is('[component="post/reply"]') ? getData(button, 'data-pid') : null;
if (selectedText) {
if (selectedNode.text && (!toPid || !selectedNode.pid || toPid === selectedNode.pid)) {
username = username || selectedNode.username;
$(window).trigger('action:composer.addQuote', {
tid: tid,
slug: ajaxify.data.slug,
index: getData(button, 'data-index'),
pid: toPid,
topicName: ajaxify.data.titleRaw,
username: username,
text: selectedText
text: selectedNode.text,
selectedPid: selectedNode.pid
});
} else {
$(window).trigger('action:composer.post.new', {
@ -230,16 +230,14 @@ define('forum/topic/postTools', [
}
function onQuoteClicked(button, tid) {
var selectedText = getSelectedText(button);
var selectedNode = getSelectedNode();
showStaleWarning(function () {
function quote(text) {
$(window).trigger('action:composer.addQuote', {
tid: tid,
slug: ajaxify.data.slug,
index: getData(button, 'data-index'),
pid: pid,
pid: toPid,
username: username,
topicName: ajaxify.data.titleRaw,
text: text
@ -247,12 +245,12 @@ define('forum/topic/postTools', [
}
var username = getUserName(button);
var pid = getData(button, 'data-pid');
var toPid = getData(button, 'data-pid');
if (selectedText) {
return quote(selectedText);
if (selectedNode.text && toPid && toPid === selectedNode.pid) {
return quote(selectedNode.text);
}
socket.emit('posts.getRawPost', pid, function (err, post) {
socket.emit('posts.getRawPost', toPid, function (err, post) {
if (err) {
return app.alertError(err.message);
}
@ -262,12 +260,20 @@ define('forum/topic/postTools', [
});
}
function getSelectedText(button) {
var selectionText = '';
function getSelectedNode() {
var selectedText = '';
var selectedPid;
var username = '';
var selection = window.getSelection ? window.getSelection() : document.selection.createRange();
var content = button.parents('[component="post"]').find('[component="post/content"]').get(0);
var postContents = $('[component="post"] [component="post/content"]');
var content;
postContents.each(function (index, el) {
if (selection && selection.containsNode && el && selection.containsNode(el, true)) {
content = el;
}
});
if (selection && selection.containsNode && content && selection.containsNode(content, true)) {
if (content) {
var bounds = document.createRange();
bounds.selectNodeContents(content);
var range = selection.getRangeAt(0).cloneRange();
@ -278,10 +284,13 @@ define('forum/topic/postTools', [
range.setEnd(bounds.endContainer, bounds.endOffset);
}
bounds.detach();
selectionText = range.toString();
selectedText = range.toString();
var postEl = $(content).parents('[component="post"]');
selectedPid = postEl.attr('data-pid');
username = getUserName($(content));
range.detach();
}
return selectionText;
return {text: selectedText, pid: selectedPid, username: username};
}
function bookmarkPost(button, pid) {

@ -238,14 +238,17 @@ define('navigator', ['forum/pagination', 'components'], function (pagination, co
navigator.scrollToPostIndex = function (postIndex, highlight, duration) {
var scrollTo = components.get('post', 'index', postIndex);
var postHeight = scrollTo.height();
var viewportHeight = $(window).height();
var navbarHeight = components.get('navbar').height();
navigator.scrollToElement(scrollTo, highlight, duration);
};
navigator.scrollToElement = function(scrollTo, highlight, duration) {
if (!scrollTo.length) {
navigator.scrollActive = false;
return;
}
var postHeight = scrollTo.height();
var viewportHeight = $(window).height();
var navbarHeight = components.get('navbar').height();
// Temporarily disable navigator update on scroll
$(window).off('scroll', navigator.update);
@ -290,13 +293,8 @@ define('navigator', ['forum/pagination', 'components'], function (pagination, co
}
}
if (components.get('topic').length) {
animateScroll();
} else {
navigator.scrollActive = false;
}
animateScroll();
};
return navigator;
});

@ -0,0 +1,150 @@
'use strict';
/* globals define, socket, app, templates */
define('pictureCropper', ['translator', 'cropper'], function (translator, cropper) {
var module = {};
module.show = function (data, callback) {
var fileSize = data.hasOwnProperty('fileSize') && data.fileSize !== undefined ? parseInt(data.fileSize, 10) : false;
parseModal({
showHelp: data.hasOwnProperty('showHelp') && data.showHelp !== undefined ? data.showHelp : true,
fileSize: fileSize,
title: data.title || '[[global:upload_file]]',
description: data.description || '',
button: data.button || '[[global:upload]]',
accept: data.accept ? data.accept.replace(/,/g, '&#44; ') : ''
}, function (uploadModal) {
uploadModal = $(uploadModal);
uploadModal.modal('show');
uploadModal.on('hidden.bs.modal', function () {
uploadModal.remove();
});
uploadModal.find('#fileUploadSubmitBtn').on('click', function () {
$(this).addClass('disabled');
data.uploadModal = uploadModal;
onSubmit(data, callback);
return false;
});
});
};
module.handleImageCrop = function (data, callback) {
$('#crop-picture-modal').remove();
templates.parse('modals/crop_picture', {url: data.url}, function (cropperHtml) {
translator.translate(cropperHtml, function (translated) {
var cropperModal = $(translated);
cropperModal.modal('show');
var img = document.getElementById('cropped-image');
var cropperTool = new cropper.default(img, {
aspectRatio: data.aspectRatio,
viewMode: 1,
ready: function () {
cropperModal.find('.rotate').on('click', function () {
var degrees = this.getAttribute("data-degrees");
cropperTool.rotate(degrees);
});
cropperModal.find('.flip').on('click', function () {
var option = this.getAttribute("data-option");
var method = this.getAttribute("data-method");
method === 'scaleX' ? cropperTool.scaleX(option) : cropperTool.scaleY(option);
this.setAttribute("data-option", option * -1);
});
cropperModal.find('.reset').on('click', function () {
cropperTool.reset();
});
cropperModal.find('.crop-btn').on('click', function () {
$(this).addClass('disabled');
var imageData = data.imageType ? cropperTool.getCroppedCanvas().toDataURL(data.imageType) : cropperTool.getCroppedCanvas().toDataURL();
cropperModal.find('#upload-progress-bar').css('width', '100%');
cropperModal.find('#upload-progress-box').show().removeClass('hide');
var socketData = {};
socketData[data.paramName] = data.paramValue;
socketData['imageData'] = imageData;
socket.emit(data.socketMethod, socketData, function (err, imageData) {
if (err) {
cropperModal.find('#upload-progress-box').hide();
cropperModal.find('.upload-btn').removeClass('disabled');
cropperModal.find('.crop-btn').removeClass('disabled');
return app.alertError(err.message);
}
callback(imageData.url);
cropperModal.modal('hide');
});
});
cropperModal.find('.upload-btn').on('click', function () {
$(this).addClass('disabled');
cropperTool.destroy();
cropperTool = new cropper.default(img, {
viewMode: 1,
autoCropArea: 1,
ready: function () {
cropperModal.find('.crop-btn').trigger('click');
}
});
});
}
});
});
});
};
function onSubmit(data, callback) {
function showAlert(type, message) {
module.hideAlerts(data.uploadModal);
if (type === 'error') {
data.uploadModal.find('#fileUploadSubmitBtn').removeClass('disabled');
}
data.uploadModal.find('#alert-' + type).translateText(message).removeClass('hide');
}
var fileInput = data.uploadModal.find('#fileInput');
if (!fileInput.val()) {
return showAlert('error', '[[uploads:select-file-to-upload]]');
}
var file = fileInput[0].files[0];
var reader = new FileReader();
var imageUrl;
var imageType = file.type;
reader.addEventListener("load", function () {
imageUrl = reader.result;
data.uploadModal.modal('hide');
module.handleImageCrop({
url: imageUrl,
imageType: imageType,
socketMethod: data.socketMethod,
aspectRatio: data.aspectRatio,
paramName: data.paramName,
paramValue: data.paramValue
}, callback);
}, false);
if (file) {
reader.readAsDataURL(file);
}
}
function parseModal(tplVals, callback) {
templates.parse('partials/modals/upload_file_modal', tplVals, function (html) {
translator.translate(html, callback);
});
}
return module;
});

@ -1,8 +1,8 @@
'use strict';
/* globals define, ajaxify, socket, app, templates */
/* globals define, templates */
define('uploader', ['translator', 'cropper'], function (translator, cropper) {
define('uploader', ['translator'], function (translator) {
var module = {};
@ -61,27 +61,46 @@ define('uploader', ['translator', 'cropper'], function (translator, cropper) {
uploadModal.find('#alert-' + type).translateText(message).removeClass('hide');
}
showAlert('status', '[[uploads:uploading-file]]');
uploadModal.find('#upload-progress-bar').css('width', '0%');
uploadModal.find('#upload-progress-box').show().removeClass('hide');
var fileInput = uploadModal.find('#fileInput');
if (!fileInput.val()) {
return showAlert('error', '[[uploads:select-file-to-upload]]');
}
var file = fileInput[0].files[0];
var reader = new FileReader();
var imageUrl;
var imageType = file.type;
reader.addEventListener("load", function () {
imageUrl = reader.result;
uploadModal.modal('hide');
callback({url: imageUrl, imageType: imageType});
}, false);
if (file) {
reader.readAsDataURL(file);
if (!hasValidFileSize(fileInput[0], fileSize)) {
return showAlert('error', '[[error:file-too-big, ' + fileSize + ']]');
}
uploadModal.find('#uploadForm').ajaxSubmit({
headers: {
'x-csrf-token': config.csrf_token
},
error: function (xhr) {
xhr = maybeParse(xhr);
showAlert('error', xhr.responseJSON ? (xhr.responseJSON.error || xhr.statusText) : 'error uploading, code : ' + xhr.status);
},
uploadProgress: function (event, position, total, percent) {
uploadModal.find('#upload-progress-bar').css('width', percent + '%');
},
success: function (response) {
response = maybeParse(response);
if (response.error) {
return showAlert('error', response.error);
}
callback(response[0].url);
showAlert('success', '[[uploads:upload-success]]');
setTimeout(function () {
module.hideAlerts(uploadModal);
uploadModal.modal('hide');
}, 750);
}
});
}
function parseModal(tplVals, callback) {
@ -90,5 +109,23 @@ define('uploader', ['translator', 'cropper'], function (translator, cropper) {
});
}
function maybeParse(response) {
if (typeof response === 'string') {
try {
return $.parseJSON(response);
} catch (e) {
return {error: '[[error:parse-error]]'};
}
}
return response;
}
function hasValidFileSize(fileElement, maxSize) {
if (window.FileReader && maxSize) {
return fileElement.files[0].size <= maxSize * 1000;
}
return true;
}
return module;
});
});

@ -69,7 +69,7 @@ categoryController.get = function (req, res, callback) {
}
if (!settings.usePagination) {
topicIndex = Math.max(topicIndex - (settings.topicsPerPage - 1), 0);
topicIndex = Math.max(0, topicIndex - (Math.ceil(settings.topicsPerPage / 2) - 1));
} else if (!req.query.page) {
var index = Math.max(parseInt((topicIndex || 0), 10), 0);
currentPage = Math.ceil((index + 1) / settings.topicsPerPage);

@ -365,7 +365,7 @@ Controllers.handle404 = function (req, res) {
if (isClientScript.test(req.url)) {
res.type('text/javascript').status(200).send('');
} else if (req.path.startsWith(relativePath + '/uploads') || (req.get('accept') && req.get('accept').indexOf('text/html') === -1) || req.path === '/favicon.ico') {
} else if (req.path.startsWith(relativePath + '/assets/uploads') || (req.get('accept') && req.get('accept').indexOf('text/html') === -1) || req.path === '/favicon.ico') {
meta.errors.log404(req.path || '');
res.sendStatus(404);
} else if (req.accepts('html')) {

@ -32,15 +32,15 @@ exports.read = function read(callback) {
fs.readFile(filePath, function (err, buffer) {
if (err) {
winston.warn('[cache-buster] could not read cache buster: ' + err.message);
return callback();
return callback(null, generate());
}
buffer = buffer.toString();
if (buffer) {
cached = buffer;
return callback(null, cached);
if (!buffer || buffer.toString().length !== 11) {
winston.warn('[cache-buster] cache buster string invalid: expected /[a-z0-9]{11}/, got `' + buffer + '`');
return callback(null, generate());
}
callback();
cached = buffer.toString();
callback(null, cached);
});
};

@ -143,7 +143,12 @@ module.exports = function (Meta) {
return callback(err);
}
postcss(global.env === 'development' ? [ autoprefixer ] : [ autoprefixer, clean() ]).process(lessOutput.css).then(function (result) {
postcss(global.env === 'development' ? [ autoprefixer ] : [
autoprefixer,
clean({
processImportFrom: ['local']
}),
]).process(lessOutput.css).then(function (result) {
result.warnings().forEach(function (warn) {
winston.verbose(warn.toString());
});

Loading…
Cancel
Save