Merge branch 'staging' of github.com:xwiki-labs/cryptpad into staging

pull/1/head
yflory 5 years ago
commit 17103e89fc

@ -9,5 +9,8 @@ define(['/common/application_config_internal.js'], function (AppConfig) {
// Example: If you want to remove the survey link in the menu: // Example: If you want to remove the survey link in the menu:
// AppConfig.surveyURL = ""; // AppConfig.surveyURL = "";
// To inform users of the support ticket panel which languages your admins speak:
//AppConfig.supportLanguages = [ 'en', 'fr' ];
return AppConfig; return AppConfig;
}); });

@ -1364,7 +1364,6 @@ define([
case 'import': case 'import':
button = $('<button>', { button = $('<button>', {
'class': 'fa fa-upload cp-toolbar-icon-import', 'class': 'fa fa-upload cp-toolbar-icon-import',
// XXX text is weird anywhere other than the drive
title: Messages.importButtonTitle, title: Messages.importButtonTitle,
}).append($('<span>', {'class': 'cp-toolbar-drawer-element'}).text(Messages.importButton)); }).append($('<span>', {'class': 'cp-toolbar-drawer-element'}).text(Messages.importButton));
/*if (data.types) { /*if (data.types) {
@ -2299,6 +2298,49 @@ define([
return $container; return $container;
}; };
UIElements.displayInfoMenu = function (Common, metadataMgr) {
//var padType = metadataMgr.getMetadata().type;
var priv = metadataMgr.getPrivateData();
var origin = priv.origin;
Messages.help_faq = "Review our list of frequently asked questions"; // XXX
var faqLine = h('p',
h('a', {
target: '_blank',
rel: 'noreferrer noopener',
href: origin + '/faq.html',
}, Messages.help_faq)
);
// XXX link to the most recent changelog/release notes
// XXX FAQ
// XXX GitHub
// XXX privacy policy
// XXX legal notice
var content = h('div', [
// CryptPad version number
h('h6', Pages.versionString),
// First point users to our FAQ
faqLine,
// Link to the support ticket form in case their
// question isn't answered by the FAQ
//supportLine,
]);
var buttons = [
{
className: 'primary',
name: Messages.filePicker_close,
onClick: function () {},
keys: [27],
},
];
var modal = UI.dialog.customModal(content, {buttons: buttons });
UI.openCustomModal(modal);
};
UIElements.createUserAdminMenu = function (Common, config) { UIElements.createUserAdminMenu = function (Common, config) {
var metadataMgr = Common.getMetadataMgr(); var metadataMgr = Common.getMetadataMgr();
@ -2479,20 +2521,17 @@ define([
}, },
}); });
} }
if (Pages.versionString) { Messages.user_about = 'About CryptPad'; // XXX
Messages.user_about = Messages.about; // XXX "About CryptPad" options.push({
options.push({ tag: 'a',
tag: 'a', attributes: {
attributes: { 'class': 'cp-toolbar-about fa fa-info',
'class': 'cp-toolbar-about fa fa-info', },
}, content: h('span', Messages.user_about),
content: h('span', Messages.user_about), action: function () {
action: function () { UIElements.displayInfoMenu(Common, metadataMgr);
// XXX UIElements.createHelpButton },
UI.alert(Pages.versionString); });
},
});
}
options.push({ tag: 'hr' }); options.push({ tag: 'hr' });
// Add login or logout button depending on the current status // Add login or logout button depending on the current status

@ -1097,7 +1097,7 @@ define([
var priv = metadataMgr.getPrivateData(); var priv = metadataMgr.getPrivateData();
var useUnsafe = Util.find(priv, ['settings', 'security', 'unsafeLinks']); var useUnsafe = Util.find(priv, ['settings', 'security', 'unsafeLinks']);
if (useUnsafe !== false) { // true of undefined: use unsafe links if (useUnsafe === true) {
return void window.open(APP.origin + href); return void window.open(APP.origin + href);
} }

@ -874,7 +874,7 @@ define([
// Use hidden hash if needed (we're an owner of this pad so we know it is stored) // Use hidden hash if needed (we're an owner of this pad so we know it is stored)
var useUnsafe = Util.find(priv, ['settings', 'security', 'unsafeLinks']); var useUnsafe = Util.find(priv, ['settings', 'security', 'unsafeLinks']);
var href = (priv.readOnly && data.roHref) ? data.roHref : data.href; var href = (priv.readOnly && data.roHref) ? data.roHref : data.href;
if (useUnsafe === false) { if (useUnsafe !== true) {
var newParsed = Hash.parsePadUrl(href); var newParsed = Hash.parsePadUrl(href);
var newSecret = Hash.getSecrets(newParsed.type, newParsed.hash, newPass); var newSecret = Hash.getSecrets(newParsed.type, newParsed.hash, newPass);
var newHash = Hash.getHiddenHashFromKeys(parsed.type, newSecret, {}); var newHash = Hash.getHiddenHashFromKeys(parsed.type, newSecret, {});

@ -399,14 +399,16 @@ define([
e.stopPropagation(); e.stopPropagation();
m.hide(); m.hide();
var $mt = $menu.data('mediatag'); var $mt = $menu.data('mediatag');
if ($(this).hasClass("cp-app-code-context-saveindrive")) { var $this = $(this);
if ($this.hasClass("cp-app-code-context-saveindrive")) {
common.importMediaTag($mt); common.importMediaTag($mt);
} }
else if ($(this).hasClass("cp-app-code-context-download")) { else if ($this.hasClass("cp-app-code-context-download")) {
var media = $mt[0]._mediaObject; var media = Util.find($mt, [0, '_mediaObject']);
if (!(media && media._blob)) { return void console.error($mt); }
window.saveAs(media._blob.content, media.name); window.saveAs(media._blob.content, media.name);
} }
else if ($(this).hasClass("cp-app-code-context-open")) { else if ($this.hasClass("cp-app-code-context-open")) {
$mt.trigger('preview'); $mt.trigger('preview');
} }
}); });

@ -7,9 +7,10 @@ define([
'/common/cryptget.js', '/common/cryptget.js',
'/common/outer/mailbox.js', '/common/outer/mailbox.js',
'/customize/messages.js', '/customize/messages.js',
'/common/common-realtime.js',
'/bower_components/nthen/index.js', '/bower_components/nthen/index.js',
'/bower_components/chainpad-crypto/crypto.js', '/bower_components/chainpad-crypto/crypto.js',
], function (AppConfig, Feedback, Hash, Util, Messaging, Crypt, Mailbox, Messages, nThen, Crypto) { ], function (AppConfig, Feedback, Hash, Util, Messaging, Crypt, Mailbox, Messages, Realtime, nThen, Crypto) {
// Start migration check // Start migration check
// Versions: // Versions:
// 1: migrate pad attributes // 1: migrate pad attributes
@ -456,6 +457,37 @@ define([
if (version < 10) { if (version < 10) {
fixTodo(); fixTodo();
} }
}).nThen(function (waitFor) {
if (version >= 11) { return; }
// Migration 11: alert users of safe links as the new default
var done = function () {
Feedback.send('Migrate-11', true);
userObject.version = version = 11;
};
/* userObject.settings.security.unsafeLinks
undefined => the user has never touched it
false => the user has explicitly enabled "safe links"
true => the user has explicitly disabled "safe links"
*/
var unsafeLinks = Util.find(userObject, [ 'settings', 'security', 'unsafeLinks' ]);
if (unsafeLinks !== undefined) { return void done(); }
var ctx = {
store: store,
};
var myData = Messaging.createData(userObject);
Mailbox.sendTo(ctx, 'SAFE_LINKS_DEFAULT', {
user: myData,
}, {
channel: myData.notifications,
curvePublic: myData.curvePublic
}, waitFor(function (obj) {
if (obj && obj.error) { return void console.error(obj); }
done();
}));
/*}).nThen(function (waitFor) { /*}).nThen(function (waitFor) {
// Test progress bar in the loading screen // Test progress bar in the loading screen
var i = 0; var i = 0;
@ -467,7 +499,7 @@ define([
}, 500); }, 500);
progress(0, 0);*/ progress(0, 0);*/
}).nThen(function () { }).nThen(function () {
setTimeout(cb); Realtime.whenRealtimeSyncs(store.realtime, Util.bake(cb));
}); });
}; };
}); });

@ -387,6 +387,21 @@ define([
} }
}; };
handlers['SAFE_LINKS_DEFAULT'] = function (common, data) {
Messages.settings_safeLinkDefault = "SAFE LINKS ARE NOW DEFAULT"; // XXX
var content = data.content;
content.getFormatText = function () {
return Messages.settings_safeLinkDefault;
};
content.handler = function () {
common.openURL('/settings/#security');
};
if (!content.archived) {
content.dismissHandler = defaultDismiss(common, data);
}
};
// NOTE: don't forget to fixHTML everything returned by "getFormatText" // NOTE: don't forget to fixHTML everything returned by "getFormatText"

@ -41,6 +41,9 @@ define([
pad: { pad: {
width: true width: true
}, },
security: {
unsafeLinks: false
},
general: { general: {
allowUserFeedback: true allowUserFeedback: true
} }

@ -515,6 +515,12 @@ define([
cb(); cb();
}; };
handlers["SAFE_LINKS_DEFAULT"] = function (ctx, box, data, cb) {
var curve = ctx.store.proxy.curvePublic;
if (data.msg.author !== curve) { return void cb(true); }
cb();
};
// Hide duplicates when receiving a SHARE_PAD notification: // Hide duplicates when receiving a SHARE_PAD notification:
// Keep only one notification per channel: the stronger and more recent one // Keep only one notification per channel: the stronger and more recent one
var comments = {}; var comments = {};

@ -806,16 +806,8 @@ define([
var title = currentTabTitle.replace(/\{title\}/g, currentTitle || 'CryptPad'); var title = currentTabTitle.replace(/\{title\}/g, currentTitle || 'CryptPad');
document.title = title; document.title = title;
}; };
sframeChan.on('Q_SET_PAD_TITLE_IN_DRIVE', function (newData, cb) {
var newTitle = newData.title || newData.defaultTitle; var setPadTitle = function (data, cb) {
currentTitle = newTitle;
setDocumentTitle();
var data = {
password: password,
title: newTitle,
channel: secret.channel,
path: initialPathInDrive // Where to store the pad if we don't have it in our drive
};
Cryptpad.setPadTitle(data, function (err, obj) { Cryptpad.setPadTitle(data, function (err, obj) {
if (!err && !(obj && obj.notStored)) { if (!err && !(obj && obj.notStored)) {
// No error and the pad was correctly stored // No error and the pad was correctly stored
@ -823,13 +815,26 @@ define([
var opts = parsed.getOptions(); var opts = parsed.getOptions();
var hash = Utils.Hash.getHiddenHashFromKeys(parsed.type, secret, opts); var hash = Utils.Hash.getHiddenHashFromKeys(parsed.type, secret, opts);
var useUnsafe = Utils.Util.find(settings, ['security', 'unsafeLinks']); var useUnsafe = Utils.Util.find(settings, ['security', 'unsafeLinks']);
if (useUnsafe === false && window.history && window.history.replaceState) { if (useUnsafe !== true && window.history && window.history.replaceState) {
if (!/^#/.test(hash)) { hash = '#' + hash; } if (!/^#/.test(hash)) { hash = '#' + hash; }
window.history.replaceState({}, window.document.title, hash); window.history.replaceState({}, window.document.title, hash);
} }
} }
cb({error: err}); cb({error: err});
}); });
};
sframeChan.on('Q_SET_PAD_TITLE_IN_DRIVE', function (newData, cb) {
var newTitle = newData.title || newData.defaultTitle;
currentTitle = newTitle;
setDocumentTitle();
var data = {
password: password,
title: newTitle,
channel: secret.channel,
path: initialPathInDrive // Where to store the pad if we don't have it in our drive
};
setPadTitle(data, cb);
}); });
sframeChan.on('EV_SET_TAB_TITLE', function (newTabTitle) { sframeChan.on('EV_SET_TAB_TITLE', function (newTabTitle) {
currentTabTitle = newTabTitle; currentTabTitle = newTabTitle;
@ -854,20 +859,7 @@ define([
path: initialPathInDrive, // Where to store the pad if we don't have it in our drive path: initialPathInDrive, // Where to store the pad if we don't have it in our drive
forceSave: true forceSave: true
}; };
Cryptpad.setPadTitle(data, function (err) { setPadTitle(data, cb);
if (!err && !(obj && obj.notStored)) {
// No error and the pad was correctly stored
// hide the hash
var opts = parsed.getOptions();
var hash = Utils.Hash.getHiddenHashFromKeys(parsed.type, secret, opts);
var useUnsafe = Utils.Util.find(settings, ['security', 'unsafeLinks']);
if (useUnsafe === false && window.history && window.history.replaceState) {
if (!/^#/.test(hash)) { hash = '#' + hash; }
window.history.replaceState({}, window.document.title, hash);
}
}
cb({error: err});
});
}); });
sframeChan.on('Q_IS_PAD_STORED', function (data, cb) { sframeChan.on('Q_IS_PAD_STORED', function (data, cb) {
Cryptpad.getPadAttribute('title', function (err, data) { Cryptpad.getPadAttribute('title', function (err, data) {

@ -14,7 +14,7 @@
"error": "Eroare", "error": "Eroare",
"saved": "Salvat", "saved": "Salvat",
"synced": "Totul a fost salvat", "synced": "Totul a fost salvat",
"deleted": "Pad șters din CryptDrive-ul tău", "deleted": "Șters",
"disconnected": "Deconectat", "disconnected": "Deconectat",
"synchronizing": "Se sincronizează", "synchronizing": "Se sincronizează",
"reconnecting": "Reconectare...", "reconnecting": "Reconectare...",
@ -239,7 +239,7 @@
"settings_pinningNotAvailable": "Pad-urile fixate sunt disponibile doar utilizatorilor înregistrați.", "settings_pinningNotAvailable": "Pad-urile fixate sunt disponibile doar utilizatorilor înregistrați.",
"settings_pinningError": "Ceva nu a funcționat", "settings_pinningError": "Ceva nu a funcționat",
"settings_usageAmount": "Pad-urile tale fixate ocupă {0}MB", "settings_usageAmount": "Pad-urile tale fixate ocupă {0}MB",
"settings_logoutEverywhereTitle": "Deloghează-te peste tot", "settings_logoutEverywhereTitle": "Închide sesiunile remote",
"settings_logoutEverywhere": "Deloghează-te din toate sesiunile web", "settings_logoutEverywhere": "Deloghează-te din toate sesiunile web",
"settings_logoutEverywhereConfirm": "Ești sigur? Va trebui să te loghezi, din nou, pe toate device-urile tale.", "settings_logoutEverywhereConfirm": "Ești sigur? Va trebui să te loghezi, din nou, pe toate device-urile tale.",
"upload_serverError": "Eroare de server: fișierele tale nu pot fi încărcate la momentul acesta.", "upload_serverError": "Eroare de server: fișierele tale nu pot fi încărcate la momentul acesta.",
@ -317,7 +317,8 @@
"todo": "De facut", "todo": "De facut",
"contacts": "Contacte", "contacts": "Contacte",
"sheet": "Foaie de calcul", "sheet": "Foaie de calcul",
"kanban": "Foaie Kanban" "kanban": "Foaie Kanban",
"teams": "Echipe"
}, },
"button_newkanban": "Kanban nou", "button_newkanban": "Kanban nou",
"padNotPinned": "Aceasta filă va expira după 3 luni de inactivitate, {0}autentifică-te{1} sau {2}înregistrează-te{3} pentru a o păstra.", "padNotPinned": "Aceasta filă va expira după 3 luni de inactivitate, {0}autentifică-te{1} sau {2}înregistrează-te{3} pentru a o păstra.",
@ -455,7 +456,7 @@
"profile_create": "Crează un profil", "profile_create": "Crează un profil",
"profile_description": "Descriere", "profile_description": "Descriere",
"profile_fieldSaved": "Valoare nouă salvată: {0}", "profile_fieldSaved": "Valoare nouă salvată: {0}",
"userlist_addAsFriendTitle": "Adaugă \"{0}\" în lista de contacte", "userlist_addAsFriendTitle": "Trimite o cerere de contact către \"{0}\"",
"canvas_currentBrush": "Culoarea curentă", "canvas_currentBrush": "Culoarea curentă",
"profile_viewMyProfile": "Vezi profilul tău", "profile_viewMyProfile": "Vezi profilul tău",
"contacts_title": "Contacte", "contacts_title": "Contacte",
@ -477,7 +478,7 @@
"contacts_confirmRemoveHistory": "Ești sigur că vrei să ștergi definitiv istoricul chat-ului? Datele nu vor putea fi recuperate", "contacts_confirmRemoveHistory": "Ești sigur că vrei să ștergi definitiv istoricul chat-ului? Datele nu vor putea fi recuperate",
"contacts_removeHistoryServerError": "A apărut o eroare în timpul ștergerii istoricului chat-ului. Te rugăm să încerci mai târziu", "contacts_removeHistoryServerError": "A apărut o eroare în timpul ștergerii istoricului chat-ului. Te rugăm să încerci mai târziu",
"contacts_fetchHistory": "Recuperează istoricul mai vechi", "contacts_fetchHistory": "Recuperează istoricul mai vechi",
"contacts_friends": "Prieteni", "contacts_friends": "Persoane de contact",
"contacts_rooms": "Camere", "contacts_rooms": "Camere",
"contacts_leaveRoom": "Părăsește această cameră", "contacts_leaveRoom": "Părăsește această cameră",
"contacts_online": "Un alt utilizator din această cameră este online", "contacts_online": "Un alt utilizator din această cameră este online",
@ -492,7 +493,7 @@
"fm_removePermanentlyNote": "Pad-urile tale vor fi șterse de pe server dacă vei continua", "fm_removePermanentlyNote": "Pad-urile tale vor fi șterse de pe server dacă vei continua",
"fm_deleteOwnedPad": "Ești sigur că vrei să ștergi definitiv acest pad de pe server?", "fm_deleteOwnedPad": "Ești sigur că vrei să ștergi definitiv acest pad de pe server?",
"fm_deleteOwnedPads": "Ești sigur că vrei să ștergi definitiv aceste pad-uri de pe server?", "fm_deleteOwnedPads": "Ești sigur că vrei să ștergi definitiv aceste pad-uri de pe server?",
"fm_info_recent": "Listează pad-urile deschise sau modificate recent", "fm_info_recent": "Aceste documente au fost deschise sau modificate recent de către tine sau de către colaboratorii tăi.",
"fm_info_sharedFolder": "Acesta este un dosar partajat. Deoarece nu ești logat, îl poți vizualiza doar în modul citire.<br><a href=\"/register/\">Înscrie-te</a> sau <a href=\"/loghează-te/\">Log in</a> pentru a-l putea importa in CryptDrive-ul tău si a-l modifica.", "fm_info_sharedFolder": "Acesta este un dosar partajat. Deoarece nu ești logat, îl poți vizualiza doar în modul citire.<br><a href=\"/register/\">Înscrie-te</a> sau <a href=\"/loghează-te/\">Log in</a> pentru a-l putea importa in CryptDrive-ul tău si a-l modifica.",
"fm_info_owned": "Ești proprietarul pad-urilor afișate aici. Acest lucru înseamna că le poți șterge definitiv de pe server oricând vei dori. Dacă decizi să le ștergi, alți utilizatori nu le vor mai putea accesa.", "fm_info_owned": "Ești proprietarul pad-urilor afișate aici. Acest lucru înseamna că le poți șterge definitiv de pe server oricând vei dori. Dacă decizi să le ștergi, alți utilizatori nu le vor mai putea accesa.",
"fm_error_cantPin": "O eroare internă de server a apărut. Te rugăm să reîncarci pagina și să încerci din nou.", "fm_error_cantPin": "O eroare internă de server a apărut. Te rugăm să reîncarci pagina și să încerci din nou.",
@ -510,7 +511,7 @@
"fm_tags_used": "Numărul de utilizări", "fm_tags_used": "Numărul de utilizări",
"fm_restoreDrive": "Drive-ul tău va fi setat la o versiune aneterioară. Pentru a obține cele mai bune rezultate, te rugăm să eviți să aduci modificări în drive-ul tău până când procesul va fi terminat.", "fm_restoreDrive": "Drive-ul tău va fi setat la o versiune aneterioară. Pentru a obține cele mai bune rezultate, te rugăm să eviți să aduci modificări în drive-ul tău până când procesul va fi terminat.",
"fm_moveNestedSF": "Nu poti plasa un folder partajat în interiorul altuia. Folderul {0} nu a fost mutat.", "fm_moveNestedSF": "Nu poti plasa un folder partajat în interiorul altuia. Folderul {0} nu a fost mutat.",
"fm_passwordProtected": "Acest document este protejat cu o parolă", "fm_passwordProtected": "Parolă protejată",
"fc_newsharedfolder": "Folder partajat nou", "fc_newsharedfolder": "Folder partajat nou",
"fc_delete_owned": "Șterge de pe server", "fc_delete_owned": "Șterge de pe server",
"fc_remove_sharedfolder": "Șterge", "fc_remove_sharedfolder": "Șterge",
@ -547,5 +548,36 @@
"settings_resetNewTitle": "Curățare CryptDrive", "settings_resetNewTitle": "Curățare CryptDrive",
"settings_resetButton": "Șterge", "settings_resetButton": "Șterge",
"settings_resetTipsAction": "Resetează", "settings_resetTipsAction": "Resetează",
"settings_thumbnails": "Miniaturi" "settings_thumbnails": "Miniaturi",
"settings_padWidth": "Lățimea maximă a editorului",
"settings_codeFontSize": "Dimensiunea font-ului in editorul de cod",
"settings_codeUseTabs": "Indentarea prin etichete (în loc de spații)",
"settings_codeIndentation": "Indentarea editorului de cod (spații)",
"settings_driveDuplicateLabel": "Ascunde duplicatele",
"settings_driveDuplicateHint": "Când deplasezi documentele tale într-un dosar comun, o copie este păstrată în CryptDrive-ul tău pentru asigura păstrarea drepturilor tale de control asupra lui. Poți ascunde fișierele duplicate. Doar versiunea partajata va fi vizibilă, dacă nu este ștearsă, în acest ultim caz originalul va fi afișat în locația precedentă.",
"settings_driveDuplicateTitle": "Documentele tale duplicate",
"register_emailWarning3": "Dacă înțelegeți aceste aspecte și dorești totuși să utilizezi adresa ta de e-mail ca și nume de utilizator, apasă OK.",
"padNotPinnedVariable": "Acest document va expira dupa {4} zile de inactivitate, {0}autentifică-te{1} sau {2}creează-ți un cont{3} pentru a-l pastra.",
"settings_logoutEverywhereButton": "Deconectează-te",
"settings_deleted": "Contul tău de utilizator este șters. Apasă OK pentru a reveni la pagina principală.",
"settings_deleteConfirm": "Dacă apeși OK, contul tău va fi șters permanent. Ești sigur?",
"settings_deleteModal": "Furnizează aceste informații administratorului CryptPad-ului tău astfel încât acestea să fie șterse de pe server.",
"settings_deleteButton": "Șterge contul tău",
"settings_deleteHint": "Ștergerea contului este permanentă. Cryptdrive-ul tău și lista ta de documente vor fi șterse de pe server. Restul documentelor vor fi șterse în timp de 90 de zile dacă nimeni nu le stochează în CryptDrive-ul său.",
"settings_deleteTitle": "Ștergere cont",
"settings_userFeedbackTitle": "Feedback",
"settings_autostoreMaybe": "Manual (întreabă întotdeauna)",
"settings_autostoreNo": "Manual (nu mai întreba)",
"settings_autostoreYes": "Automat",
"settings_autostoreHint": "<b>Automat</b> Toate documentele accesate sunt stocate în CryptDrive-ul dumneavoastră.<br><b>Manual (întreabă întotdeauna)</b> Dacă nu ai stocat încă un document, vei fi întrebat dacă dorești să îl stochezi în Cryptdrive-ul tău.<br><b>Manual (nu mai întreba)</b> Documentele nu sunt stocate automat în Cryptpad-ul tău. Opțiunea de a le stoca ulterior va fi ascunsă.",
"settings_autostoreTitle": "Capacitatea de stocare a documentului în CryptDrive",
"register_emailWarning2": "Nu vei putea reseta parola utilizând adresa ta de e-mail.",
"register_emailWarning1": "Poți proceda astfel dacă doreşti, însă nici o notificare nu va fi transmisă server-ului nostru.",
"register_emailWarning0": "Se pare că ai adăugat adresa ta de e-mail în loc de numele tău de utilizator.",
"fc_expandAll": "Extinde",
"fc_openInCode": "Deschide in editorul de cod",
"fc_color": "Schimbă culoarea",
"fm_morePads": "Mai mult",
"uploadFolderButton": "Încarcă dosar",
"storageStatus": "Capacitate de stocare:<br /><b>{0}</b> utilizat din <b>{1}</b>"
} }

@ -17,5 +17,13 @@
display: flex; display: flex;
flex-flow: column; flex-flow: column;
.cp-support-language-list {
.cp-support-language {
margin-left: 5px;
background-color: rgba(0, 0, 0, 0.1);
padding: 0 5px;
}
}
} }

@ -11,6 +11,7 @@ define([
'/common/hyperscript.js', '/common/hyperscript.js',
'/support/ui.js', '/support/ui.js',
'/api/config', '/api/config',
'/customize/application_config.js',
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css', 'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
'css!/bower_components/components-font-awesome/css/font-awesome.min.css', 'css!/bower_components/components-font-awesome/css/font-awesome.min.css',
@ -27,7 +28,8 @@ define([
Messages, Messages,
h, h,
Support, Support,
ApiConfig ApiConfig,
AppConfig
) )
{ {
var APP = window.APP = {}; var APP = window.APP = {};
@ -41,6 +43,7 @@ define([
'cp-support-list', 'cp-support-list',
], ],
'new': [ 'new': [
'cp-support-language',
'cp-support-form', 'cp-support-form',
], ],
}; };
@ -132,6 +135,30 @@ define([
return $div; return $div;
}; };
create['language'] = function () {
if (!Array.isArray(AppConfig.supportLanguages)) { return $(h('div')); }
var languages = AppConfig.supportLanguages;
var list = h('span.cp-support-language-list', languages
.map(function (lang) {
return Messages._languages[lang];
})
.filter(Boolean)
.map(function (lang) {
return h('span.cp-support-language', lang);
})
);
Messages.support_languagesPreamble = "This server's administrators speak the following languages:"; // XXX
var $div = $(
h('div.cp-support-language', [
Messages.support_languagesPreamble,
list,
])
);
return $div;
};
// Create a new tickets // Create a new tickets
create['form'] = function () { create['form'] = function () {
var key = 'form'; var key = 'form';

Loading…
Cancel
Save