');
+ // There should always be a title here (defaultTitle if nothing else)
+ // so we don't ever need to supply a uid for an animal avatar
common.displayAvatar($div, null, name, function () {
$mAvatar.html($div.html());
$lAvatar.find('.cp-app-contacts-right-col').before($div.html());
});
});
+*/
// TODO room
// var onJoinRoom
@@ -878,7 +888,7 @@ define([
h('i.fa.fa-bell'),
Messages.contacts_unmute || 'unmute'
]);
- common.displayAvatar($(avatar), data.avatar, data.name);
+ common.displayAvatar($(avatar), data.avatar, data.name, Util.noop, data.uid);
$(button).click(function () {
unmuteUser(curve, button);
execCommand('UNMUTE_USER', curve, function (e, data) {
@@ -894,7 +904,7 @@ define([
});
return h('div.cp-contacts-muted-user', [
h('span', avatar),
- h('span', data.name),
+ h('span', UI.getDisplayName(data.name)),
button
]);
});
diff --git a/www/common/onlyoffice/inner.js b/www/common/onlyoffice/inner.js
index f1c10261d..caa3e39e4 100644
--- a/www/common/onlyoffice/inner.js
+++ b/www/common/onlyoffice/inner.js
@@ -1798,7 +1798,7 @@ define([
var text = getContent();
var suggestion = Title.suggestTitle(Title.defaultTitle);
var ext = ['.xlsx', '.ods', '.bin',
- //'.csv', // XXX
+ //'.csv', // XXX 4.11.0
'.pdf'];
var type = common.getMetadataMgr().getPrivateData().ooType;
var warning = '';
diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js
index 130926e6a..cd8887a15 100644
--- a/www/common/outer/async-store.js
+++ b/www/common/outer/async-store.js
@@ -26,9 +26,9 @@ define([
'/bower_components/chainpad-crypto/crypto.js',
'/bower_components/chainpad/chainpad.dist.js',
- '/bower_components/chainpad-netflux/chainpad-netflux.js',
- '/bower_components/chainpad-listmap/chainpad-listmap.js',
- '/bower_components/netflux-websocket/netflux-client.js',
+ 'chainpad-netflux',
+ 'chainpad-listmap',
+ 'netflux-client',
'/bower_components/nthen/index.js',
'/bower_components/saferphore/index.js',
], function (ApiConfig, Sortify, UserObject, ProxyManager, Migrate, Hash, Util, Constants, Feedback,
diff --git a/www/common/outer/cache-store.js b/www/common/outer/cache-store.js
index 93bc0d0c6..17fea6b16 100644
--- a/www/common/outer/cache-store.js
+++ b/www/common/outer/cache-store.js
@@ -97,7 +97,7 @@ define([
var checkCheckpoints = function (array) {
if (!Array.isArray(array)) { return;Â }
// Keep the last 100 messages
- if (array.length > 100) { // XXX 4.10.0
+ if (array.length > 100) { // FIXME this behaviour is only valid for chainpad-style documents
array.splice(0, array.length - 100);
}
// Remove every message before the first checkpoint
diff --git a/www/common/outer/calendar.js b/www/common/outer/calendar.js
index bea22db6b..a0b990e89 100644
--- a/www/common/outer/calendar.js
+++ b/www/common/outer/calendar.js
@@ -6,7 +6,7 @@ define([
'/common/outer/cache-store.js',
'/customize/messages.js',
'/bower_components/nthen/index.js',
- '/bower_components/chainpad-listmap/chainpad-listmap.js',
+ 'chainpad-listmap',
'/bower_components/chainpad-crypto/crypto.js',
'/bower_components/chainpad/chainpad.dist.js',
], function (Util, Hash, Constants, Realtime, Cache, Messages, nThen, Listmap, Crypto, ChainPad) {
diff --git a/www/common/outer/cursor.js b/www/common/outer/cursor.js
index 95b2b34c6..b1a5e7cd0 100644
--- a/www/common/outer/cursor.js
+++ b/www/common/outer/cursor.js
@@ -187,6 +187,7 @@ define([
data.color = Util.find(proxy, ['settings', 'general', 'cursor', 'color']);
data.name = proxy[Constants.displayNameKey] || ctx.store.noDriveName || Messages.anonymous;
data.avatar = Util.find(proxy, ['profile', 'avatar']);
+ data.uid = Util.find(proxy, ['uid']) || ctx.store.noDriveUid;
c.cursor = data;
sendMyCursor(ctx, client);
cb();
diff --git a/www/common/outer/mailbox.js b/www/common/outer/mailbox.js
index a7269c6e5..dbe95e84d 100644
--- a/www/common/outer/mailbox.js
+++ b/www/common/outer/mailbox.js
@@ -7,7 +7,7 @@ define([
'/common/common-messaging.js',
'/common/notify.js',
'/common/outer/mailbox-handlers.js',
- '/bower_components/chainpad-netflux/chainpad-netflux.js',
+ 'chainpad-netflux',
'/bower_components/chainpad-crypto/crypto.js',
], function (Config, BCast, Util, Hash, Realtime, Messaging, Notify, Handlers, CpNetflux, Crypto) {
var Mailbox = {};
diff --git a/www/common/outer/profile.js b/www/common/outer/profile.js
index 733b2b4c4..7cba963c7 100644
--- a/www/common/outer/profile.js
+++ b/www/common/outer/profile.js
@@ -3,7 +3,7 @@ define([
'/common/common-hash.js',
'/common/common-constants.js',
'/common/common-realtime.js',
- '/bower_components/chainpad-listmap/chainpad-listmap.js',
+ 'chainpad-listmap',
'/bower_components/chainpad-crypto/crypto.js',
'/bower_components/chainpad/chainpad.dist.js',
], function (Util, Hash, Constants, Realtime, Listmap, Crypto, ChainPad) {
diff --git a/www/common/outer/roster.js b/www/common/outer/roster.js
index e395891b7..6aa80e5d8 100644
--- a/www/common/outer/roster.js
+++ b/www/common/outer/roster.js
@@ -918,7 +918,7 @@ var factory = function (Util, Hash, CPNetflux, Sortify, nThen, Crypto, Feedback)
define([
'/common/common-util.js',
'/common/common-hash.js',
- '/bower_components/chainpad-netflux/chainpad-netflux.js',
+ 'chainpad-netflux',
'json.sortify',
'/bower_components/nthen/index.js',
'/bower_components/chainpad-crypto/crypto.js',
diff --git a/www/common/outer/sharedfolder.js b/www/common/outer/sharedfolder.js
index 6735330b4..4579492ba 100644
--- a/www/common/outer/sharedfolder.js
+++ b/www/common/outer/sharedfolder.js
@@ -6,7 +6,7 @@ define([
'/bower_components/nthen/index.js',
'/bower_components/chainpad-crypto/crypto.js',
- '/bower_components/chainpad-listmap/chainpad-listmap.js',
+ 'chainpad-listmap',
'/bower_components/chainpad/chainpad.dist.js',
], function (Hash, Util, UserObject, Cache,
nThen, Crypto, Listmap, ChainPad) {
diff --git a/www/common/outer/team.js b/www/common/outer/team.js
index 94f91c807..32ce35f3b 100644
--- a/www/common/outer/team.js
+++ b/www/common/outer/team.js
@@ -14,9 +14,9 @@ define([
'/common/cryptget.js',
'/common/outer/cache-store.js',
- '/bower_components/chainpad-listmap/chainpad-listmap.js',
+ 'chainpad-listmap',
'/bower_components/chainpad-crypto/crypto.js',
- '/bower_components/chainpad-netflux/chainpad-netflux.js',
+ 'chainpad-netflux',
'/bower_components/chainpad/chainpad.dist.js',
'/bower_components/nthen/index.js',
'/bower_components/saferphore/index.js',
diff --git a/www/common/requireconfig.js b/www/common/requireconfig.js
index 4e3baf857..7ed772575 100644
--- a/www/common/requireconfig.js
+++ b/www/common/requireconfig.js
@@ -16,6 +16,9 @@ define([
cm: '/bower_components/codemirror',
'tui-code-snippet': '/lib/calendar/tui-code-snippet.min',
'tui-date-picker': '/lib/calendar/date-picker',
+ 'netflux-client': '/bower_components/netflux-websocket/netflux-client',
+ 'chainpad-netflux': '/bower_components/chainpad-netflux/chainpad-netflux',
+ 'chainpad-listmap': '/bower_components/chainpad-listmap/chainpad-listmap',
},
map: {
'*': {
diff --git a/www/common/sframe-common-file.js b/www/common/sframe-common-file.js
index a6b097876..e4f6c9260 100644
--- a/www/common/sframe-common-file.js
+++ b/www/common/sframe-common-file.js
@@ -11,10 +11,12 @@ define([
'/common/hyperscript.js',
'/customize/messages.js',
'/customize/pages.js',
+ '/bower_components/nthen/index.js',
+ '/common/media-tag.js',
'/bower_components/file-saver/FileSaver.min.js',
'/bower_components/tweetnacl/nacl-fast.min.js',
-], function ($, ApiConfig, FileCrypto, MakeBackup, Thumb, UI, UIElements, Util, Hash, h, Messages, Pages) {
+], function ($, ApiConfig, FileCrypto, MakeBackup, Thumb, UI, UIElements, Util, Hash, h, Messages, Pages, nThen, MT) {
var Nacl = window.nacl;
var module = {};
@@ -312,7 +314,8 @@ define([
});
return manualStore;
};
- var fileUploadModal = function (defaultFileName, cb) {
+
+ var fileUploadModal = function (defaultFileName, cb, preview) {
var parsedName = /^(\.?.+?)(\.[^.]+)?$/.exec(defaultFileName) || [];
var ext = parsedName[2] || "";
@@ -321,9 +324,14 @@ define([
// Ask for name, password and owner
var content = h('div', [
h('h4', Messages.upload_modal_title),
+ (preview? h('div#cp-upload-preview-container', preview): undefined),
UIElements.setHTML(h('label', {for: 'cp-upload-name'}),
Messages._getKey('upload_modal_filename', [ext])),
h('input#cp-upload-name', {type: 'text', placeholder: defaultFileName, value: defaultFileName}),
+
+ h('label', {for: 'cp-upload-alt'}, Messages.upload_addOptionalAlt),
+ h('input#cp-upload-alt', {type: 'text', placeholder: Messages.upload_modal_alt, autocomplete: 'off'}),
+
h('label', {for: 'cp-upload-password'}, Messages.addOptionalPassword),
UI.passwordInput({id: 'cp-upload-password'}),
h('span', {
@@ -335,7 +343,8 @@ define([
manualStore
]);
- $(content).find('#cp-upload-owned').on('change', function () {
+ var $content = $(content);
+ $content.find('#cp-upload-owned').on('change', function () {
var val = Util.isChecked($(content).find('#cp-upload-owned'));
if (val) {
$(content).find('#cp-upload-store').prop('checked', true).prop('disabled', true);
@@ -348,8 +357,9 @@ define([
if (!yes) { return void cb(); }
// Get the values
- var newName = $(content).find('#cp-upload-name').val();
- var password = $(content).find('#cp-upload-password').val() || undefined;
+ var newName = $content.find('#cp-upload-name').val();
+ var password = $content.find('#cp-upload-password').val() || undefined;
+ var alt = $content.find('#cp-upload-alt').val() || undefined;
var owned = Util.isChecked($(content).find('#cp-upload-owned'));
var forceSave = owned || Util.isChecked($(content).find('#cp-upload-store'));
@@ -366,7 +376,8 @@ define([
name: newName,
password: password,
owned: owned,
- forceSave: forceSave
+ forceSave: forceSave,
+ alt: alt,
});
});
};
@@ -437,6 +448,8 @@ define([
}
var thumb;
+ var preview;
+ var alt;
var file_arraybuffer;
var name = file.name;
var password;
@@ -447,6 +460,7 @@ define([
var metadata = {
name: name,
type: type,
+ alt: alt,
};
if (thumb) { metadata.thumbnail = thumb; }
queue.push({
@@ -486,8 +500,9 @@ define([
password = obj.password;
owned = obj.owned;
forceSave = obj.forceSave;
+ alt = obj.alt;
finish();
- });
+ }, preview);
}
};
@@ -495,11 +510,20 @@ define([
if (e) { console.error(e); }
file_arraybuffer = buffer;
if (!Thumb.isSupportedType(file)) { return getName(); }
- // make a resized thumbnail from the image..
- Thumb.fromBlob(file, function (e, thumb64) {
- if (e) { console.error(e); }
- if (!thumb64) { return getName(); }
- thumb = thumb64;
+ nThen(function (w) {
+ // make a resized thumbnail from the image..
+ Thumb.fromBlob(file, w(function (e, thumb64) {
+ if (e) { console.error(e); }
+ if (!thumb64) { return; }
+ thumb = thumb64;
+ }));
+ MT.preview(buffer, {
+ type: file.type,
+ }, void 0, w(function (err, el) {
+ if (err) { return void console.error(err); }
+ preview = el;
+ }));
+ }).nThen(function () {
getName();
});
});
diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js
index 3faefe0bb..21344cd3f 100644
--- a/www/common/sframe-common-outer.js
+++ b/www/common/sframe-common-outer.js
@@ -623,6 +623,7 @@ define([
prefersDriveRedirect: Utils.LocalStore.getDriveRedirectPreference(),
isPresent: parsed.hashData && parsed.hashData.present,
isEmbed: parsed.hashData && parsed.hashData.embed,
+ canEdit: hashes && hashes.editHash,
oldVersionHash: parsed.hashData && parsed.hashData.version < 2, // password
isHistoryVersion: parsed.hashData && parsed.hashData.versionHash,
notifications: notifs,
@@ -1792,6 +1793,22 @@ define([
});
});
+ sframeChan.on('Q_COPY_VIEW_URL', function (data, cb) {
+ require(['/common/clipboard.js'], function (Clipboard) {
+ var url = window.location.origin +
+ Utils.Hash.hashToHref(hashes.viewHash, 'form');
+ var success = Clipboard.copy(url);
+ cb(success);
+ });
+ });
+ sframeChan.on('EV_OPEN_VIEW_URL', function () {
+ var url = Utils.Hash.hashToHref(hashes.viewHash, 'form');
+ var a = window.open(url);
+ if (!a) {
+ sframeChan.event('EV_POPUP_BLOCKED');
+ }
+ });
+
if (cfg.messaging) {
sframeChan.on('Q_CHAT_OPENPADCHAT', function (data, cb) {
Cryptpad.universal.execCommand({
diff --git a/www/common/sframe-common.js b/www/common/sframe-common.js
index 6a7e3effd..b7efd9f4f 100644
--- a/www/common/sframe-common.js
+++ b/www/common/sframe-common.js
@@ -235,9 +235,6 @@ define([
};
};
- funcs.getAuthorId = function () {
- };
-
var authorUid = function(existing) {
if (!Array.isArray(existing)) { existing = []; }
var n;
@@ -249,11 +246,25 @@ define([
if (existing.indexOf(n) !== -1) { n = 0; }
return n;
};
- funcs.getAuthorId = function(authors, curve) {
+ funcs.getAuthorId = function(authors, curve, tokenId) {
var existing = Object.keys(authors || {}).map(Number);
- if (!funcs.isLoggedIn()) { return authorUid(existing); }
-
var uid;
+ var loggedIn = funcs.isLoggedIn();
+ if (!loggedIn && !tokenId) { return authorUid(existing); }
+ if (!loggedIn) {
+ existing.some(function (id) {
+ var author = authors[id];
+ if (!author || author.uid !== tokenId) { return; }
+ uid = Number(id);
+ return true;
+ });
+ return uid || authorUid(existing);
+ }
+ // TODO this should check for a matching curvePublic / uid if:
+ // 1. you are logged in OR
+ // 2. you have a token
+ // so that users that register recognize comments from before
+ // they registered as their own (same uid)
existing.some(function(id) {
var author = authors[id] || {};
if (author.curvePublic !== curve) { return; }
@@ -921,9 +932,10 @@ define([
});
ctx.sframeChan.on('EV_WORKER_TIMEOUT', function () {
- UI.errorLoadingScreen(Messages.timeoutError, false, function () { // XXX mobile users can't necessarily hit 'ESC' as this message suggests. provice a click option
- funcs.gotoURL('');
- });
+ var message = UI.setHTML(h('span'), Messages.timeoutError);
+ var cb = Util.once(function () { funcs.gotoURL(''); });
+ $(message).find('em').on('touchend', cb);
+ UI.errorLoadingScreen(message, false, cb);
});
ctx.sframeChan.on('EV_CHROME_68', function () {
diff --git a/www/common/toolbar.js b/www/common/toolbar.js
index ccc1c5e78..8931c57f5 100644
--- a/www/common/toolbar.js
+++ b/www/common/toolbar.js
@@ -65,7 +65,9 @@ MessengerUI, Messages, Pages) {
if (!config.$container) { return; }
var $container = config.$container;
- var isEmbed = Bar.isEmbed = config.metadataMgr.getPrivateData().isEmbed;
+ var priv = config.metadataMgr.getPrivateData();
+ var isEmbed = Bar.isEmbed = priv.isEmbed ||
+ (priv.app === 'form' && priv.readOnly && !priv.form_auditorHash);
if (isEmbed) {
$container.hide();
}
@@ -249,6 +251,7 @@ MessengerUI, Messages, Pages) {
var friendRequests = Common.getFriendRequests(); // Friend requests received
editUsersNames.forEach(function (data) {
var name = data.name || Messages.anonymous;
+ var safeName = Util.fixHTML(name);
var $span = $('
', {'class': 'cp-avatar'});
if (data.color && showColors) {
$span.css('border-color', data.color);
@@ -323,7 +326,7 @@ MessengerUI, Messages, Pages) {
$('', {
'class': 'fa fa-bell cp-toolbar-userlist-button',
'data-cptippy-html': true,
- 'title': Messages._getKey('friendRequest_received', [Util.fixHTML(name)]),
+ 'title': Messages._getKey('friendRequest_received', [safeName]),
}).appendTo($nameSpan).click(function (e) {
e.stopPropagation();
UIElements.displayFriendRequestModal(Common, friendRequests[data.curvePublic]);
@@ -334,7 +337,7 @@ MessengerUI, Messages, Pages) {
'class': 'fa fa-user-plus cp-toolbar-userlist-button',
'data-cptippy-html': true,
'title': Messages._getKey('userlist_addAsFriendTitle', [
- Util.fixHTML(name)
+ safeName,
])
}).appendTo($nameSpan).click(function (e) {
e.stopPropagation();
@@ -356,14 +359,16 @@ MessengerUI, Messages, Pages) {
});
}
if (data.profile) {
+ // Messages.contacts_info3 "Double-click their icon to view their profile",
$span.addClass('cp-userlist-clickable');
+ $span.attr('title', Messages._getKey('userlist_visitProfile', [name]));
$span.click(function () {
Common.openURL(origin+'/profile/#' + data.profile);
});
}
Common.displayAvatar($span, data.avatar, name, function () {
$span.append($rightCol);
- });
+ }, data.uid);
$span.data('uid', data.uid);
$editUsersList.append($span);
});
@@ -455,13 +460,9 @@ MessengerUI, Messages, Pages) {
return $container;
};
- //Messages.collapse = Messages.admin_support_collapse;
- Messages.ui_collapse = "Collapse toolbar"; // XXX
- Messages.ui_expand = "Expand toolbar"; // XXX
-
createCollapse = function (toolbar) {
- var up = h('i.fa.fa-chevron-up', {title: Messages.ui_collapse});
- var down = h('i.fa.fa-chevron-down', {title: Messages.ui_expand});
+ var up = h('i.fa.fa-chevron-up', {title: Messages.toolbar_collapse});
+ var down = h('i.fa.fa-chevron-down', {title: Messages.toolbar_expand});
var $button = $(h('button.cp-toolbar-collapse',[
up,
@@ -1043,24 +1044,10 @@ MessengerUI, Messages, Pages) {
userMenuCfg.displayName = 1;
userMenuCfg.displayChangeName = 1;
}
- /*if (config.displayed.indexOf('userlist') !== -1) {
- userMenuCfg.displayChangeName = 0;
- }*/
Common.createUserAdminMenu(userMenuCfg);
- $userAdmin.find('> button').attr('title', Messages.userAccountButton);
-
- var $userButton = toolbar.$userNameButton = $userAdmin.find('a.' + USERBUTTON_CLS);
- $userButton.click(function (e) {
- e.preventDefault();
- e.stopPropagation();
- var myData = metadataMgr.getUserData();
- var lastName = myData.name;
- UI.prompt(Messages.changeNamePrompt, lastName || '', function (newName) {
- if (newName === null && typeof(lastName) === "string") { return; }
- if (newName === null) { newName = ''; }
- else { Feedback.send('NAME_CHANGED'); }
- setDisplayName(newName);
- });
+ $userAdmin.find('> button').attr({
+ title: Messages.userAccountButton,
+ alt: Messages.userAccountButton,
});
return $userAdmin;
@@ -1236,18 +1223,31 @@ MessengerUI, Messages, Pages) {
}
};
+ var getFancyGuestName = function (name, uid) {
+ name = UI.getDisplayName(name);
+ if (name === Messages.anonymous && uid) {
+ var animal = MT.getPseudorandomAnimal(uid);
+ if (animal) {
+ name = animal + ' ' + name;
+ }
+ }
+ return name;
+ };
+
// Notifications
var initNotifications = function (toolbar, config) {
// Display notifications when users are joining/leaving the session
var oldUserData;
if (!config.metadataMgr) { return; }
var metadataMgr = config.metadataMgr;
- var notify = function(type, name, oldname) {
+ var notify = function(type, name, oldname, uid) {
if (toolbar.isAlone) { return; }
// type : 1 (+1 user), 0 (rename existing user), -1 (-1 user)
if (typeof name === "undefined") { return; }
- name = name || Messages.anonymous;
if (Config.disableUserlistNotifications) { return; }
+ name = getFancyGuestName(name, uid);
+ oldname = getFancyGuestName(oldname, uid);
+
switch(type) {
case 1:
UI.log(Messages._getKey("notifyJoined", [name]));
@@ -1296,7 +1296,7 @@ MessengerUI, Messages, Pages) {
delete oldUserData[u];
if (temp && newdata[userNetfluxId] && temp.uid === newdata[userNetfluxId].uid) { return; }
if (userPresent(u, temp, newdata || oldUserData) < 1) {
- notify(-1, temp.name);
+ notify(-1, temp.name, undefined, temp.uid);
}
}
}
@@ -1316,10 +1316,10 @@ MessengerUI, Messages, Pages) {
if (typeof oldUserData[k] === "undefined") {
// if the same uid is already present in the userdata, don't notify
if (!userPresent(k, newdata[k], oldUserData)) {
- notify(1, newdata[k].name);
+ notify(1, newdata[k].name, undefined, newdata[k].uid);
}
} else if (oldUserData[k].name !== newdata[k].name) {
- notify(0, newdata[k].name, oldUserData[k].name);
+ notify(0, newdata[k].name, oldUserData[k].name, newdata[k].uid);
}
}
}
@@ -1383,7 +1383,7 @@ MessengerUI, Messages, Pages) {
toolbar.$file.show();
addElement([
'chat',
- 'collapse', // XXX
+ 'collapse',
'userlist', 'title', 'useradmin', 'spinner',
'newpad', 'share', 'access', 'limit', 'unpinnedWarning',
'notifications'
diff --git a/www/common/translations/messages.de.json b/www/common/translations/messages.de.json
index 0b5db20e7..e2e1a6805 100644
--- a/www/common/translations/messages.de.json
+++ b/www/common/translations/messages.de.json
@@ -26,7 +26,7 @@
"typeError": "Dieses Dokument ist nicht mit der ausgewählten Anwendung kompatibel",
"onLogout": "Du bist ausgeloggt. {0}Klicke hier{1}, um dich wieder einzuloggen, oder drÃŧcke Escape , um dein Pad schreibgeschÃŧtzt zu benutzen.",
"padNotPinned": "Dieses Pad wird nach 3 Monaten ohne Aktivität auslaufen, {0}logge dich ein{1} oder {2}registriere dich{3}, um das Auslaufen zu verhindern.",
- "anonymousStoreDisabled": "Der Webmaster dieses CryptPad-Servers hat die anonyme Verwendung des Speichers deaktiviert. Du musst dich einloggen, um CryptDrive zu verwenden.",
+ "anonymousStoreDisabled": "Der Administrator dieser CryptPad-Instanz hat die Verwendung des Speichers fÃŧr Gäste deaktiviert. Logge dich ein, um dein persÃļnliches CryptDrive zu verwenden.",
"expiredError": "Dieses Pad ist abgelaufen und nicht mehr verfÃŧgbar.",
"deletedError": "Dieses Dokument wurde gelÃļscht und ist nicht mehr verfÃŧgbar.",
"inactiveError": "Dieses Pad ist wegen Inaktivität gelÃļscht worden. DrÃŧcke Esc, um ein neues Pad zu erstellen.",
@@ -50,7 +50,7 @@
"forgotten": "In den Papierkorb verschoben",
"errorState": "Kritischer Fehler: {0}",
"readonly": "schreibgeschÃŧtzt",
- "anonymous": "Anonym",
+ "anonymous": "Gast",
"users": "Nutzer",
"viewer": "Betrachter",
"viewers": "Betrachter",
@@ -88,7 +88,7 @@
"shareSuccess": "Die URL wurde in die Zwischenablage kopiert",
"userListButton": "Benutzerliste",
"chatButton": "Chat",
- "userAccountButton": "Dein Account",
+ "userAccountButton": "BenutzermenÃŧ",
"newButton": "Neu",
"newButtonTitle": "Neues Pad erstellen",
"uploadButton": "Hochladen",
@@ -326,7 +326,7 @@
"login_invalUser": "Der Benutzername kann nicht leer sein",
"login_invalPass": "Der Passwort kann nicht leer sein",
"login_unhandledError": "Ein unerwarteter Fehler ist aufgetreten :(",
- "register_importRecent": "Dokumente aus deiner nicht-registrierten Sitzung importieren",
+ "register_importRecent": "Dokumente aus deiner Gast-Sitzung importieren",
"register_acceptTerms": "Ich bin mit den Nutzungsbedingungen einverstanden",
"register_passwordsDontMatch": "PasswÃļrter stimmen nicht Ãŧberein!",
"register_passwordTooShort": "PasswÃļrter mÃŧssen mindestens {0} Zeichen haben.",
@@ -498,7 +498,7 @@
"whatis_drive": "Organisieren mit CryptDrive",
"features": "Funktionen",
"features_title": "Funktionen",
- "features_anon": "Nicht-registriert",
+ "features_anon": "Gast",
"features_registered": "Registriert",
"features_premium": "Premium",
"features_f_apps": "Zugang zu allen Anwendungen",
@@ -510,7 +510,7 @@
"features_f_cryptdrive0_note": "Du kannst besuchte Dokumente in deinem Browser speichern, damit du sie später Ãļffnen kannst",
"features_f_storage0": "Speicherung fÃŧr eine begrenzte Zeit",
"features_f_storage0_note": "Dokumente werden nach {0} Tagen ohne Aktivität gelÃļscht",
- "features_f_anon": "Alle Funktionen fÃŧr anonyme Benutzer",
+ "features_f_anon": "Alle Funktionen fÃŧr Gäste",
"features_f_anon_note": "Mit zusätzlichen Funktionen",
"features_f_cryptdrive1": "Alle Funktionen des CryptDrives",
"features_f_cryptdrive1_note": "Ordner, geteilte Ordner, Vorlagen, Tags",
@@ -557,7 +557,7 @@
"creation_expireDays": "Tag(e)",
"creation_expireMonths": "Monat(e)",
"creation_password": "Passwort\n",
- "creation_noTemplate": "Keine Vorlage",
+ "creation_noTemplate": "Leeres Dokument",
"creation_newTemplate": "Neue Vorlage",
"creation_create": "Erstellen",
"creation_owners": "EigentÃŧmer",
@@ -584,8 +584,8 @@
"share_linkView": "Ansehen",
"share_linkEmbed": "Einbettungsmodus (Werkzeugleiste und Benutzerliste verbergen)",
"share_linkPresent": "Anzeigemodus",
- "share_linkOpen": "Vorschau",
- "share_linkCopy": "Kopieren",
+ "share_linkOpen": "Link Ãļffnen",
+ "share_linkCopy": "Link kopieren",
"share_embedCategory": "Einbetten",
"share_mediatagCopy": "Media-Tag in die Zwischenablage kopieren",
"sharedFolders_forget": "Dieses Pad ist nur in einem geteilten Ordner gespeichert. Du kannst es nicht in den Papierkorb verschieben. Aber du kannst es in deinem CryptDrive lÃļschen.",
@@ -882,7 +882,7 @@
"oo_exportInProgress": "Export wird durchgefÃŧhrt",
"oo_sheetMigration_loading": "Deine Tabelle wird auf die neueste Version aktualisiert. Bitte warte etwa eine Minute.",
"oo_sheetMigration_complete": "Eine aktualisierte Version ist verfÃŧgbar. Klicke auf OK, um neu zu laden.",
- "oo_sheetMigration_anonymousEditor": "Die Bearbeitung dieser Tabelle ist fÃŧr nicht-registrierte Benutzer deaktiviert, bis sie von einem registrierten Benutzer auf die neueste Version aktualisiert wird.",
+ "oo_sheetMigration_anonymousEditor": "Die Bearbeitung dieser Tabelle ist fÃŧr Gäste deaktiviert, bis sie von einem registrierten Benutzer auf die neueste Version aktualisiert wird.",
"imprint": "Impressum",
"isContact": "{0} ist einer deiner Kontakte",
"isNotContact": "{0} ist nicht einer deiner Kontakte",
@@ -1120,7 +1120,7 @@
"whatis_apps": "Eine vollständige Anwendungs-Suite",
"whatis_drive_info": "Speichere und verwalte Dokumente mit CryptDrive. Erstelle Ordner, gemeinsame Ordner und Tags, um Dokumente zu organisieren. Lade Dateien hoch und teile sie (PDFs, Fotos, Video, Audio, etc.). Team-Drives werden zwischen Benutzern geteilt und ermÃļglichen eine gemeinsame Organisation und detaillierte Zugriffskontrolle.
",
"whatis_apps_info": "CryptPad bietet eine vollwertige Office-Suite mit allen notwendigen Werkzeugen fÃŧr eine produktive Zusammenarbeit. Die Anwendungen umfassen: Rich Text, Tabellen, Code/Markdown, Kanban, Präsentationen, Whiteboard und Umfragen.
Die Anwendungen werden ergänzt durch eine Reihe von Funktionen zur Zusammenarbeit wie Chat, Kontakte, Farbe nach Autor (Code/Markdown) und Kommentare mit Erwähnungen (Rich Text).
",
- "register_notes": "Dein Passwort ist der geheime SchlÃŧssel, der alle deine Dokumente verschlÃŧsselt. Wenn du ihn verlierst, gibt es keine MÃļglichkeit, deine Daten wiederherzustellen. Wenn du einen gemeinsam genutzten Computer verwendest, denke daran, dich abzumelden , wenn du fertig bist. Durch bloÃes SchlieÃen des Browserfensters bleibt das Konto ungeschÃŧtzt. Um die erstellten und/oder gespeicherten Dokumente zu behalten, ohne eingeloggt zu sein, setze einen Haken bei \"Dokumente aus deiner nicht-registrierten Sitzung importieren\". ",
+ "register_notes": "Dein Passwort ist der geheime SchlÃŧssel, der alle deine Dokumente verschlÃŧsselt. Wenn du ihn verlierst, gibt es keine MÃļglichkeit, deine Daten wiederherzustellen. Wenn du einen gemeinsam genutzten Computer verwendest, denke daran, dich abzumelden , wenn du fertig bist. Durch bloÃes SchlieÃen des Browserfensters bleibt das Konto ungeschÃŧtzt. Um die Dokumente zu behalten, die du erstellt und/oder gespeichert hast, ohne eingeloggt zu sein, setze einen Haken bei \"Dokumente aus deiner Gast-Sitzung importieren\". ",
"settings_cacheTitle": "Cache",
"settings_cacheButton": "Cache leeren",
"settings_cacheCheckbox": "Cache auf diesem Gerät aktivieren",
@@ -1243,12 +1243,12 @@
"button_newform": "Neues Formular",
"form_page": "Seite {0}/{1}",
"form_anonymous_on": "Erlaubt",
- "form_anonymous": "Anonyme Antworten",
+ "form_anonymous": "Gastzugriff (nicht eingeloggt)",
"form_removeEnd": "Enddatum entfernen",
"form_setEnd": "Enddatum festlegen",
"form_isPrivate": "Antworten sind privat",
"form_isPublic": "Antworten sind Ãļffentlich",
- "form_makePublicWarning": "Bist du sicher, dass du die Antworten verÃļffentlichen mÃļchtest? Dies kann nicht rÃŧckgängig gemacht werden.",
+ "form_makePublicWarning": "Bist du sicher, dass du die Antworten verÃļffentlichen mÃļchtest? Vergangene und zukÃŧnftige Antworten werden fÃŧr Teilnehmer sichtbar sein. Dies kann nicht rÃŧckgängig gemacht werden.",
"form_makePublic": "Antworten verÃļffentlichen",
"form_invalidQuestion": "Frage {0}",
"form_input_ph_url": "https://example.com",
@@ -1256,7 +1256,7 @@
"form_backButton": "ZurÃŧck",
"form_showSummary": "Zusammenfassung anzeigen",
"form_results_empty": "Es gibt keine Antworten",
- "form_results": "Antworten",
+ "form_results": "Antworten ({0})",
"form_delete": "LÃļschen",
"form_reset": "ZurÃŧcksetzen",
"form_maxOptions": "Maximal {0} Antwort(en)",
@@ -1323,7 +1323,7 @@
"form_answerName": "Antwort von {0} am {1}",
"form_answerAnonymous": "Anonyme Antwort am {0}",
"form_anonymousBox": "Anonym antworten",
- "form_anonymous_blocked": "Anonyme Antworten sind in diesem Formular nicht erlaubt. Du musst dich einloggen oder registrieren , um Antworten abzusenden.",
+ "form_anonymous_blocked": "Antworten von Gästen sind in diesem Formular nicht erlaubt. Du musst dich einloggen oder registrieren , um Antworten abzusenden.",
"form_anonymous_off": "Blockiert",
"form_invalidWarning": "Es gibt fehlerhafte Antworten:",
"form_notAnswered": "{0} leere Antworten",
@@ -1382,5 +1382,47 @@
"fm_link_new": "Neuer Link",
"form_totalResponses": "Antworten insgesamt: {0}",
"ui_expand": "Ausklappen",
- "ui_collapse": "Einklappen"
+ "ui_collapse": "Einklappen",
+ "support_premiumPriority": "Premium-Benutzer helfen bei der Verbesserung der Benutzerfreundlichkeit von CryptPad und profitieren von priorisierten Antworten auf ihre Support-Tickets.",
+ "support_premiumLink": "Abonnementoptionen ansehen",
+ "form_viewAnswer": "Meine Antworten anzeigen",
+ "form_editAnswer": "Meine Antworten bearbeiten",
+ "form_preview_button": "Vorschau",
+ "form_colors": "Farbschema",
+ "userlist_visitProfile": "Profil aufrufen",
+ "toolbar_preview": "Vorschau",
+ "form_geturl": "Link kopieren",
+ "upload_modal_alt": "Alt-Text",
+ "upload_addOptionalAlt": "Beschreibungstext hinzufÃŧgen (optional)",
+ "toolbar_expand": "Werkzeugleiste ausklappen",
+ "toolbar_collapse": "Werkzeugleiste einklappen",
+ "profile_defaultAlt": "Standard-Profilbild",
+ "form_required_on": "Erforderlich",
+ "form_authAnswer": "Dieses Formular kann nicht anonym beantwortet werden",
+ "form_type_section": "Bedingter Abschnitt",
+ "form_editable": "Bearbeitung nach Absenden",
+ "form_addMsg": "Endnachricht hinzufÃŧgen",
+ "form_updateMsg": "Endnachricht bearbeiten",
+ "form_responseMsg": "Diese Nachricht wird angezeigt, nachdem die Teilnehmer das Formular abgesendet haben.",
+ "form_required_off": "Optional",
+ "form_conditional_hint": "Um diesen Abschnitt von Bedingungen abhängig zu machen, fÃŧge bitte darÃŧber eine Einfachauswahl- oder Mehrfachauswahl-Frage hinzu",
+ "form_conditional_addAnd": "UND-Bedingung hinzufÃŧgen",
+ "form_conditional_add": "ODER-Bedingung hinzufÃŧgen",
+ "form_conditional": "Zeige diesen Abschnitt nur, wenn:",
+ "form_condition_hasnot": "hat nicht",
+ "form_condition_has": "hat",
+ "form_condition_isnot": "ist nicht",
+ "form_condition_is": "ist",
+ "form_condition_q": "Wähle eine Frage",
+ "form_condition_v": "Wähle einen Wert",
+ "form_required_answer": "Antwort: ",
+ "form_changeTypeConfirm": "Wähle den neuen Fragetyp aus.",
+ "form_corruptAnswers": "FÃŧr dieses Formular gibt es bereits Antworten. Eine Ãnderung dieses Fragetyps kann dazu fÃŧhren, dass frÃŧhere Antwortdaten ungÃŧltig werden.",
+ "form_makeAnon": "Antworten anonymisieren",
+ "form_preview": "Vorschau",
+ "form_requiredWarning": "Die folgenden Fragen mÃŧssen beantwortet werden:",
+ "form_anonAnswer": "Antworten auf dieses Formular sind anonymisiert",
+ "form_viewAllAnswers": "Alle Antworten anzeigen ({0})",
+ "form_alreadyAnswered": "Du hast dieses Formular beantwortet am {0}",
+ "form_template_poll": "Schnelle Terminumfrage"
}
diff --git a/www/common/translations/messages.es.json b/www/common/translations/messages.es.json
index 2c6c4e98a..f185ea637 100644
--- a/www/common/translations/messages.es.json
+++ b/www/common/translations/messages.es.json
@@ -607,5 +607,44 @@
"share_linkEdit": "Editar",
"share_linkAccess": "Permisos de acceso",
"properties_passwordWarning": "La contraseÃąa ha sido cambiada con Êxito pero fue incapaz de actualizar tu CryptDrive con los nuevos datos. Es posible que tenga que eliminar la versiÃŗn antigua del pad manualmente. Pulse OK para recargar y actualizar sus derechos de acceso.",
- "properties_passwordSuccess": "La contraseÃąa ha sido cambiada con Êxito. Pulsa OK para recargar y actualizar tus derechos de acceso."
+ "properties_passwordSuccess": "La contraseÃąa ha sido cambiada con Êxito. Pulsa OK para recargar y actualizar tus derechos de acceso.",
+ "admin_updateLimitTitle": "Actualizar cuotas de usuarios",
+ "admin_registeredHint": "NÃēmero de usuarios registrados en tu instancia",
+ "admin_registeredTitle": "Usuarios registrados",
+ "admin_activePadsHint": "NÃēmero de documentos Ãēnicos que se estÃĄn viendo o editando ahora",
+ "admin_activePadsTitle": "Blocs activos",
+ "admin_activeSessionsHint": "NÃēmero de conexiones websocket activas (y direcciones IP Ãēnicas conectadas)",
+ "admin_activeSessionsTitle": "Conexiones activas",
+ "adminPage": "AdministraciÃŗn",
+ "admin_cat_stats": "EstadÃsticas",
+ "admin_cat_general": "General",
+ "admin_authError": "Solo los administradores pueden acceder a esta pÃĄgina.",
+ "markdown_toc": "Contenido",
+ "survey": "Encuesta de CryptPad",
+ "crowdfunding_popup_no": "Ahora no",
+ "crowdfunding_popup_text": "ÂĄNecesitamos tu ayuda! Para garantizar que CryptPad se desarrolle activamente, considera apoyar el proyecto a travÊs de la pÃĄgina OpenCollective, donde puedes ver nuestra Hoja de ruta y Objetivos de financiaciÃŗn .",
+ "autostore_notAvailable": "Tienes que guardar el bloc en tu CryptDrive antes de usar esta funciÃŗn.",
+ "autostore_forceSave": "Guarda el fichero en tu CryptDrive",
+ "autostore_saved": "El bloc se guardÃŗ correctamente en tu CryptDrive!",
+ "autostore_error": "Error extraÃąo: No pudimos guardar este bloc, intÊntalo otra vez.",
+ "autostore_hide": "No guardar",
+ "autostore_store": "Guardar",
+ "autostore_settings": "Puedes habilitar el almacenamiento automÃĄtico de blocs en su PÃĄgina de configuraciÃŗn!",
+ "autostore_notstored": "Este {0} no estÃĄ en su CryptDrive. ÂŋQuieres guardarlo ahora?",
+ "autostore_sf": "carpeta",
+ "chrome68": "Parece que estÃĄs usando el navegador Chrome o Chromium versiÃŗn 68. Contiene un error que hace que la pÃĄgina se vuelva completamente blanca despuÊs de unos segundos o que la pÃĄgina no responda a los clics. Para solucionar este problema, puede cambiar a otra pestaÃąa y volver, o tratar de desplazarse en la pÃĄgina. Este error debe corregirse en la prÃŗxima versiÃŗn de su navegador.",
+ "convertFolderToSF_confirm": "Esta carpeta debe convertirse a carpeta compartida para que otros la puedan ver. ÂŋContinuar?",
+ "sharedFolders_create_owned": "Carpeta con propietario",
+ "sharedFolders_create_name": "Nombre de carpeta",
+ "share_embedCategory": "Embeber",
+ "share_linkPresent": "Presentar",
+ "share_linkEmbed": "Modo de inserciÃŗn (oculta barra de herramientas y lista de usuarios)",
+ "settings_padOpenLinkLabel": "Habilita la apertura directa del enlace",
+ "settings_padOpenLinkHint": "Con esta opciÃŗn puedes abrir enlaces embebidos haciendo click sin el popup de previsualizaciÃŗn",
+ "properties_changePasswordButton": "Enviar",
+ "convertFolderToSF_SFChildren": "Esta carpeta no puede ser convertida a una carpeta compartida porque ya contiene carpetas compartidas. Mueva esas carpetas compartidas a otro lugar para continuar.",
+ "convertFolderToSF_SFParent": "Esta carpeta no puede ser convertida a una carpeta compartida en su actual localizaciÃŗn. Mueva la carpeta fuera de la carperta compartida para continuar.",
+ "sharedFolders_share": "Comparte este enlace con otros usuarios registrados para darles accesso a la carpeta compartida. Una vez que ellos/as abran este enlace, la carpeta compartida serÃĄ aÃąadida a sus CryptDrive.",
+ "sharedFolders_create": "Crear una carpeta compartida",
+ "sharedFolders_duplicate": "Algunos de los documentos que intentaste mover ya estaban compartidos en la carpeta de destino"
}
diff --git a/www/common/translations/messages.fr.json b/www/common/translations/messages.fr.json
index e814ad87b..c7831f922 100644
--- a/www/common/translations/messages.fr.json
+++ b/www/common/translations/messages.fr.json
@@ -26,7 +26,7 @@
"typeError": "Ce pad n'est pas compatible avec l'application sÊlectionnÊe",
"onLogout": "Vous ÃĒtes dÊconnectÊ de votre compte utilisateur, {0}cliquez ici{1} pour vous authentifier ou appuyez sur Ãchap pour accÊder au pad en mode lecture seule.",
"padNotPinned": "Ce pad va expirer après 3 mois d'inactivitÊ, {0}connectez-vous{1} ou {2}enregistrez-vous{3} pour le prÊserver.",
- "anonymousStoreDisabled": "L'administrateur de cette instance de CryptPad a dÊsactivÊ le drive pour les utilisateurs non enregistrÊs. Vous devez vous connecter pour pouvoir utiliser CryptDrive.",
+ "anonymousStoreDisabled": "L'administrateur de cette instance de CryptPad a dÊsactivÊ le drive pour les visiteurs. Enregistrez vous ou connectez vous à un compte pour pouvoir utiliser CryptDrive.",
"expiredError": "Ce pad a atteint sa date d'expiration est n'est donc plus disponible.",
"deletedError": "Ce document a ÊtÊ supprimÊ et n'est plus disponible.",
"inactiveError": "Ce pad a ÊtÊ supprimÊ en raison de son inactivitÊ. Appuyez sur Ãchap pour crÊer un nouveau pad.",
@@ -51,7 +51,7 @@
"forgotten": "DÊplacÊ vers la corbeille",
"errorState": "Erreur critique : {0}",
"readonly": "Lecture seule",
- "anonymous": "Anonyme",
+ "anonymous": "Visiteur",
"users": "Utilisateurs",
"viewer": "lecteur",
"viewers": "lecteurs",
@@ -89,7 +89,7 @@
"shareSuccess": "Lien copiÊ dans le presse-papiers",
"userListButton": "Liste d'utilisateurs",
"chatButton": "Chat",
- "userAccountButton": "Votre compte",
+ "userAccountButton": "Menu utilisateur",
"newButton": "Nouveau",
"newButtonTitle": "CrÊer un nouveau pad",
"uploadButton": "Importer des fichiers",
@@ -333,7 +333,7 @@
"login_invalUser": "Nom d'utilisateur requis",
"login_invalPass": "Mot de passe requis",
"login_unhandledError": "Une erreur inattendue s'est produite :(",
- "register_importRecent": "Importer les documents de votre session non-enregistrÊe",
+ "register_importRecent": "Importer les documents de votre session visiteur",
"register_acceptTerms": "J'accepte les conditions d'utilisation ",
"register_passwordsDontMatch": "Les mots de passe doivent ÃĒtre identiques !",
"register_passwordTooShort": "Les mots de passe doivent contenir au moins {0} caractères.",
@@ -502,7 +502,7 @@
"whatis_drive": "Organisation avec CryptDrive",
"features": "FonctionnalitÊs",
"features_title": "FonctionnalitÊs",
- "features_anon": "Non-enregistrÊ",
+ "features_anon": "Visiteur",
"features_registered": "EnregistrÊ",
"features_premium": "Premium",
"features_f_apps": "Accès à toutes les applications",
@@ -514,7 +514,7 @@
"features_f_cryptdrive0_note": "Stockage dans votre navigateur des pads visitÊs afin de pouvoir les retrouver plus tard",
"features_f_storage0": "DurÊe de stockage limitÊe",
"features_f_storage0_note": "Les documents sont supprimÊs après {0} jours d'inactivitÊ",
- "features_f_anon": "Avantages des utilisateurs anonymes",
+ "features_f_anon": "Avantages des visiteurs",
"features_f_anon_note": "Avec des fonctionnalitÊs supplÊmentaires",
"features_f_cryptdrive1": "Accès complet à CryptDrive",
"features_f_cryptdrive1_note": "Dossiers, dossiers partagÊs, modèles, tags",
@@ -561,7 +561,7 @@
"creation_expireDays": "Jour(s)",
"creation_expireMonths": "Mois",
"creation_password": "Mot de passe\n",
- "creation_noTemplate": "Pas de modèle",
+ "creation_noTemplate": "Document vierge",
"creation_newTemplate": "Nouveau modèle",
"creation_create": "CrÊer",
"creation_owners": "PropriÊtaires",
@@ -588,8 +588,8 @@
"share_linkView": "Lecture-seule",
"share_linkEmbed": "Mode intÊgration (cache la barre d'outils)",
"share_linkPresent": "PrÊsenter",
- "share_linkOpen": "Aperçu",
- "share_linkCopy": "Copier",
+ "share_linkOpen": "Ouvrir le lien",
+ "share_linkCopy": "Copier le lien",
"share_embedCategory": "IntÊgration",
"share_mediatagCopy": "Copier le mediatag",
"sharedFolders_forget": "Ce pad est stockÊ uniquement dans un dossier partagÊ. Vous ne pouvez pas le dÊplacer dans votre corbeille. Si vous souhaitez le supprimer, vous pouvez utiliser l'application CryptDrive.",
@@ -879,7 +879,7 @@
"oo_exportInProgress": "Exportation en cours",
"oo_sheetMigration_loading": "Mise à jour de la feuille de calcul. Merci de patienter environ 1 minute.",
"oo_sheetMigration_complete": "Version mise à jour disponible, appuyez sur OK pour recharger.",
- "oo_sheetMigration_anonymousEditor": "L'Êdition de cette feuille de calcul est dÊsactivÊe pour les utilisateurs non-enregistrÊs jusqu'à ce qu'elle soit mise à jour par un utilisateur enregistrÊ.",
+ "oo_sheetMigration_anonymousEditor": "L'Êdition de cette feuille de calcul est dÊsactivÊe pour les visiteurs jusqu'à ce qu'elle soit mise à jour par un utilisateur enregistrÊ.",
"imprint": "Mentions lÊgales",
"isContact": "{0} est dans vos contacts",
"isNotContact": "{0} n'est pas dans vos contacts",
@@ -1108,7 +1108,7 @@
"whatis_apps": "Une suite complète d'applications",
"whatis_collaboration_info": "CryptPad est construit pour permettre la collaboration. Les modifications apportÊes aux documents sont synchronisÊes en temps rÊel. Comme toutes les donnÊes sont chiffrÊes, le service et ses administrateurs n'ont aucun moyen de voir le contenu en cours d'Êdition et de stockage.
",
"register_warning_note": "En raison de la nature chiffrÊe de CryptPad, les administrateurs du service ne seront pas en mesure de rÊcupÊrer les donnÊes au cas oÚ vous oublieriez votre nom d'utilisateur et/ou votre mot de passe. Veuillez les sauvegarder dans un endroit sÃģr.",
- "register_notes": "Votre mot de passe est la clÊ secrète utilisÊe pour chiffrer tous vos documents. Si vous le perdez, nous ne pourrons pas rÊcupÊrer vos donnÊes. Si vous utilisez un ordinateur partagÊ, n'oubliez pas de vous dÊconnecter après avoir terminÊ. La simple fermeture de la fenÃĒtre du navigateur laisse votre compte exposÊ. Pour conserver les documents que vous avez crÊÊs et/ou stockÊs sans ÃĒtre connectÊ, cochez \"Importer les documents de votre session anonyme\". ",
+ "register_notes": "Votre mot de passe est la clÊ secrète utilisÊe pour chiffrer tous vos documents. Si vous le perdez, nous ne pourrons pas rÊcupÊrer vos donnÊes. Si vous utilisez un ordinateur partagÊ, n'oubliez pas de vous dÊconnecter après avoir terminÊ. La simple fermeture de la fenÃĒtre du navigateur laisse votre compte exposÊ. Pour conserver les documents que vous avez crÊÊs et/ou stockÊs sans ÃĒtre connectÊ, cochez \"Importer les documents de votre session visiteur\". ",
"register_notes_title": "Notes importantes",
"home_support": "L'Êquipe de dÊveloppement ne tire aucun profit des donnÊes personnelles des utilisateurs. Cela s'inscrit dans une vision pour des services en ligne qui respectent la vie privÊe. Contrairement aux grandes plateformes qui prÊtendent ÃĒtre \"gratuites\" tout en tirant profit des informations personnelles, CryptPad vise à construire un modèle durable financÊ volontairement par les utilisateurs.
Vous pouvez soutenir le projet en faisant un don unique ou rÊcurrent par le biais de notre Open Collective. Notre budget est transparent et des mises à jour sont publiÊes rÊgulièrement. Il existe Êgalement un certain nombre de moyens non financiers de contribuer .
",
"home_support_title": "Soutenez CryptPad",
@@ -1230,7 +1230,7 @@
"genericCopySuccess": "CopiÊ dans le presse-papiers",
"mediatag_defaultImageName": "image",
"register_registrationIsClosed": "Les inscriptions sont fermÊes.",
- "oo_conversionSupport": "Votre navigateur ne gère pas la conversion vers et depuis les formats Microsoft Office. Il est recommandÊ d'utiliser une version rÊcente de Firefox ou Chrome.",
+ "oo_conversionSupport": "Votre navigateur ne gère pas la conversion vers et depuis les formats office. Il est recommandÊ d'utiliser une version rÊcente de Firefox ou Chrome.",
"oo_importBin": "Cliquez sur OK pour importer au format .bin interne à CryptPad.",
"admin_emailButton": "Valider",
"admin_supportPrivButton": "Afficher la clÊ",
@@ -1274,16 +1274,16 @@
"form_clear": "Effacer",
"form_addMultipleHint": "Ajouter plusieurs dates et heures",
"form_addMultiple": "Tout ajouter",
- "form_anonymous_blocked": "Les rÊponses anonymes sont bloquÊes pour ce formulaire. Merci de vous connecter ou de vous enregistrer pour rÊpondre.",
+ "form_anonymous_blocked": "Les rÊponses de visiteurs sont bloquÊes pour ce formulaire. Merci de vous connecter ou de vous enregistrer pour rÊpondre.",
"form_add_item": "Ajouter un objet",
"form_add_option": "Ajouter une option",
"form_newItem": "Nouvel objet",
"form_newOption": "Nouvelle option",
"form_defaultItem": "Objet {0}",
"form_defaultOption": "Option {0}",
- "form_anonymous_off": "BloquÊes",
- "form_anonymous_on": "AutorisÊes",
- "form_anonymous": "RÊponses anonymes",
+ "form_anonymous_off": "BloquÊ",
+ "form_anonymous_on": "AutorisÊ",
+ "form_anonymous": "Accès visiteur (non connectÊ)",
"form_willClose": "Ce formulaire fermera le {0}",
"form_isClosed": "Ce formulaire a ÊtÊ fermÊ le {0}",
"form_isOpen": "Ce formulaire est ouvert",
@@ -1292,7 +1292,7 @@
"form_open": "Ouvrir",
"form_isPrivate": "Les rÊponses sont privÊes",
"form_isPublic": "Les rÊponses sont publiques",
- "form_makePublicWarning": "Ãtes-vous sÃģr de vouloir rendre les rÊponses à ce formulaire publiques ? Cette opÊration ne peut pas ÃĒtre annulÊe.",
+ "form_makePublicWarning": "Ãtes-vous sÃģr de vouloir rendre publiques les rÊponses à ce formulaire ? Les rÊponses passÊes et futures seront visibles par les participants. Cette opÊration ne peut pas ÃĒtre annulÊe.",
"form_makePublic": "Publier les rÊponses",
"form_invalidQuestion": "Questions {0}",
"form_invalidWarning": "Certaines rÊsponses contiennent des erreurs :",
@@ -1309,7 +1309,7 @@
"form_form": "Formulaire",
"form_editor": "Ãditeur",
"form_results_empty": "Il n'y a pas de rÊponses",
- "form_results": "RÊponses",
+ "form_results": "RÊponses ({0})",
"form_answered": "Vous avez dÊjà rÊpondu à ce formulaire",
"form_cantFindAnswers": "Vos rÊponses à ce formulaire n'ont pas pu ÃĒtre rÊcupÊrÊes.",
"form_updateWarning": "Mettre à jour avec erreurs",
@@ -1381,5 +1381,48 @@
"fm_link_new": "Nouveau Lien",
"notification_openLink": "Vous avez reçu un lien {0} de {1} :",
"ui_expand": "DÊvelopper",
- "ui_collapse": "RÊduire"
+ "ui_collapse": "RÊduire",
+ "form_totalResponses": "Nombre de rÊponses : {0}",
+ "form_colors": "Thème de couleur",
+ "userlist_visitProfile": "Voir le profil",
+ "form_conditional_addAnd": "Ajouter une condition et",
+ "form_conditional_add": "Ajouter une condition ou",
+ "form_conditional": "Cette section ne sera affichÊe que si :",
+ "form_condition_has": "contient",
+ "form_condition_hasnot": "ne contient pas",
+ "form_condition_is": "est",
+ "form_condition_isnot": "n'est pas",
+ "form_condition_v": "Choisir une rÊponse",
+ "form_condition_q": "Choisir une question",
+ "form_type_section": "Section conditionelle",
+ "form_editable": "Modifier les rÊponses après l'envoi",
+ "form_responseMsg": "Ce message s'affichera après l'envoi du formulaire par un participant.",
+ "form_makeAnon": "Anonymiser les rÊsponses",
+ "form_corruptAnswers": "Ce formulaire a dÊjà reçu des rÊponses. La modification du type de question risque d'invalider les donnÊes des rÊponses prÊcÊdentes.",
+ "form_geturl": "Copier le lien",
+ "toolbar_preview": "Aperçu",
+ "form_updateMsg": "Modifier le message de confirmation",
+ "form_addMsg": "Ajouter un message de confirmation",
+ "form_changeTypeConfirm": "SÊlectionner le type de question.",
+ "form_preview": "Aperçu",
+ "form_required_off": "Optionelle",
+ "form_required_on": "Requise",
+ "form_required_answer": "RÊponse : ",
+ "form_requiredWarning": "Une rÊponse est requise pour les questions suivantes :",
+ "form_authAnswer": "Ce formulaire ne peut pas ÃĒtre envoyÊ de manière anonyme",
+ "form_anonAnswer": "Les rÊponses à ce formulaire sont anonymisÊes",
+ "form_viewAllAnswers": "Voir toutes les rÊponses ({0})",
+ "form_viewAnswer": "Voir mes rÊponses",
+ "form_editAnswer": "Modifier mes rÊponses",
+ "form_alreadyAnswered": "Vous avez repondu à ce formulaire le {0}",
+ "form_preview_button": "Aperçu",
+ "form_template_poll": "Sondage de disponibilitÊ",
+ "upload_addOptionalAlt": "Ajouter un texte descitpif (optionnel)",
+ "upload_modal_alt": "Texte alternatif",
+ "profile_defaultAlt": "Image de profil par dÊfaut",
+ "toolbar_expand": "Afficher la barre d'outils",
+ "toolbar_collapse": "Cacher la barre d'outils",
+ "support_premiumLink": "Voir les options d'abonnement",
+ "support_premiumPriority": "Les utilisateurs abonnÊs contribuent à l'amÊlioration des fonctionnalitÊs de CryptPad et bÊnÊficient de rÊponses prioritaires à leurs tickets de support.",
+ "form_conditional_hint": "Pour rendre cette section conditionnelle, veuillez ajouter une question choix ou cases à cocher ci-dessus"
}
diff --git a/www/common/translations/messages.ja.json b/www/common/translations/messages.ja.json
index 55bb0b8c5..9b3676143 100644
--- a/www/common/translations/messages.ja.json
+++ b/www/common/translations/messages.ja.json
@@ -123,7 +123,7 @@
"login_hashing": "ããšã¯ãŧãããããˇãĨåããĻããžããããŽåĻįãĢã¯æéããããå ´åããããžãã",
"login_invalPass": "ããšã¯ãŧããå
ĨåããĻãã ãã",
"login_invalUser": "ãĻãŧãļãŧåãå
ĨåããĻãã ãã",
- "register_importRecent": "åŋåãģããˇã§ãŗãŽãããĨãĄãŗããã¤ãŗããŧã",
+ "register_importRecent": "ã˛ãšããģããˇã§ãŗãŽãããĨãĄãŗããã¤ãŗããŧã",
"importButton": "ã¤ãŗããŧã",
"main_catch_phrase": "ãŗãŠããŦãŧãˇã§ãŗãšã¤ãŧã įĢ¯æĢéæåˇåã¨ãĒãŧããŗãŊãŧãš",
"tos_3rdparties": "į§ããĄã¯ãæŗäģ¤ãĢåēãĨãå ´åãé¤ããåäēēæ
å ąãįŦŦä¸č
ãĢæäžããžããã",
@@ -196,7 +196,7 @@
"contacts_unmute": "ããĨãŧãč§Ŗé¤",
"contacts_mute": "ããĨãŧã",
"contacts": "éŖįĩĄå
",
- "share_linkOpen": "ããŦããĨãŧ",
+ "share_linkOpen": "ãĒãŗã¯ãéã",
"share_linkView": "襨į¤ē",
"view": "襨į¤ē",
"settings_exportError": "襨į¤ēã¨ãŠãŧ",
@@ -206,7 +206,7 @@
"reconnecting": "åæĨįļä¸",
"synchronizing": "åæä¸",
"initializing": "åæåä¸...",
- "anonymous": "åŋå",
+ "anonymous": "ã˛ãšã",
"editor": "įˇ¨éč
",
"typing": "įˇ¨éä¸",
"team_infoLabel": "ããŧã ãĢã¤ããĻ",
@@ -265,7 +265,7 @@
"features_f_cryptdrive1_note": "ããŠãĢããå
ąæããŠãĢããããŗããŦãŧãããŋã°",
"features_f_cryptdrive1": "CryptDriveãŽå
¨æŠčŊ",
"features_f_anon_note": "čŋŊå æŠčŊãã",
- "features_f_anon": "åŋåãĻãŧãļãŧãŽå
¨æŠčŊ",
+ "features_f_anon": "ã˛ãšããĻãŧãļãŧãŽå
¨æŠčŊ",
"features_f_storage0_note": "ãããĨãĄãŗãã¯{0}æĨäģĨä¸åŠį¨ãããĒãã¨åé¤ãããžã",
"features_f_storage0": "ä¸æįãĒäŋå",
"features_f_cryptdrive0_note": "ãĸã¯ãģãšããããããããŠãĻãļãĢäŋåããĻãåžã§éããã¨ãã§ããžã",
@@ -278,7 +278,7 @@
"features_premium": "ããŦããĸã ",
"features_registered": "įģé˛æ¸",
"features_title": "æŠčŊ",
- "features_anon": "æĒįģé˛",
+ "features_anon": "ã˛ãšã",
"register_whyRegister": "įģé˛ãããĄãĒããããį´šäģããžã",
"historyText": "åąĨæ´",
"help_button": "ããĢã",
@@ -481,7 +481,7 @@
"upload_pending": "äŋįä¸",
"settings_resetTips": "ããŗã",
"chrome68": "ããŧã¸ã§ãŗ68ãŽChromeãããã¯ChromiumãäŊŋį¨ããĻããããã§ããããŽããŧã¸ã§ãŗãĢã¯ãæ°į§įĩéããåžã§ããŧã¸ãįŊį´ãĢãĒãŖãããã¯ãĒãã¯ãĢããŧã¸ãååŋããĒããĒãŖãããããã°ããããžããããŽåéĄãč§ŖæąēãããĢã¯ãåĨãŽãŋãã襨į¤ēããĻæšããĻ襨į¤ēããããããŽããŧã¸ã§ãšã¯ããŧãĢãčŠĻãŋãĻãã ãããããŽãã°ã¯æŦĄãŽããŧã¸ã§ãŗã§č§ŖæąēãããäēåŽã¨ãĒãŖãĻããžãã",
- "register_notes": "ãããĨãĄãŗãã¯ãããšã¯ãŧããĢããŖãĻæåˇåãããžããããšã¯ãŧããį´å¤ąããã¨ãããŧãŋã垊å
ãããã¨ã¯ã§ããžããã å
ąæãŽãŗãŗããĨãŧãŋãäŊŋį¨ããĻããå ´åã¯ãäŊæĨåŽäēæãĢåŋãããã°ãĸãĻãããĻãã ããã ããŠãĻãļãŧãŽãĻã¤ãŗããĻãéããĻãããĸãĢãĻãŗãããã¯ãã°ãĸãĻããããžããã æĒãã°ã¤ãŗã§äŊæãå
ąæããããĄã¤ãĢãäŋåãããĢã¯ã ãåŋåãģããˇã§ãŗãŽãããĨãĄãŗããã¤ãŗããŧãããĢãã§ãã¯ãããĻãã ããã ",
+ "register_notes": "ãããĨãĄãŗãã¯ãããšã¯ãŧããĢããŖãĻæåˇåãããžããããšã¯ãŧããį´å¤ąããã¨ãããŧãŋã垊å
ãããã¨ã¯ã§ããžããã å
ąæãŽãŗãŗããĨãŧãŋãäŊŋį¨ããĻããå ´åã¯ãäŊæĨåŽäēæãĢåŋãããã°ãĸãĻãããĻãã ããã ããŠãĻãļãŧãŽãĻã¤ãŗããĻãéããĻãããĸãĢãĻãŗãããã¯ãã°ãĸãĻããããžããã æĒãã°ã¤ãŗã§äŊæãå
ąæããããĄã¤ãĢãäŋåãããĢã¯ã ãã˛ãšããģããˇã§ãŗãŽãããĨãĄãŗããã¤ãŗããŧãããĢãã§ãã¯ãããĻãã ããã ",
"poll_commit": "éäŋĄ",
"admin_removeDonateButtonTitle": "ã¯ãŠãĻãããĄãŗããŖãŗã°ã¸ãŽåå ",
"mediatag_notReady": "ããĻãŗããŧããåŽäēããĻãã ãã",
@@ -525,7 +525,7 @@
"crowdfunding_popup_no": "ãã¨ã§",
"sharedFolders_create_name": "ããŠãĢãå",
"creation_newTemplate": "æ°ããããŗããŦãŧã",
- "creation_noTemplate": "ããŗããŦãŧãããããžãã",
+ "creation_noTemplate": "įŠēãŽãããĨãĄãŗã",
"creation_expire": "æéåããŽããã",
"mdToolbar_list": "įŽæĄæ¸ã",
"uploadFolder_modal_filesPassword": "ããĄã¤ãĢãŽããšã¯ãŧã",
@@ -626,7 +626,7 @@
"autostore_pad": "ããã",
"autostore_sf": "ããŠãĢã",
"autostore_file": "ããĄã¤ãĢ",
- "share_linkCopy": "ãŗããŧ",
+ "share_linkCopy": "ãĒãŗã¯ããŗããŧ",
"creation_passwordValue": "ããšã¯ãŧã",
"edit": "įˇ¨é",
"features": "æŠčŊ",
@@ -746,7 +746,7 @@
"saveTemplatePrompt": "ããŗããŦãŧããŽãŋã¤ããĢãå
ĨåããĻãã ãã",
"newButtonTitle": "æ°ããããããäŊæ",
"newButton": "æ°čĻ",
- "userAccountButton": "ãĸãĢãĻãŗã",
+ "userAccountButton": "ãĄããĨãŧ",
"userListButton": "ãĻãŧãļãŧãĒãšã",
"movedToTrash": "ããããã´ãįŽąãĢį§ģåããžãããããŠã¤ããĢãĸã¯ãģãš ",
"forgetPrompt": "OKãã¯ãĒãã¯ããã¨ããããã´ãįŽąã¸ã¨į§ģåããžããããããã§ããīŧ",
@@ -774,7 +774,7 @@
"inactiveError": "ããŽãããã¯åŠį¨ãããĻããĒããŖãããåé¤ãããžãããEscããŧãæŧãã¨æ°ããããããäŊæããžãã",
"deletedError": "ããŽãããĨãĄãŗãã¯åé¤ããããããåŠį¨ã§ããĒããĒããžããã",
"expiredError": "ããŽãããã¯åŠį¨æéãéããĻããžãŖããããåŠį¨ã§ããĒããĒããžããã",
- "anonymousStoreDisabled": "ããŽCryptPadãŽã¤ãŗãšãŋãŗãšãŽįŽĄįč
ã¯ãåŋåãĻãŧãļãŧãĢããäŋåãįĄåšãĢč¨åŽããĻããžããCryptDriveãäŊŋį¨ãããĢã¯ãã°ã¤ãŗããåŋ
čĻããããžãã",
+ "anonymousStoreDisabled": "ããŽCryptPadãŽã¤ãŗãšãŋãŗãšãŽįŽĄįč
ã¯ãã˛ãšããĢããäŋåãįĄåšãĢč¨åŽããĻããžããããĒããŽCryptDriveãĢãĸã¯ãģãšãããĢã¯ãã°ã¤ãŗãåŋ
čĻã§ãã",
"padNotPinnedVariable": "ããŽãããã¯{4}æĨéåŠį¨ããĒãã¨æåšæéãåããžãã{0}ãã°ã¤ãŗ{1}ããã{2}įģé˛{3}ããĻäŋåããĻãã ããã",
"padNotPinned": "ããŽãããã¯3ãæéåŠį¨ããĒãã¨æåšæéãåããžãã{0}ãã°ã¤ãŗ{1}ããã{2}įģé˛{3}ããĻäŋåããĻãã ããã",
"onLogout": "ãã°ãĸãĻãããžããã{0}ãããã¯ãĒãã¯{1}ãããEscape ããŧãæŧãã¨ãé˛čĻ§ãĸãŧãã§ããããĢãĸã¯ãģãšã§ããžãã",
@@ -897,7 +897,7 @@
"mdToolbar_embed": "ãŋã¤ããĢãåãčžŧã",
"copyToClipboard": "ã¯ãĒããããŧããĢãŗããŧ",
"form_anonymousBox": "åŋåã§åį",
- "form_anonymous_blocked": "åŋåãŽåįã¯ãããã¯ãããĻããžããåįãĢ㯠ãã°ã¤ãŗ ãããã¯įģé˛ ãåŋ
čĻã§ãã",
+ "form_anonymous_blocked": "ã˛ãšããŽåįã¯ãããã¯ãããĻããžããåįãĢ㯠ãã°ã¤ãŗ ãããã¯įģé˛ ãåŋ
čĻã§ãã",
"form_add_item": "é
įŽãčŋŊå ",
"form_type_radio": "é¸æčĸ",
"form_makePublicWarning": "åįãå
ŦéããĻããããã§ããīŧããã¯åãæļããžããã",
@@ -905,7 +905,7 @@
"form_showSummary": "æĻčĻã襨į¤ē",
"form_showIndividual": "åã
ãŽåįã襨į¤ē",
"form_results_empty": "åįããããžãã",
- "form_results": "åį",
+ "form_results": "åįīŧ{0}īŧ",
"form_answered": "ããŽããŠãŧã ã¯åįæ¸ãŋã§ã",
"form_cantFindAnswers": "ããŽããŠãŧã ãŽæĸåãŽåįãååžã§ããžããã",
"form_duplicates": "éč¤ããé
įŽãåé¤ãããžãã",
@@ -1075,7 +1075,7 @@
"form_add_option": "ãĒããˇã§ãŗãčŋŊå ",
"form_newItem": "æ°ããé
įŽ",
"form_newOption": "æ°ãããĒããˇã§ãŗ",
- "form_anonymous": "åŋåãŽåį",
+ "form_anonymous": "ã˛ãšããĸã¯ãģãšīŧæĒãã°ã¤ãŗīŧ",
"form_removeEnd": "įˇ åæĨãåé¤",
"form_setEnd": "įˇ åæĨãč¨åŽ",
"form_isPrivate": "åįã¯å
ŦéãããĻããžãã",
@@ -1095,7 +1095,7 @@
"trimHistory_getSizeError": "ããŠã¤ããŽåąĨæ´ãŽãĩã¤ãēãč¨įŽããĻããéä¸ã§ã¨ãŠãŧãįēįããžãã",
"profile_login": "ããŽãĻãŧãļãŧãéŖįĩĄå
ãĢčŋŊå ãããĢã¯ãã°ã¤ãŗããåŋ
čĻããããžã",
"dontShowAgain": "åãŗ襨į¤ēããĒã",
- "oo_sheetMigration_anonymousEditor": "įģé˛ãĻãŧãļãŧãææ°ãŽããŧã¸ã§ãŗãĢæ´æ°ãããžã§ãããŽãšããŦãããˇãŧããæĒįģé˛ãĻãŧãļãŧãįˇ¨éãããã¨ã¯ã§ããžããã",
+ "oo_sheetMigration_anonymousEditor": "įģé˛ãĻãŧãļãŧãææ°ãŽããŧã¸ã§ãŗãĢæ´æ°ãããžã§ãããŽãšããŦãããˇãŧããã˛ãšããįˇ¨éãããã¨ã¯ã§ããžããã",
"oo_invalidFormat": "ããŽããĄã¤ãĢã¯ã¤ãŗããŧãã§ããžãã",
"burnAfterReading_warningDeleted": "ããŽãããã¯åé¤ãããžããããĻã¤ãŗããĻãéããåžã§åãŗãĸã¯ãģãšãããã¨ã¯ã§ããžããã",
"burnAfterReading_proceed": "襨į¤ēããĻåé¤",
@@ -1382,5 +1382,39 @@
"form_answerAs": "ååãč¨å
ĨããĻãã ãã",
"form_totalResponses": "åįæ°īŧ{0}",
"ui_expand": "åēãã",
- "ui_collapse": "æãããã"
+ "ui_collapse": "æãããã",
+ "support_premiumPriority": "ããŦããĸã ãĻãŧãļãŧãĢãĒãã¨ãCryptPadãŽäŊŋãåæãæšč¯ããæåŠããã§ãããģãããĩããŧãããąãããĢ寞ããåĒå
ãĩããŧããåãããã¨ãã§ããžãã",
+ "support_premiumLink": "åŽéĄåŠį¨ãŽãĒããˇã§ãŗã襨į¤ē",
+ "toolbar_collapse": "ããŧãĢããŧãããã",
+ "toolbar_expand": "ããŧãĢããŧãåēãã",
+ "form_preview": "ããŠãŧã ãããŦããĨãŧ",
+ "form_geturl": "ãĒãŗã¯ããŗããŧ",
+ "form_viewAnswer": "åįã襨į¤ē",
+ "form_editAnswer": "åįãįˇ¨é",
+ "form_preview_button": "ããŦããĨãŧ",
+ "upload_addOptionalAlt": "čĒŦææãčŋŊå īŧäģģæīŧ",
+ "upload_modal_alt": "äģŖæŋãããšã",
+ "form_authAnswer": "ããŽããŠãŧã ã¯åŋåã§ã¯éäŋĄã§ããžãã",
+ "form_anonAnswer": "ããŽããŠãŧã ã¸ãŽåįã¯åŋååãããĻããžã",
+ "form_viewAllAnswers": "å
¨ãĻãŽåįã襨į¤ēīŧ{0}īŧ",
+ "form_condition_v": "å¤ãé¸æ",
+ "form_condition_q": "čŗĒåãé¸æ",
+ "form_makeAnon": "åįãåŋåå",
+ "toolbar_preview": "ããŦããĨãŧ",
+ "form_required_off": "äģģæ",
+ "form_required_on": "åŋ
é ",
+ "form_colors": "ããŧããŽč˛",
+ "profile_defaultAlt": "æĸåŽãŽããããŖãŧãĢįģå",
+ "userlist_visitProfile": "ããããŖãŧãĢã襨į¤ē",
+ "form_addMsg": "éäŋĄæãŽãĄããģãŧã¸ãčŋŊå ",
+ "form_updateMsg": "éäŋĄæãŽãĄããģãŧã¸ãå¤æ´",
+ "form_corruptAnswers": "ããŽããŠãŧã ãĢã¯æĸãĢåįããããžããč¨åãŽį¨ŽéĄãå¤æ´ããã¨ãåįãŽããŧãŋãįĄåšãĢãĒãæãããããžãã",
+ "form_changeTypeConfirm": "æ°ããč¨åãŽį¨ŽéĄãé¸æããĻãã ããã",
+ "form_required_answer": "åįīŧ ",
+ "form_requiredWarning": "äģĨä¸ãŽč¨åã¯åįãåŋ
é ã§ãīŧ",
+ "form_alreadyAnswered": "ããŽããŠãŧã ãĢ{0}ãĢåįããžãã",
+ "form_conditional_hint": "ããŽãģã¯ãˇã§ãŗãį§å¯ãĢãããĢã¯ãããŽä¸ãĢé¸æãããã¯ãã§ãã¯ããã¯ãšãŽč¨åãčŋŊå ããĻãã ãã",
+ "form_editable": "éäŋĄåžãŽįˇ¨é",
+ "form_responseMsg": "åå č
ãããŠãŧã ãéäŋĄããã¨äģĨä¸ãŽãĄããģãŧã¸ã襨į¤ēãããžãã",
+ "form_type_section": "æĄäģļãŽãģã¯ãˇã§ãŗ"
}
diff --git a/www/common/translations/messages.json b/www/common/translations/messages.json
index 9b4020fc4..ad8e165df 100644
--- a/www/common/translations/messages.json
+++ b/www/common/translations/messages.json
@@ -28,7 +28,7 @@
"onLogout": "You are logged out, {0}click here{1} to log in or press Escape to access your pad in read-only mode.",
"padNotPinned": "This pad will expire after 3 months of inactivity, {0}login{1} or {2}register{3} to preserve it.",
"padNotPinnedVariable": "This pad will expire after {4} days of inactivity, {0}login{1} or {2}register{3} to preserve it.",
- "anonymousStoreDisabled": "The webmaster of this CryptPad instance has disabled the store for anonymous users. You have to log in to be able to use CryptDrive.",
+ "anonymousStoreDisabled": "The administrator of this CryptPad instance has disabled storage for guests. Log in to access your own CryptDrive.",
"expiredError": "This pad has reached its expiration time and is no longer available.",
"deletedError": "This document has been deleted and is no longer available.",
"inactiveError": "This pad has been deleted due to inactivity. Press Esc to create a new pad.",
@@ -53,7 +53,7 @@
"forgotten": "Moved to the trash",
"errorState": "Critical error: {0}",
"readonly": "Read only",
- "anonymous": "Anonymous",
+ "anonymous": "Guest",
"users": "Users",
"viewer": "viewer",
"viewers": "viewers",
@@ -92,7 +92,7 @@
"shareSuccess": "Copied link to clipboard",
"userListButton": "User list",
"chatButton": "Chat",
- "userAccountButton": "Your account",
+ "userAccountButton": "User menu",
"newButton": "New",
"newButtonTitle": "Create a new pad",
"uploadButton": "Upload files",
@@ -339,7 +339,7 @@
"login_invalUser": "Username required",
"login_invalPass": "Password required",
"login_unhandledError": "An unexpected error occurred :(",
- "register_importRecent": "Import documents from your unregistered session",
+ "register_importRecent": "Import documents from your guest session",
"register_acceptTerms": "I accept the terms of service ",
"register_passwordsDontMatch": "Passwords do not match!",
"register_passwordTooShort": "Passwords must be at least {0} characters long.",
@@ -520,7 +520,7 @@
"whatis_drive": "Organization with CryptDrive",
"features": "Features",
"features_title": "Features",
- "features_anon": "Non-registered",
+ "features_anon": "Guest",
"features_registered": "Registered",
"features_premium": "Premium",
"features_f_apps": "Access to all the applications",
@@ -532,7 +532,7 @@
"features_f_cryptdrive0_note": "Ability to store visited pads in your browser to be able to open them later",
"features_f_storage0": "Limited storage time",
"features_f_storage0_note": "Documents are deleted after {0} days of inactivity",
- "features_f_anon": "All anonymous user features",
+ "features_f_anon": "All guest user features",
"features_f_anon_note": "With additional functionality",
"features_f_cryptdrive1": "Complete CryptDrive functionality",
"features_f_cryptdrive1_note": "Folders, shared folders, templates, tags",
@@ -579,7 +579,7 @@
"creation_expireDays": "Day(s)",
"creation_expireMonths": "Month(s)",
"creation_password": "Password\n",
- "creation_noTemplate": "No template",
+ "creation_noTemplate": "Blank document",
"creation_newTemplate": "New template",
"creation_create": "Create",
"creation_owners": "Owners",
@@ -606,8 +606,8 @@
"share_linkView": "View",
"share_linkEmbed": "Embed mode (hide toolbar and user list)",
"share_linkPresent": "Present",
- "share_linkOpen": "Preview",
- "share_linkCopy": "Copy",
+ "share_linkOpen": "Open link",
+ "share_linkCopy": "Copy link",
"share_contactCategory": "Contacts",
"share_embedCategory": "Embed",
"share_mediatagCopy": "Copy mediatag to clipboard",
@@ -884,7 +884,7 @@
"oo_exportInProgress": "Export in progress",
"oo_sheetMigration_loading": "Upgrading your spreadsheet to the latest version. Please wait approximately 1 minute.",
"oo_sheetMigration_complete": "Updated version available, press OK to reload.",
- "oo_sheetMigration_anonymousEditor": "Editing this spreadsheet is disabled for non-registered users until it is upgraded to the latest version by a registered user.",
+ "oo_sheetMigration_anonymousEditor": "Editing this spreadsheet is disabled for guests until it is upgraded to the latest version by a registered user.",
"imprint": "Legal notice",
"settings_cat_security": "Confidentiality",
"settings_safeLinksTitle": "Safe Links",
@@ -1108,7 +1108,7 @@
"home_support_title": "Support CryptPad",
"home_support": "The development team does not profit from user data in any way. This is part of a vision for online services that respect privacy. Unlike the big platforms that pretend to be \"free\" while making profits from personal information, we aim to build a sustainable model funded willingly by users.
You can support the project by making a one-time or recurring donation through our Open Collective. Our budget is transparent and updates are published regularly. There are also a number of non-financial ways to contribute .
",
"register_notes_title": "Important notes",
- "register_notes": "Your password is the secret key that encrypts all of your documents. If you lose it there is no way we can recover your data. If you are using a shared computer, remember to log out when you are done. Only closing the browser window leaves your account exposed. To keep the documents you created and/or stored without being logged in, tick \"Import documents from your anonymous session\". ",
+ "register_notes": "Your password is the secret key that encrypts all of your documents. If you lose it there is no way we can recover your data. If you are using a shared computer, remember to log out when you are done. Only closing the browser window leaves your account exposed. To keep the documents you created and/or stored without being logged in, tick \"Import documents from your guest session\". ",
"register_warning_note": "Due to the encrypted nature of CryptPad, the service administrators will not be able to recover data in case you forget your username and/or password. Please save them in a safe place.",
"whatis_collaboration_info": "CryptPad is built to enable collaboration. It synchronizes changes to documents in real time. Because all data is encrypted, the service and its administrators have no way of seeing the content being edited and stored.
",
"whatis_apps": "A full suite of applications",
@@ -1284,7 +1284,7 @@
"form_updateWarning": "Update anyway",
"form_cantFindAnswers": "Unable to retrieve your existing answers for this form.",
"form_answered": "You have already answered this form",
- "form_results": "Responses",
+ "form_results": "Responses ({0})",
"form_results_empty": "There are no responses",
"form_editor": "Editor",
"form_form": "Form",
@@ -1301,7 +1301,7 @@
"form_invalidWarning": "There are errors in some answers:",
"form_invalidQuestion": "Question {0}",
"form_makePublic": "Publish responses",
- "form_makePublicWarning": "Are you sure you want to make responses to this form public? This cannot be undone.",
+ "form_makePublicWarning": "Are you sure you want to make responses to this form public? Past and future responses will be visible by participants. This cannot be undone.",
"form_isPublic": "Responses are public",
"form_isPrivate": "Responses are private",
"form_open": "Open",
@@ -1310,7 +1310,7 @@
"form_isOpen": "This form is open",
"form_isClosed": "This form was closed on {0}",
"form_willClose": "This form will close on {0}",
- "form_anonymous": "Anonymous answers",
+ "form_anonymous": "Guest access (not logged in)",
"form_anonymous_on": "Allowed",
"form_anonymous_off": "Blocked",
"form_defaultOption": "Option {0}",
@@ -1319,7 +1319,7 @@
"form_newItem": "New item",
"form_add_option": "Add option",
"form_add_item": "Add item",
- "form_anonymous_blocked": "Anonymous responses are blocked for this form. You must log in or register to submit answers.",
+ "form_anonymous_blocked": "Guest responses are blocked for this form. You must log in or register to submit answers.",
"form_addMultiple": "Add all",
"form_addMultipleHint": "Add multiple dates and times",
"form_clear": "Clear",
@@ -1382,5 +1382,47 @@
"fm_link_invalid": "Invalid URL",
"ui_collapse": "Collapse",
"ui_expand": "Expand",
- "form_totalResponses": "Total responses: {0}"
+ "form_totalResponses": "Total responses: {0}",
+ "support_premiumPriority": "Premium users help support improvements to CryptPad's usability and benefit from prioritized responses to their support tickets.",
+ "support_premiumLink": "View subscription options",
+ "toolbar_collapse": "Collapse toolbar",
+ "toolbar_expand": "Expand toolbar",
+ "profile_defaultAlt": "Default profile picture",
+ "upload_modal_alt": "Alt text",
+ "upload_addOptionalAlt": "Add descriptive text (optional)",
+ "form_template_poll": "Quick Scheduling Poll",
+ "form_preview_button": "Preview",
+ "form_alreadyAnswered": "You responded to this form on {0}",
+ "form_editAnswer": "Edit my responses",
+ "form_viewAnswer": "View my responses",
+ "form_viewAllAnswers": "View all responses ({0})",
+ "form_anonAnswer": "Responses to this form are anonymized",
+ "form_authAnswer": "This form cannot be submitted anonymously",
+ "form_requiredWarning": "The following questions require an answer:",
+ "form_required_answer": "Answer: ",
+ "form_required_on": "Required",
+ "form_required_off": "Optional",
+ "form_preview": "Preview form",
+ "form_changeTypeConfirm": "Select the new question type.",
+ "form_corruptAnswers": "This form already has responses. Changing this question type may invalidate previous response data.",
+ "form_geturl": "Copy link",
+ "toolbar_preview": "Preview",
+ "form_updateMsg": "Update submit message",
+ "form_addMsg": "Add submit message",
+ "form_responseMsg": "This message will be displayed after participants submit the form.",
+ "form_makeAnon": "Anonymize responses",
+ "form_editable": "Editing after submission",
+ "form_type_section": "Conditional section",
+ "form_condition_q": "Choose a question",
+ "form_condition_v": "Choose a value",
+ "form_condition_is": "is",
+ "form_condition_isnot": "is not",
+ "form_condition_has": "has",
+ "form_condition_hasnot": "has not",
+ "form_conditional": "Only show this section when:",
+ "form_conditional_add": "Add OR condition",
+ "form_conditional_addAnd": "Add AND condition",
+ "userlist_visitProfile": "Visit profile",
+ "form_colors": "Color theme",
+ "form_conditional_hint": "To make this section conditional, please add a choice or checkbox question above it"
}
diff --git a/www/common/translations/messages.ru.json b/www/common/translations/messages.ru.json
index 56245dd92..975dd48f7 100644
--- a/www/common/translations/messages.ru.json
+++ b/www/common/translations/messages.ru.json
@@ -13,7 +13,8 @@
"todo": "ĐĄĐŋиŅĐžĐē Đ´ĐĩĐģ",
"contacts": "ĐĐ´ŅĐĩŅĐŊĐ°Ņ ĐēĐŊиĐŗĐ°",
"sheet": "ĐĸĐ°ĐąĐģиŅĐ°",
- "teams": "ĐĐžĐŧĐ°ĐŊĐ´Ņ"
+ "teams": "ĐĐžĐŧĐ°ĐŊĐ´Ņ",
+ "form": "ФОŅĐŧŅ"
},
"button_newpad": "ĐОваŅ Đ´ĐžĐēŅĐŧĐĩĐŊŅ Ņ ŅĐžŅĐŧĐ°ŅиŅОваĐŊиĐĩĐŧ",
"button_newcode": "ĐОвŅĐš Đ´ĐžĐēŅĐŧĐĩĐŊŅ Ņ ĐēОдОĐŧ",
@@ -31,13 +32,13 @@
"inactiveError": "ĐŅĐžŅ Đ´ĐžĐēŅĐŧĐĩĐŊŅ ĐąŅĐģ ŅĐ´Đ°ĐģŅĐŊ иС-Са Đ´ĐģиŅĐĩĐģŅĐŊОК ĐŊĐĩĐ°ĐēŅивĐŊĐžŅŅи. ĐĐ°ĐļĐŧиŅĐĩ Esc ŅŅОйŅ ŅОСдаŅŅ ĐŊОвŅĐš.",
"chainpadError": "ĐĐž вŅĐĩĐŧŅ ОйĐŊОвĐģĐĩĐŊиŅ ваŅĐĩĐš иĐŊŅĐžŅĐŧĐ°Ņии ĐŋŅОиСОŅĐģĐ° ĐēŅиŅиŅĐĩŅĐēĐ°Ņ ĐžŅийĐēĐ°. ĐĐžĐēŅĐŧĐĩĐŊŅ ĐŋĐžĐēĐ° Đ´ĐžŅŅŅĐŋĐĩĐŊ ŅĐžĐģŅĐēĐž Đ´ĐģŅ ŅŅĐĩĐŊиŅ ŅŅОйŅ вŅ ĐŊĐĩ ĐŋĐžŅĐĩŅŅĐģи ŅвОŅ иĐŊŅĐžŅĐŧĐ°ŅиŅ. ĐĐ°ĐļĐŧиŅĐĩ Esc ŅŅОйŅ ĐŋŅОдОĐģĐļĐ°ŅŅ ŅŅĐĩĐŊиĐĩ иĐģи ĐŋĐĩŅĐĩСаĐŗŅŅСиŅĐĩ ŅŅŅĐ°ĐŊиŅŅ и ĐŊĐ°ŅĐŊиŅĐĩ СаĐŊОвО.",
"invalidHashError": "ĐĐ°ĐŋŅĐžŅĐĩĐŊĐŊŅĐš ваĐŧи Đ´ĐžĐēŅĐŧĐĩĐŊŅ иĐŧĐĩĐĩŅ ĐŊĐĩĐŋŅавиĐģŅĐŊŅĐš Đ°Đ´ŅĐĩŅ URL.",
- "errorCopy": " ĐŅ ĐŧĐžĐļĐĩŅĐĩ ŅĐžĐģŅĐēĐž ŅĐēĐžĐŋиŅОваŅŅ ŅОдĐĩŅĐļиĐŧĐžĐĩ в Đ´ŅŅĐŗĐžĐĩ ĐŧĐĩŅŅĐž, ĐŊĐ°Đļав Esc . ĐŅĐģи вŅ СаĐēŅĐžĐĩŅĐĩ ŅŅŅĐ°ĐŊиŅŅ, вŅŅ ŅОдĐĩŅĐļиĐŧĐžĐĩ ĐąŅĐ´ĐĩŅ ŅŅĐĩŅŅĐŊĐž!",
+ "errorCopy": "ĐŅ вŅĐĩ ĐĩŅĐĩ ĐŧĐžĐļĐĩŅĐĩ ĐŋĐžĐģŅŅиŅŅ Đ´ĐžŅŅŅĐŋ Đē ŅОдĐĩŅĐļиĐŧĐžĐŧŅ, ĐŊĐ°Đļав Esc . ĐŅĐģи вŅ СаĐēŅĐžĐĩŅĐĩ ŅŅĐž ĐžĐēĐŊĐž, ŅОдĐĩŅĐļиĐŧĐžĐĩ ĐąŅĐ´ĐĩŅ ŅŅĐĩŅŅĐŊĐž.",
"errorRedirectToHome": "ĐĐ°ĐļĐŧиŅĐĩ Esc ŅŅОйŅ ĐŋĐĩŅĐĩĐšŅи Đē ваŅĐĩĐŧŅ Ņ
ŅĐ°ĐŊиĐģиŅŅ.",
"newVersionError": "ĐĐžŅŅŅĐŋĐŊĐ° ĐŊОваŅ вĐĩŅŅиŅ CryptPad.ĐĐĩŅĐĩСаĐŗŅŅСиŅĐĩ ŅŅОйŅ иŅĐŋĐžĐģŅСОваŅŅ ĐŊОвŅŅ вĐĩŅŅиŅ иĐģи ĐŊĐ°ĐļĐŧиŅĐĩ Esc, ŅŅОйŅ иŅĐŋĐžĐģŅСОваŅŅ ваŅŅ иĐŊŅĐžŅĐŧĐ°ŅиŅ в ĐžŅŅĐģĐ°ĐšĐŊ-ŅĐĩĐļиĐŧĐĩ .",
"loading": "ĐĐ°ĐŗŅŅСĐēĐ°...",
"error": "ĐŅийĐēĐ°",
"saved": "ĐĄĐžŅ
ŅĐ°ĐŊĐĩĐŊĐž",
- "deleted": "ĐĐžĐēŅĐŧĐĩĐŊŅ ŅĐ´Đ°ĐģŅĐŊ иС ваŅĐĩĐŗĐž CryptDrive",
+ "deleted": "ĐŖĐ´Đ°ĐģĐĩĐŊĐž",
"deletedFromServer": "ĐĐžĐēŅĐŧĐĩĐŊŅ ŅĐ´Đ°ĐģŅĐŊ Ņ ŅĐĩŅвĐĩŅĐ°",
"mustLogin": "ĐĐ°Đŧ ĐŊŅĐļĐŊĐž вОКŅи, ŅŅОйŅ ĐŋĐžĐģŅŅиŅŅ Đ´ĐžŅŅŅĐŋ Đē ŅŅОК ŅŅŅĐ°ĐŊиŅĐĩ",
"disabledApp": "ĐŅиĐģĐžĐļĐĩĐŊиĐĩ ĐąŅĐģĐž ĐžŅĐēĐģŅŅĐĩĐŊĐž. ХвŅĐļиŅĐĩŅŅ Ņ Đ°Đ´ĐŧиĐŊиŅŅŅĐ°ŅĐžŅĐžĐŧ ŅŅĐžĐŗĐž CryptPad.",
@@ -91,7 +92,7 @@
"userAccountButton": "ĐĐ°Ņ ĐŋŅĐžŅиĐģŅ",
"newButton": "ХОСдаŅŅ",
"uploadButton": "ĐĐ°ĐŗŅŅСиŅŅ ŅĐ°ĐšĐģŅ",
- "uploadButtonTitle": "ĐĐ°ĐŗŅŅСиŅŅ ĐŊОвŅĐš ŅĐ°ĐšĐģ в ŅŅŅ ĐŋĐ°ĐŋĐēŅ",
+ "uploadButtonTitle": "ĐĐ°ĐŗŅŅСиŅŅ ĐŊОвŅĐš ŅĐ°ĐšĐģ в ваŅ CryptDrive",
"saveTemplateButton": "ĐĄĐžŅ
ŅĐ°ĐŊиŅŅ ĐēĐ°Đē ОйŅаСĐĩŅ",
"saveTemplatePrompt": "ĐŅĐąŅĐ°ŅŅ ĐŊаСваĐŊиĐĩ Đ´ĐģŅ ОйŅаСŅĐ°",
"templateSaved": "ĐĐąŅаСĐĩŅ ŅĐžŅ
ŅĐ°ĐŊĐĩĐŊ!",
@@ -120,7 +121,7 @@
"filePicker_description": "ĐŅĐąĐĩŅиŅĐĩ ŅĐ°ĐšĐģ иС ваŅĐĩĐŗĐž CryptDrive ŅŅОйŅ вŅŅавиŅŅ ĐĩĐŗĐž иĐģи вŅĐąĐĩŅиŅĐĩ ĐŊОвŅĐš",
"filePicker_filter": "ФиĐģŅŅОваŅŅ ŅĐ°ĐšĐģŅ ĐŋĐž иĐŧĐĩĐŊĐ°Đŧ",
"tags_title": "ĐĸĐĩĐŗи (ŅĐžĐģŅĐēĐž Đ´ĐģŅ ваŅ)",
- "tags_add": "ĐĐąĐŊОвиŅŅ ŅĐĩĐŗи ŅŅŅĐ°ĐŊиŅŅ",
+ "tags_add": "ĐĐąĐŊОвиŅŅ ŅĐĩĐŗи вŅĐąŅĐ°ĐŊĐŊŅŅ
Đ´ĐžĐēŅĐŧĐĩĐŊŅОв",
"tags_notShared": "ĐĐ°Ņи ŅĐĩĐŗи ĐŊĐĩ ŅаСдĐĩĐģŅŅŅŅŅ Ņ Đ´ŅŅĐŗиĐŧи ĐŋĐžĐģŅСОваŅĐĩĐģŅĐŧи",
"button_newsheet": "ĐОвŅĐš ĐиŅŅ",
"newButtonTitle": "ŅОСдаŅŅ ĐŊОвŅŅ СаĐŋиŅŅ",
diff --git a/www/convert/inner.js b/www/convert/inner.js
index 08ac8a7fc..6c9c676f4 100644
--- a/www/convert/inner.js
+++ b/www/convert/inner.js
@@ -85,8 +85,8 @@ define([
},
};
- Messages.convertPage = "Convert"; // XXX 4.10.0
- Messages.convert_hint = "Pick the file you want to convert. The list of output format will be visible afterward."; // XXX 4.10.0
+ Messages.convertPage = "Convert"; // XXX 4.11.0
+ Messages.convert_hint = "Pick the file you want to convert. The list of output format will be visible afterward."; // XXX 4.11.0
var createToolbar = function () {
var displayed = ['useradmin', 'newpad', 'limit', 'pageTitle', 'notifications'];
diff --git a/www/file/inner.js b/www/file/inner.js
index d69420f7b..2be2759db 100644
--- a/www/file/inner.js
+++ b/www/file/inner.js
@@ -62,7 +62,6 @@ define([
}
var configTb = {
displayed: displayed,
- //hideDisplayName: true,
$container: $bar,
metadataMgr: metadataMgr,
sfCommon: common,
diff --git a/www/form/app-form.less b/www/form/app-form.less
index a38867d34..7a8e1ece1 100644
--- a/www/form/app-form.less
+++ b/www/form/app-form.less
@@ -10,12 +10,88 @@
@bg-color: @colortheme_apps[form]
);
+ @cp_form_bar_color: fade(@cryptpad_color_link, 75%); // Color for the response chart bars
+
display: flex;
flex-flow: column;
font: @colortheme_app-font;
color: @cryptpad_text_col;
background-color: @cp_app-bg;
+ .alert {
+ font-size: 1rem;
+ &.alert-info {
+ color: @cryptpad_text_col !important;
+ }
+ }
+
+ @palette0: @cp_kanban-color0; // Default bg color for header
+ @form-colors: @cp_form-palette;
+ .form-colors(@form-colors; @index) when (@index > 0){
+ .form-colors(@form-colors; (@index - 1));
+ @color: extract(@form-colors, @index);
+ .cp-form-palette-color@{index}{
+ &.cp-form-palette {
+ background-color: @color !important;
+ }
+ }
+ &.cp-form-palette-color@{index}{
+ #cp-app-form-editor {
+ background-color: fade(@color, 50%);
+ }
+ }
+ }
+ .form-colors(@form-colors; length(@form-colors));
+
+ @form-colors2: @cp_form-palette2;
+ .checkmark-colors(@form-colors2; @index) when (@index > 0){
+ .checkmark-colors(@form-colors2; (@index - 1));
+ @color: extract(@form-colors2, @index);
+ &.cp-form-palette-color@{index}{
+ .cp-form-block {
+ .cp-radio input:checked ~ .cp-radio-mark, .cp-checkmark input:checked ~ .cp-checkmark-mark {
+ background-color: @color !important;
+ border-color: @color !important;
+ }
+ input, textarea {
+ border-color: @color !important;
+ }
+ }
+ .cp-form-block-question-text, .cp-form-block-question-number {
+ color: @color !important;
+ }
+ .cp-form-type-sort:hover {
+ color: @color !important;
+ .cp-form-sort-order {
+ border-color: @color !important;
+ }
+ }
+ .cp-form-input-block {
+ input { color: @color !important; }
+ border-bottom-color: @color !important;
+ }
+ }
+ }
+ .checkmark-colors(@form-colors2; length(@form-colors2));
+
+ .cp-form-palette {
+ &.cp-form-palette-nocolor {
+ background-color: @palette0 !important;
+ }
+ }
+ &.cp-form-palette-nocolor {
+ background-color: @cp_app-bg !important;
+ }
+
+ div.alert.cp-burn-after-reading {
+ margin: 10px !important;
+ }
+
+ & > .flatpickr-calendar {
+ animation: none !important;
+ -webkit-animation: none !important;
+ }
+
#cp-app-form-editor {
flex: 1;
display: flex;
@@ -54,7 +130,7 @@
.cp-form-block {
cursor: default !important;
.cp-form-block-drag-handle {
- display: none !important;
+ visibility: hidden;
}
}
}
@@ -74,49 +150,30 @@
height: 200px;
}
-/*
- table.cp-chart-table {
-
- --color: @colortheme_apps[pad];
- margin-top: 2em;
- margin-right: auto;
- min-width: 400px;
- padding-bottom: 2rem;
- width: min-content;
-
- tr {
- min-height: 200px;
- min-width: max-content;
- position: relative;
- }
-
- td {
- margin: 1px;
- min-width: 20px;
- max-width: 30px;
- border: 1px solid @cryptpad_color_brand_fadest;
- }
-
- th {
- position: absolute;
- bottom: -1.5rem;
- left: 50%;
- transform: translateX(-50%);
- }
-
- tr:not(:first-of-type):not(:last-of-type):not(:nth-of-type(5n+1)) {
- th {
- visibility: hidden;
- }
- }
- .cp-bar:not(:hover) {
- color: transparent;
- }
+ .cp-form-input-block {
+ display: flex;
}
-*/
- .cp-form-input-block {
+ .cp-form-view-title {
+ margin-bottom: 20px;
+ }
+ div.cp-form-view-footer {
display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 20px 20px 150px 20px;
+ div.cp-form-view-logo {
+ padding: 10px;
+ font-size: 40px;
+ font-family: "IBM Plex Mono";
+ .tools_unselectable();
+ color: @cryptpad_color_grey_500;
+ cursor: pointer;
+ img {
+ max-height: 60px;
+ margin: 0px 20px;
+ }
+ }
}
div.cp-form-creator-container {
@@ -134,20 +191,72 @@
width: 100% !important;
.cp-form-creator-settings {
display: flex;
- justify-content: space-evenly;
+ justify-content: space-between;
flex-wrap: wrap;
+ & > div {
+ flex-basis: 33.333333%;
+ padding-right: 20px;
+ }
+ }
+ }
+ }
+ @media screen and (max-width: 600px) and (min-width: 400px) {
+ .cp-form-creator-settings {
+ & > div {
+ flex-basis: 50% !important;
+ }
+ }
+ }
+ @media screen and (max-width: 400px) {
+ .cp-form-creator-settings {
+ & > div {
+ flex-basis: 100% !important;
}
}
}
.cp-form-creator-settings {
- padding: 30px;
.cp-form-actions {
margin-top: 5px;
}
& > div:not(:last-child) {
margin-bottom: 20px;
}
+ .cp-forms-results-participant {
+ display: flex;
+ flex-flow: column;
+ button {
+ margin-bottom: 20px;
+ }
+ }
+
+ .cp-form-color-container {
+ & > div {
+ display: flex;
+ justify-content: space-between;
+ margin-top: 5px;
+ &:last-child {
+ justify-content: space-evenly;
+ }
+ .cp-form-palette {
+ display: inline-block;
+ border-radius: 50%;
+ height: 30px;
+ width: 30px;
+ text-align: center;
+ line-height: 30px;
+ color: @cp_kanban-fg;
+ border: 1px solid fade(@cp_kanban-fg, 40%);
+ cursor: pointer;
+ }
+ }
+ }
+
+ .cp-form-response-msg-container button {
+ white-space: initial;
+ line-height: 25px;
+ padding: 5.5px 6px;
+ }
}
div.cp-form-filler-container {
width: 300px;
@@ -156,6 +265,7 @@
}
div.cp-form-creator-control {
padding: 10px;
+ margin-top: 10px;
display: flex;
flex-flow: column;
width: 300px;
@@ -165,6 +275,74 @@
flex-flow: column;
}
}
+ div.cp-form-creator-content {
+ .cp-form-block-type {
+ margin-top: -35px;
+ &.editable {
+ cursor: pointer;
+ }
+ .fa-caret-down {
+ margin-left: 5px;
+ }
+ }
+
+
+ .cp-form-conditional {
+ .cp-form-conditional-hint {
+ margin-bottom: 10px;
+ }
+ .cp-form-condition {
+ display: flex;
+ align-items: center;
+ margin-bottom: 10px;
+ flex-wrap: wrap;
+ & > * {
+ margin-right: 10px;
+ }
+ .cp-dropdown-container button {
+ max-width: 200px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+ }
+ .cp-form-condition-rule {
+ padding-bottom: 20px;
+ margin-bottom: 20px;
+ border-bottom: 1px solid @cryptpad_text_col;
+ }
+ }
+
+ div.cp-form-section-sortable {
+ min-height: 300px;
+ border: 2px dashed @cryptpad_text_col;
+ padding: 20px;
+ margin-top: 20px;
+ background: @cp_app-bg;
+ .cp-form-creator-add-inline {
+ button[data-type="section"] {
+ display: none;
+ }
+ }
+ }
+ }
+ div.cp-form-creator-results {
+ .cp-form-block {
+ .cp-form-block-content {
+ overflow-x: auto;
+ }
+ }
+ .cp-form-creator-results-timeline {
+ margin-bottom: 20px;
+ table.cp-charts.column {
+ overflow-x: initial;
+ td {
+ background-color: @cp_form_bar_color;
+ border-color: @cp_form_bar_color;
+ }
+ }
+ }
+ }
div.cp-form-creator-content, div.cp-form-creator-results {
max-width: 1000px;
min-width: 300px;
@@ -283,6 +461,7 @@
color: @cp_form-invalid;
ul {
list-style-type: disclosure-closed;
+ margin-bottom: 5px;
}
li {
text-align: left;
@@ -290,6 +469,10 @@
color: @cryptpad_color_link;
}
}
+ .alert-danger {
+ font-size: 1rem;
+ padding: 10px;
+ }
}
.cp-form-anon-answer {
text-align: center;
@@ -303,6 +486,10 @@
margin-left: 10px;
}
}
+ .cp-form-anon-answer-registered {
+ font-style: italic;
+ margin-left: 10px;
+ }
}
}
@@ -330,13 +517,27 @@
.cp-form-block {
background: @cp_form-bg1;
padding: 10px;
+ box-shadow: 0px 0px 15px @cp_shadow-color;
&:not(:last-child) {
margin-bottom: 20px;
}
+ .cp-form-disabled {
+ .cp-form-poll-choice, .cp-form-type-sort {
+ cursor: not-allowed !important;
+ }
+ }
+
+ .cp-form-preview {
+ color: @cp_sidebar-hint;
+ margin-bottom: 10px;
+ padding: 0;
+ }
+
.cp-form-block-drag-handle {
display: flex;
flex-flow: column;
+ height: 25px;
align-items: center;
color: @cp_sidebar-hint;
i {
@@ -359,18 +560,43 @@
.cp-form-block-question {
margin-bottom: 5px;
+ display: flex;
.cp-form-block-question-number {
font-weight: bold;
margin-right: 10px;
}
+ .cp-form-block-question-text {
+ flex: 1;
+ }
+ .cp-form-required-tag {
+ background: fade(@cryptpad_text_col, 15%);
+ padding: 5px;
+ margin-top: -10px;
+ margin-right: -10px;
+ &.cp-is-empty {
+ padding: 3px;
+ border: 2px solid @cryptpad_color_red;
+ color: @cp_form-invalid;
+ }
+ }
}
.cp-form-block-content {
- overflow-x: auto;
p {
a {
color: @cryptpad_color_link;
}
}
+ .cp-form-required-radio {
+ flex-direction: row;
+ display: flex;
+ margin-bottom: 20px;
+ span {
+ margin-right: 10px;
+ &.cp-radio-mark {
+ margin-right: 5px;
+ }
+ }
+ }
.cp-form-page-break-edit {
font-size: 20px;
text-align: center;
@@ -481,7 +707,12 @@
}
}
.cp-form-edit-block {
-
+ &.cp-no-sortable {
+ .cp-form-handle {
+ visibility: hidden;
+ cursor: default;
+ }
+ }
button.btn-secondary {
margin-left: 30px;
margin-bottom: 5px;
@@ -516,6 +747,22 @@
}
}
}
+ div.cp-form-creator-answered {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex: 1;
+ flex-flow: column;
+ .cp-form-submit-actions {
+ button:not(:last-child) {
+ margin-right: 10px;
+ }
+ }
+ .cp-form-view-logo {
+ margin-top: 100px;
+ padding-bottom: 20px;
+ }
+ }
div.cp-form-creator-results {
display: flex;
flex-flow: column;
@@ -528,11 +775,13 @@
p:last-child {
margin-bottom: 0;
}
+ * {
+ max-width: 100%;
+ }
}
.cp-form-creator-results-controls {
margin-bottom: 20px;
- margin-top: 20px;
//background: @cp_form-bg1;
//padding: 10px;
button {
@@ -543,21 +792,13 @@
.cp-form-creator-results-content {
padding-bottom: 100px;
.cp-form-block {
- background: @cp_form-bg1;
- padding: 10px;
+ background: @cp_form-bg1;
+ padding: 10px;
}
}
.cp-form-block-question {
margin-bottom: 5px;
}
- .cp-form-block-type {
- float: right;
- padding: 5px;
- margin-top: -10px;
- margin-right: -10px;
- i { margin-right: 5px; }
- background: fade(@cryptpad_text_col, 15%);
- }
.cp-form-results-type-text {
max-height: 300px;
overflow: auto;
@@ -573,26 +814,52 @@
background: @cp_form-bg2;
&:not(:last-child) { margin-bottom: 1px; }
}
- .cp-form-results-type-radio {
- display: table;
- .cp-form-results-type-multiradio-data {
- display: flex;
- flex-flow: column;
+
+ .cp-form-results-cell() {
+ border: 1px solid @cp_form-border;
+ display: table-cell;
+ padding: 5px 10px;
+ background: @cp_form-bg2;
+ }
+
+ .cp-form-results-type-multiradio-data {
+ .cp-mr-q {
+ font-weight: bold;
+ padding: 5px 10px;
+ .cp-form-results-cell();
+ background: transparent;
}
- .cp-form-results-type-radio-data {
- display: table-row;
- border: 1px solid @cp_form-border;
- & > span {
- border: 1px solid @cp_form-border;
- display: table-cell;
- padding: 5px 10px;
- background: @cp_form-bg2;
- &.cp-value {
- min-width: 200px;
+ &:not(:first-child) {
+ .cp-mr-q {
+ margin-top: 15px;
+ }
+ }
+ }
+
+ .cp-charts {
+ .cp-charts-row {
+ .cp-grid-sub-question {
+ background: transparent;
+ }
+ .cp-value {
+ min-width: 200px;
+ max-width: 200px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+ .cp-bar-container {
+ .cp-bar {
+ background-color: @cp_form_bar_color;
}
}
}
}
+
+ .cp-form-results-contained {
+ max-height: 350px; // enough for 10 table entries
+ overflow: auto;
+ }
.cp-form-individual {
background: @cp_form-bg1;
padding: 10px;
@@ -614,6 +881,14 @@
}
}
}
+ .cp-form-block-type {
+ float: right;
+ padding: 5px;
+ margin-top: -10px;
+ margin-right: -10px;
+ i { margin-right: 5px; }
+ background: fade(@cryptpad_text_col, 10%);
+ }
}
.cp-form-type-radio, .cp-form-type-checkbox {
@@ -844,6 +1119,11 @@
color: @cp_form-poll-yes-color;
}
}
+ .cp-form-response-modal {
+ .CodeMirror {
+ border: 1px solid @cp_forms-border;
+ }
+ }
.charts_main();
}
diff --git a/www/form/inner.js b/www/form/inner.js
index a54fc53c3..cb300facd 100644
--- a/www/form/inner.js
+++ b/www/form/inner.js
@@ -1,6 +1,7 @@
define([
'jquery',
'json.sortify',
+ '/api/config',
'/bower_components/chainpad-crypto/crypto.js',
'/common/sframe-app-framework.js',
'/common/toolbar.js',
@@ -18,12 +19,13 @@ define([
'/customize/application_config.js',
'/common/diffMarked.js',
'/common/sframe-common-codemirror.js',
+ '/common/text-cursor.js',
'cm/lib/codemirror',
+ '/bower_components/chainpad/chainpad.dist.js',
'/common/inner/share.js',
'/common/inner/access.js',
'/common/inner/properties.js',
- '/common/inner/charts.js',
'/lib/datepicker/flatpickr.js',
'/bower_components/sortablejs/Sortable.min.js',
@@ -38,12 +40,12 @@ define([
'css!/bower_components/codemirror/addon/dialog/dialog.css',
'css!/bower_components/codemirror/addon/fold/foldgutter.css',
'css!/lib/datepicker/flatpickr.min.css',
- //'css!/lib/chart/charts.min.css',
'css!/bower_components/components-font-awesome/css/font-awesome.min.css',
'less!/form/app-form.less',
], function (
$,
Sortify,
+ ApiConfig,
Crypto,
Framework,
Toolbar,
@@ -61,18 +63,25 @@ define([
AppConfig,
DiffMd,
SFCodeMirror,
+ TextCursor,
CMeditor,
- Share, Access, Properties, Charts,
+ ChainPad,
+ Share, Access, Properties,
Flatpickr,
Sortable
)
{
var APP = window.APP = {
+ blocks: {}
};
var is24h = UIElements.is24h();
var dateFormat = "Y-m-d H:i";
var timeFormat = "H:i";
+
+ var evCheckConditions = Util.mkEvent();
+ var evShowConditions = Util.mkEvent();
+
if (!is24h) {
dateFormat = "Y-m-d h:i K";
timeFormat = "h:i K";
@@ -84,28 +93,26 @@ define([
var MAX_OPTIONS = 15;
var MAX_ITEMS = 10;
- var saveAndCancelOptions = function (getRes, cb) {
- // Cancel changes
- var cancelBlock = h('button.btn.btn-secondary', Messages.cancel);
- $(cancelBlock).click(function () { cb(); });
-
- // Save changes
- var saveBlock = h('button.btn.btn-primary', [
- h('i.fa.fa-floppy-o'),
- h('span', Messages.settings_save)
- ]);
+ var getOptionValue = function (obj) {
+ if (!Util.isObject(obj)) { return obj; }
+ return obj.v;
+ };
+ var extractValues = function (values) {
+ if (!Array.isArray(values)) { return []; }
+ return values.map(getOptionValue);
+ };
- $(saveBlock).click(function () {
- $(saveBlock).attr('disabled', 'disabled');
- cb(getRes());
- });
+ var saveAndCancelOptions = function (cb) {
+ var cancelBlock = h('button.btn.btn-default.cp-form-preview-button',[
+ h('i.fa.fa-eye'),
+ Messages.form_preview_button
+ ]);
+ $(cancelBlock).click(function () { cb(undefined, true); });
- return h('div.cp-form-edit-save', [cancelBlock, saveBlock]);
+ return cancelBlock;
};
- var editTextOptions = function (opts, setCursorGetter, cb, tmp) {
- if (tmp && tmp.content && Sortify(opts) === Sortify(tmp.old)) {
- opts = tmp.content;
- }
+ var editTextOptions = function (opts, setCursorGetter, cb) {
+ var evOnSave = Util.mkEvent();
var maxLength, getLengthVal;
if (opts.maxLength) {
@@ -128,8 +135,8 @@ define([
var $l = $(lengthInput).on('input', Util.throttle(function () {
$l.val(getLengthVal());
+ evOnSave.fire();
}, 500));
-
}
var type, typeSelect;
@@ -162,16 +169,11 @@ define([
h('span', Messages.form_textType),
typeSelect[0]
]);
+ typeSelect.onChange.reg(evOnSave.fire);
}
setCursorGetter(function ()Â {
- return {
- old: (tmp && tmp.old) || opts,
- content: {
- maxLength: getLengthVal ? getLengthVal() : undefined,
- type: typeSelect ? typeSelect.getValue() : undefined
- }
- };
+ return {};
});
var getSaveRes = function () {
@@ -180,7 +182,14 @@ define([
type: typeSelect ? typeSelect.getValue() : undefined
};
};
- var saveAndCancel = saveAndCancelOptions(getSaveRes, cb);
+
+ evOnSave.reg(function () {
+ var res = getSaveRes();
+ if (!res) { return; }
+ cb(res);
+ });
+
+ var saveAndCancel = saveAndCancelOptions(cb);
return [
maxLength,
@@ -188,7 +197,9 @@ define([
saveAndCancel
];
};
- var editOptions = function (v, setCursorGetter, cb, tmp) {
+ var editOptions = function (v, isDefaultOpts, setCursorGetter, cb, tmp) {
+ var evOnSave = Util.mkEvent();
+
var add = h('button.btn.btn-secondary', [
h('i.fa.fa-plus'),
h('span', Messages.form_add_option)
@@ -199,11 +210,11 @@ define([
]);
var cursor;
- if (tmp && tmp.content && Sortify(v) === Sortify(tmp.old)) {
- v = tmp.content;
+ if (tmp && tmp.cursor)Â {
cursor = tmp.cursor;
}
+ // Checkbox: max options
var maxOptions, maxInput;
if (typeof(v.max) === "number") {
maxInput = h('input', {
@@ -216,8 +227,12 @@ define([
h('span', Messages.form_editMax),
maxInput
]);
+ $(maxInput).on('input', function () {
+ setTimeout(evOnSave.fire);
+ });
}
+ // Poll: type (text/day/time)
var type, typeSelect;
if (v.type) {
// Messages.form_poll_text.form_poll_day.form_poll_time
@@ -253,9 +268,18 @@ define([
// Show existing options
var $add, $addItem;
var addMultiple;
- var getOption = function (val, isItem, uid) {
+ var getOption = function (val, placeholder, isItem, uid) {
var input = h('input', {value:val});
- if (uid) { $(input).data('uid', uid); }
+ var $input = $(input);
+ if (placeholder) {
+ input.placeholder = val;
+ input.value = '';
+ $input.on('keypress', function () {
+ $input.removeAttr('placeholder');
+ $input.off('keypress');
+ });
+ }
+ if (uid) { $input.data('uid', uid); }
// If the input is a date, initialize flatpickr
if (v.type && v.type !== 'text') {
@@ -276,14 +300,19 @@ define([
// if this element was active before the remote change, restore cursor
var setCursor = function () {
if (v.type && v.type !== 'text') { return; }
+ try {
+ var ops = ChainPad.Diff.diff(cursor.el, val);
+ ['start', 'end'].forEach(function (attr) {
+ cursor[attr]Â = TextCursor.transformCursor(cursor[attr], ops);
+ });
+ } catch (e) { console.error(e); }
input.selectionStart = cursor.start || 0;
input.selectionEnd = cursor.end || 0;
setTimeout(function () { input.focus(); });
};
- if (isItem) {
- if (cursor && cursor.uid === uid && cursor.item) { setCursor(); }
- } else {
- if (cursor && cursor.el === val && !cursor.item) { setCursor(); }
+
+ if (cursor && cursor.uid === uid && Boolean(cursor.item) === Boolean(isItem)) {
+ setCursor();
}
var del = h('button.btn.btn-danger-outline', h('i.fa.fa-times'));
@@ -312,26 +341,64 @@ define([
var currentMax = Number($maxInput.val());
$maxInput.val(Math.min(inputs, currentMax));
}
+
+ evOnSave.fire();
});
+
+ if (!v.type || v.type === "text") {
+ $input.keyup(function (e) {
+ try {
+ if (e.which === 13) {
+ var $line = $input.closest('.cp-form-edit-block-input');
+ if ($input.closest('.cp-form-edit-block')
+ .find('.cp-form-edit-block-input').last()[0] === $line[0]) {
+ // If we're the last input, add a new one
+ if (isItem && $addItem && $addItem.is(':visible')) {
+ $addItem.click();
+ }
+ if (!isItem && $add && $add.is(':visible')) { $add.click(); }
+ } else {
+ // Otherwise focus the next one
+ $line.next().find('input').focus();
+ }
+ }
+ if (e.which === 27 && !$(input).val()) {
+ $(del).click();
+ }
+ } catch (err)Â { console.error(err); }
+ });
+ }
+
+ $(input).on('input', function () {
+ evOnSave.fire();
+ });
+
return el;
};
- var inputs = v.values.map(function (val) { return getOption(val, false); });
+ var inputs = v.values.map(function (data) {
+ return getOption(data.v, isDefaultOpts, false, data.uid);
+ });
inputs.push(add);
var container = h('div.cp-form-edit-block', inputs);
var $container = $(container);
- Sortable.create(container, {
+ var sortableOption = Sortable.create(container, {
direction: "vertical",
handle: ".cp-form-handle",
draggable: ".cp-form-edit-block-input",
forceFallback: true,
+ store: {
+ set: function () {
+ evOnSave.fire();
+ }
+ }
});
var containerItems;
if (v.items)Â {
var inputsItems = v.items.map(function (itemData) {
- return getOption(itemData.v, true, itemData.uid);
+ return getOption(itemData.v, isDefaultOpts, true, itemData.uid);
});
inputsItems.push(addItem);
containerItems = h('div.cp-form-edit-block', inputsItems);
@@ -340,15 +407,21 @@ define([
handle: ".cp-form-handle",
draggable: ".cp-form-edit-block-input",
forceFallback: true,
+ store: {
+ set: function () {
+ evOnSave.fire();
+ }
+ }
});
}
// Calendar...
var calendarView;
- if (v.type) {
+ if (v.type) { // Polls
+ // Calendar inline for "day" type
var calendarInput = h('input');
calendarView = h('div', calendarInput);
- var calendarDefault = v.type === "day" ? v.values.map(function (time) {
+ var calendarDefault = v.type === "day" ? extractValues(v.values).map(function (time) {
if (!time) { return; }
var d = new Date(time);
if (!isNaN(d)) { return d; }
@@ -357,12 +430,13 @@ define([
mode: 'multiple',
inline: true,
defaultDate: calendarDefault,
- appendTo: calendarView
+ appendTo: calendarView,
+ onChange: function ()Â {
+ evOnSave.fire();
+ }
});
- }
- // Calendar time
- if (v.type) {
+ // Calendar popup for "time"
var multipleInput = h('input', {placeholder: Messages.form_addMultipleHint});
var multipleClearButton = h('button.btn', Messages.form_clear);
var addMultipleButton = h('button.btn', [
@@ -384,7 +458,7 @@ define([
});
$(addMultipleButton).click(function () {
multiplePickr.selectedDates.some(function (date) {
- $add.before(getOption(date, false));
+ $add.before(getOption(date, false, false, Util.uid()));
var l = $container.find('input').length;
$(maxInput).attr('max', l);
if (l >= MAX_OPTIONS) {
@@ -394,12 +468,15 @@ define([
}
});
multiplePickr.clear();
+ evOnSave.fire();
});
}
var refreshView = function () {
if (!v.type) { return; }
var $calendar = $(calendarView);
+ sortableOption.option("disabled", v.type !== "text");
+ $container.toggleClass('cp-no-sortable', v.type !== "text");
if (v.type !== "day") {
$calendar.hide();
$container.show();
@@ -422,8 +499,20 @@ define([
typeSelect.onChange.reg(function (prettyVal, val) {
v.type = val;
refreshView();
+ setTimeout(evOnSave.fire);
if (val !== "text") {
$container.find('.cp-form-edit-block-input').remove();
+ if (val === "time") {
+ var time = new Date();
+ time.setHours(14);
+ time.setMinutes(0);
+ time.setSeconds(0);
+ time.setMilliseconds(0);
+ var el = getOption(+time, false, false, Util.uid());
+ $add.before(el);
+ $(el).find('input').focus();
+ return;
+ }
$(add).click();
return;
}
@@ -439,7 +528,9 @@ define([
// "Add option" button handler
$add = $(add).click(function () {
var txt = v.type ? '' : Messages.form_newOption;
- $add.before(getOption(txt, false));
+ var el = getOption(txt, true, false, Util.uid());
+ $add.before(el);
+ $(el).find('input').focus();
var l = $container.find('input').length;
$(maxInput).attr('max', l);
if (l >= MAX_OPTIONS) { $add.hide(); }
@@ -447,7 +538,9 @@ define([
// If multiline block, handle "Add item" button
$addItem = $(addItem).click(function () {
- $addItem.before(getOption(Messages.form_newItem, true, Util.uid()));
+ var el = getOption(Messages.form_newItem, true, true, Util.uid());
+ $addItem.before(el);
+ $(el).find('input').focus();
if ($(containerItems).find('input').length >= MAX_ITEMS) { $addItem.hide(); }
});
if ($container.find('input').length >= MAX_OPTIONS) { $add.hide(); }
@@ -455,52 +548,43 @@ define([
// Set cursor getter (to handle remote changes to the form)
setCursorGetter(function ()Â {
- var values = [];
var active = document.activeElement;
var cursor = {};
$container.find('input').each(function (i, el) {
+ var val = $(el).val() || el.placeholder || '';
if (el === active && !el._flatpickr) {
- cursor.el= $(el).val();
+ cursor.item = false;
+ cursor.uid= $(el).data('uid');
cursor.start = el.selectionStart;
cursor.end = el.selectionEnd;
+ cursor.el = val;
}
- values.push($(el).val());
});
- if (v.type === "day") {
- var dayPickr = $(calendarView).find('input')[0]._flatpickr;
- values = dayPickr.selectedDates.map(function (date) {
- return +date;
- });
- }
- var _content = {values: values};
-
- if (maxInput) {
- _content.max = Number($(maxInput).val()) || 1;
- }
-
- if (typeSelect) {
- _content.type = typeSelect.getValue();
- }
-
if (v.items) {
- var items = [];
$(containerItems).find('input').each(function (i, el) {
+ var val = $(el).val() || el.placeholder || '';
if (el === active) {
cursor.item = true;
cursor.uid= $(el).data('uid');
cursor.start = el.selectionStart;
cursor.end = el.selectionEnd;
+ cursor.el = val;
}
- items.push({
- uid: $(el).data('uid'),
- v: $(el).val()
- });
});
- _content.items = items;
+ }
+ if (v.type === "time") {
+ $container.find('input').each(function (i, el) {
+ var f = el._flatpickr;
+ if (!f || !f.isOpen) { return; }
+ var rect = el.getBoundingClientRect();
+ cursor = {
+ flatpickr: true,
+ val: +f.selectedDates[0],
+ y: rect && rect.y
+ };
+ });
}
return {
- old: (tmp && tmp.old) || v,
- content: _content,
cursor: cursor
};
});
@@ -508,7 +592,6 @@ define([
var getSaveRes = function () {
// Get values
var values = [];
- var duplicates = false;
if (v.type === "day") {
var dayPickr = $(calendarView).find('input')[0]._flatpickr;
values = dayPickr.selectedDates.map(function (date) {
@@ -516,45 +599,43 @@ define([
});
} else {
$container.find('input').each(function (i, el) {
- var val = $(el).val().trim();
+ var val = ($(el).val() || el.placeholder || '').trim();
if (v.type === "day" || v.type === "time") {
var f = el._flatpickr;
if (f && f.selectedDates && f.selectedDates.length) {
val = +f.selectedDates[0];
}
}
- if (val && values.indexOf(val) === -1) { values.push(val); }
- else { duplicates = true; }
+ var uid = $(el).data('uid');
+ var hasUid = values.some(function (i) { return i.uid === uid; });
+ if (hasUid) { uid = Util.uid(); }
+ values.push({
+ uid: uid,
+ v: val
+ });
+ if (hasUid) { $(el).data('uid', uid); }
});
}
- values = values.filter(Boolean); // Block empty or undeinfed options
- if (!values.length) {
- return void UI.warn(Messages.error);
- }
var res = { values: values };
// If multiline block, get items
if (v.items)Â {
var items = [];
$(containerItems).find('input').each(function (i, el) {
- var val = $(el).val().trim();
+ var val = ($(el).val() || el.placeholder || '').trim();
var uid = $(el).data('uid');
- if (!items.some(function (i) { return i.uid === uid; })) {
- items.push({
- uid: $(el).data('uid'),
- v: val
- });
- }
- else { duplicates = true; }
+ var hasUid = items.some(function (i) { return i.uid === uid; });
+ if (hasUid) { uid = Util.uid(); }
+ items.push({
+ uid: uid,
+ v: val
+ });
+ if (hasUid) { $(el).data('uid', uid); }
});
+ items = items.filter(Boolean);
res.items = items;
}
- // Show duplicates warning
- if (duplicates) {
- UI.warn(Messages.form_duplicates);
- }
-
// If checkboxes, get the maximum number of values the users can select
if (maxInput) {
var maxVal = Number($(maxInput).val());
@@ -569,7 +650,13 @@ define([
return res;
};
- var saveAndCancel = saveAndCancelOptions(getSaveRes, cb);
+ evOnSave.reg(function () {
+ var res = getSaveRes();
+ if (!res) { return; }
+ cb(res);
+ });
+
+ var saveAndCancel = saveAndCancelOptions(cb);
return [
type,
@@ -599,13 +686,15 @@ define([
var makePollTable = function (answers, opts, resultsPageObj) {
// Sort date values
if (opts.type !== "text") {
- opts.values.sort(function (a, b) {
+ opts.values.sort(function (_a, _b) {
+ var a = getOptionValue(_a);
+ var b = getOptionValue(_b);
return +new Date(a) - +new Date(b);
});
}
// Create first line with options
var allDays = getWeekDays(true);
- var els = opts.values.map(function (data) {
+ var els = extractValues(opts.values).map(function (data) {
var _date;
if (opts.type === "day") {
_date = new Date(data);
@@ -636,7 +725,7 @@ define([
if (opts.type === "time") {
var days = [h('div.cp-poll-cell')];
var _days = {};
- opts.values.forEach(function (d) {
+ extractValues(opts.values).forEach(function (d) {
var date = new Date(d);
var day = date.toLocaleDateString();
_days[day] = {
@@ -667,7 +756,7 @@ define([
var avatar = h('span.cp-avatar');
APP.common.displayAvatar($(avatar), Util.find(answerObj, ['user', 'avatar']), name);
var values = answer.values || {};
- var els = opts.values.map(function (data) {
+ var els = extractValues(opts.values).map(function (data) {
var res = values[data] || 0;
var v = (Number(res) === 1) ? h('i.fa.fa-check.cp-yes') : undefined;
var cell = h('div.cp-poll-cell.cp-form-poll-answer', {
@@ -705,7 +794,7 @@ define([
var myTotals = {};
var updateMyTotals = function () {
if (!myLine) { return; }
- opts.values.forEach(function (data) {
+ extractValues(opts.values).forEach(function (data) {
myLine.some(function (el) {
if ($(el).data('option') !== data) { return; }
var res = Number($(el).attr('data-value')) || 0;
@@ -728,7 +817,7 @@ define([
});
};
- var totalEls = opts.values.map(function (data) {
+ var totalEls = extractValues(opts.values).map(function (data) {
var y = 0; // Yes
var m = 0; // Maybe
answers.forEach(function (answerObj) {
@@ -805,10 +894,31 @@ define([
return total;
};
- var getEmpty = function (empty) { // XXX don't include this in the scrollable area
- if (empty) {
- return UI.setHTML(h('div.cp-form-results-type-text-empty'), Messages._getKey('form_notAnswered', [empty]));
- }
+ var multiAnswerSubHeading = function (content) {
+ return h('span.cp-charts-row', h('td.cp-charts-cell.cp-grid-sub-question', {
+ colspan: 3,
+ style: 'font-weight: bold;',
+ }, content));
+ };
+
+ var getEmpty = function (empty) {
+ if (!empty) { return; }
+ var msg = UI.setHTML(h('span.cp-form-results-empty-text'), Messages._getKey('form_notAnswered', [empty]));
+ return multiAnswerSubHeading(msg);
+ };
+
+ var barGraphic = function (itemScale) {
+ return h('span.cp-bar-container', h('div.cp-bar', {
+ style: 'width: ' + (itemScale * 100) + '%',
+ }, ' '));
+ };
+
+ var barRow = function (value, count, max, showBar) {
+ return h('div.cp-charts-row', [
+ h('span.cp-value', value),
+ h('span.cp-count', count),
+ showBar? barGraphic((count / max)): undefined,
+ ]);
};
var findItem = function (items, uid) {
@@ -823,6 +933,27 @@ define([
return res;
};
+ var getSections = function (content) {
+ var uids = Object.keys(content.form).filter(function (uid) {
+ return content.form[uid].type === 'section';
+ });
+ return uids;
+ };
+ var getFullOrder = function (content) {
+ var order = content.order.slice();
+ getSections(content).forEach(function (uid) {
+ var block = content.form[uid];
+ if (!block.opts || !Array.isArray(block.opts.questions)) { return; }
+ var idx = order.indexOf(uid);
+ if (idx === -1) { return; }
+ idx++;
+ block.opts.questions.forEach(function (el, i) {
+ order.splice(idx+i, 0, el);
+ });
+ });
+ return order;
+ };
+
var getBlockAnswers = function (answers, uid, filterCurve)Â {
if (!answers) { return; }
return Object.keys(answers || {}).map(function (user) {
@@ -837,6 +968,25 @@ define([
}).filter(Boolean);
};
+ // When there is a change to the form, we need to check if we can still add
+ // conditions to the different sections
+ evShowConditions.reg(function () {
+ (APP.formBlocks || []).forEach(function (block) {
+ if (!block || !block.updateState) { return; }
+ block.updateState();
+ });
+ });
+ // When a section contains a condition that is now invalid (the question has been moved
+ // or deleted locally), we need to redraw the list of conditions for this section
+ evCheckConditions.reg(function (_uid) {
+ (APP.formBlocks || []).some(function (block) {
+ if (block.uid && block.uid !== _uid) { return; }
+ if (!block || !block.updateState) { return; }
+ return block.updateState(true, _uid);
+ });
+ });
+
+
var STATIC_TYPES = {
md: {
defaultOpts: {
@@ -853,36 +1003,46 @@ define([
return {
tag: tag,
edit: function (cb, tmp) {
- var t = h('textarea');
- var block = h('div.cp-form-edit-options-block', [t]);
- var cm = SFCodeMirror.create("gfm", CMeditor, t);
- var editor = cm.editor;
- editor.setOption('lineNumbers', true);
- editor.setOption('lineWrapping', true);
- editor.setOption('styleActiveLine', true);
- editor.setOption('readOnly', false);
+ // Cancel changes
+ var cancelBlock = saveAndCancelOptions(cb);
var text = opts.text;
var cursor;
- if (tmp && tmp.content && tmp.old.text === text) {
- text = tmp.content.text;
+ if (tmp && tmp.cursor) {
cursor = tmp.cursor;
}
+ var block, editor;
+ if (tmp && tmp.block) {
+ block = tmp.block;
+ editor = tmp.editor;
+ }
+
+ var cm;
+ if (!block || !editor) {
+ var t = h('textarea');
+ block = h('div.cp-form-edit-options-block', [t]);
+ cm = SFCodeMirror.create("gfm", CMeditor, t);
+ editor = cm.editor;
+ editor.setOption('lineNumbers', true);
+ editor.setOption('lineWrapping', true);
+ editor.setOption('styleActiveLine', true);
+ editor.setOption('readOnly', false);
+ }
+
setTimeout(function () {
- editor.setValue(text);
- if (cursor) {
- if (Sortify(cursor.start) === Sortify(cursor.end)) {
- editor.setCursor(cursor.start);
- } else {
- editor.setSelection(cursor.start, cursor.end);
- }
+ editor.focus();
+ if (!(tmp && tmp.editor)) {
+ editor.setValue(text);
+ } else {
+ SFCodeMirror.setValueAndCursor(editor, editor.getValue(), text);
}
editor.refresh();
editor.save();
editor.focus();
});
- if (APP.common) {
+
+ if (APP.common && !(tmp && tmp.block) && cm) {
var markdownTb = APP.common.createMarkdownToolbar(editor, {
embed: function (mt) {
editor.focus();
@@ -893,26 +1053,20 @@ define([
$(markdownTb.toolbar).show();
cm.configureTheme(APP.common, function () {});
}
- // Cancel changes
- var cancelBlock = h('button.btn.btn-secondary', Messages.cancel);
- $(cancelBlock).click(function () {
- cb();
- });
- // Save changes
- var saveBlock = h('button.btn.btn-primary', [
- h('i.fa.fa-floppy-o'),
- h('span', Messages.settings_save)
- ]);
var getContent = function () {
return {
text: editor.getValue()
};
};
- $(saveBlock).click(function () {
- $(saveBlock).attr('disabled', 'disabled');
+
+ if (tmp && tmp.onChange) {
+ editor.off('change', tmp.onChange);
+ }
+ var on = function () {
cb(getContent());
- });
+ };
+ editor.on('change', on);
cursorGetter = function () {
if (document.activeElement && block.contains(document.activeElement)) {
@@ -922,15 +1076,16 @@ define([
};
}
return {
- old: opts,
- content: getContent(),
- cursor: cursor
+ cursor: cursor,
+ block: block,
+ editor: editor,
+ onChange: on
};
};
return [
block,
- h('div.cp-form-edit-save', [cancelBlock, saveBlock])
+ cancelBlock
];
},
getCursor: function () { return cursorGetter(); },
@@ -953,51 +1108,483 @@ define([
printResults: function () { return; },
icon: h('i.cptools.cptools-form-page-break')
},
+ section: {
+ defaultOpts: {
+ questions: []
+ },
+ get: function (opts, a, n, ev, data) {
+ var sortable = h('div.cp-form-section-sortable');
+ var tag = h('div.cp-form-section-edit', [
+ sortable
+ ]);
+ if (!APP.isEditor) {
+ return {
+ tag: tag,
+ noViewMode: true
+ };
+ }
+
+ var block = data.block;
+ if (!opts) { opts = block.opts = STATIC_TYPES.section.defaultOpts; }
+ var content = data.content;
+ var uid = data.uid;
+ var form = content.form;
+ var framework = APP.framework;
+ var tmp = data.tmp;
+
+ var getConditionsValues = function () {
+ var order = getFullOrder(content);
+ var blockIdx = order.indexOf(uid);
+ var blocks = order.slice(0, blockIdx); // Get all previous questions
+ var values = blocks.map(function(uid) {
+ var block = form[uid];
+ var type = block.type;
+ if (['radio', 'checkbox'].indexOf(type) === -1) { return; }
+ var obj = {
+ uid: uid,
+ type: type,
+ q: block.q || Messages.form_default
+ };
+ var val;
+ if (type === 'radio') {
+ val = block.opts ? block.opts.values
+ : APP.TYPES.radio.defaultOpts.values;
+ }
+ if (type === 'checkbox') {
+ val = block.opts ? block.opts.values
+ : APP.TYPES.checkbox.defaultOpts.values;
+ }
+ obj.values = extractValues(val);
+ return obj;
+ }).filter(Boolean);
+ return values;
+ };
+ var addCondition = h('button.btn.btn-secondary', [
+ h('i.fa.fa-plus'),
+ h('span', Messages.form_conditional_add)
+ ]);
+ var $addC = $(addCondition);
+ var getConditions;
+ var getAddAndButton = function ($container, rules) {
+ var btn = h('button.btn.btn-secondary.cp-form-add-and', [
+ h('i.fa.fa-plus'),
+ h('span', Messages.form_conditional_addAnd)
+ ]);
+ var $b = $(btn).click(function () {
+ getConditions($container, true, rules, undefined, $b);
+ });
+ $container.append(btn);
+ return $b;
+ };
+ var values = getConditionsValues();
+ getConditions = function ($container, isNew, rules, condition, $btn) {
+ condition = condition || {};
+ condition.uid = condition.uid || Util.uid();
+
+ var content = h('div.cp-form-condition', {
+ 'data-uid': condition.uid,
+ });
+ var $content = $(content);
+
+ var qSelect, iSelect, vSelect;
+ var onChange = function (resetV) {
+ var w = block.opts.when = block.opts.when || [];
+
+ if (qSelect) { condition.q = qSelect.getValue(); }
+ if (iSelect) { condition.is = Number(iSelect.getValue()); }
+ if (resetV) { delete condition.v; }
+ else if (vSelect) { condition.v = vSelect.getValue(); }
+
+ if (isNew) {
+ if (!Array.isArray(rules)) { // new set of rules (OR)
+ rules = [condition];
+ w.push(rules);
+ $btn = getAddAndButton($container, rules);
+ } else {
+ rules.push(condition);
+ }
+ isNew = false;
+ }
+
+ framework.localChange();
+ };
+
+ onChange();
+
+ var qOptions = values.map(function (obj) {
+ return {
+ tag: 'a',
+ attributes: {
+ 'class': 'cp-form-condition-question',
+ 'data-value': obj.uid,
+ 'href': '#',
+ },
+ content: obj.q
+ };
+ });
+ var qConfig = {
+ text: Messages.form_condition_q, // Button initial text
+ options: qOptions, // Entries displayed in the menu
+ isSelect: true,
+ caretDown: true,
+ buttonCls: 'btn btn-secondary'
+ };
+ qSelect = UIElements.createDropdown(qConfig);
+ qSelect[0].dropdown = qSelect;
+ $(qSelect).attr('data-drop', 'q');
+
+ var isOn = !condition || condition.is !== 0;
+ var iOptions = [{
+ tag: 'a',
+ attributes: {
+ 'data-value': 1,
+ 'href': '#',
+ },
+ content: Messages.form_condition_is
+ }, {
+ tag: 'a',
+ attributes: {
+ 'data-value': 0,
+ 'href': '#',
+ },
+ content: Messages.form_condition_isnot
+ }];
+ var iConfig = {
+ options: iOptions, // Entries displayed in the menu
+ isSelect: true,
+ caretDown: true,
+ buttonCls: 'btn btn-default'
+ };
+ iSelect = UIElements.createDropdown(iConfig);
+ iSelect[0].dropdown = iSelect;
+ iSelect.setValue(isOn ? 1 : 0, undefined, true);
+ $(iSelect).attr('data-drop', 'i').hide();
+ iSelect.onChange.reg(function () { onChange(); });
+
+ var remove = h('button.btn.btn-danger-alt.cp-condition-remove', [
+ h('i.fa.fa-times.nomargin')
+ ]);
+ $(remove).on('click', function () {
+ var w = block.opts.when = block.opts.when || [];
+ var deleteRule = false;
+ if (rules.length === 1) {
+ var rIdx = w.indexOf(rules);
+ w.splice(rIdx, 1);
+ deleteRule = true;
+ } else {
+ var idx = rules.indexOf(condition);
+ rules.splice(idx, 1);
+ }
+ framework.localChange();
+ framework._.cpNfInner.chainpad.onSettle(function () {
+ if (deleteRule) {
+ $content.closest('.cp-form-condition-rule').remove();
+ return;
+ }
+ $content.remove();
+ });
+ });
+
+ $content.append(qSelect).append(iSelect).append(remove);
+ if ($container.find('button.cp-form-add-and').length) {
+ $container.find('button.cp-form-add-and').before($content);
+ } else {
+ $container.append($content);
+ }
+
+ qSelect.onChange.reg(function (prettyVal, val, init) {
+ qSelect.find('button').removeClass('btn-secondary')
+ .addClass('btn-default');
+ onChange(!init);
+ $(iSelect).show();
+ var res, type;
+ values.some(function (obj) {
+ if (String(obj.uid) === String(val)) {
+ res = obj.values;
+ type = obj.type;
+ return true;
+ }
+ });
+
+ var $selDiv = $(iSelect);
+ if (type === 'checkbox') {
+ $selDiv.find('[data-value="0"]').text(Messages.form_condition_hasnot);
+ $selDiv.find('[data-value="1"]').text(Messages.form_condition_has);
+ } else {
+ $selDiv.find('[data-value="0"]').text(Messages.form_condition_isnot);
+ $selDiv.find('[data-value="1"]').text(Messages.form_condition_is);
+ }
+ iSelect.setValue(iSelect.getValue(), undefined, true);
+
+ $content.find('.cp-form-condition-values').remove();
+ if (!res) { return; }
+ var vOptions = res.map(function (str) {
+ return {
+ tag: 'a',
+ attributes: {
+ 'class': 'cp-form-condition-value',
+ 'data-value': str,
+ 'href': '#',
+ },
+ content: str
+ };
+ });
+ var vConfig = {
+ text: Messages.form_condition_v, // Button initial text
+ options: vOptions, // Entries displayed in the menu
+ //left: true, // Open to the left of the button
+ //container: $(type),
+ isSelect: true,
+ caretDown: true,
+ buttonCls: 'btn btn-secondary'
+ };
+ vSelect = UIElements.createDropdown(vConfig);
+ vSelect[0].dropdown = vSelect;
+ vSelect.addClass('cp-form-condition-values').attr('data-drop', 'v');
+ $content.append(vSelect).append(remove);
+
+ vSelect.onChange.reg(function () {
+ vSelect.find('button').removeClass('btn-secondary')
+ .addClass('btn-default');
+ $(remove).off('click').click(function () {
+ var w = block.opts.when = block.opts.when || [];
+ var deleteRule = false;
+ if (rules.length === 1) {
+ var rIdx = w.indexOf(rules);
+ w.splice(rIdx, 1);
+ deleteRule = true;
+ } else {
+ var idx = rules.indexOf(condition);
+ rules.splice(idx, 1);
+ }
+ framework.localChange();
+ framework._.cpNfInner.chainpad.onSettle(function () {
+ if (deleteRule) {
+ $content.closest('.cp-form-condition-rule').remove();
+ return;
+ }
+ $content.remove();
+ });
+ }).appendTo($content);
+ onChange();
+ });
+
+ if (condition && condition.v && init) {
+ vSelect.setValue(condition.v, undefined, true);
+ vSelect.onChange.fire(condition.v, condition.v);
+ }
+
+ if (!tmp || tmp.uid !== condition.uid) { return; }
+ if (tmp.type === 'v') {
+ vSelect.click();
+ }
+ });
+ if (condition && condition.q) {
+ qSelect.setValue(condition.q, undefined, true);
+ qSelect.onChange.fire(condition.q, condition.q, true);
+ }
+
+ if (!tmp || tmp.uid !== condition.uid) { return; }
+
+ if (tmp.type === 'q') { qSelect.click(); }
+ else if (tmp.type === 'i') { iSelect.click(); }
+ };
+
+ var conditionalDiv = h('div.cp-form-conditional', [
+ h('div.cp-form-conditional-hint', Messages.form_conditional),
+ addCondition
+ ]);
+ var $condition = $(conditionalDiv).prependTo(tag);
+ var redraw = function () {
+ var w = block.opts.when = block.opts.when || [];
+ w.forEach(function (rules) {
+ var rulesC = h('div.cp-form-condition-rule');
+ var $rulesC = $(rulesC);
+ var $b = getAddAndButton($rulesC, rules);
+ rules.forEach(function (obj) {
+ getConditions($rulesC, false, rules, obj, $b);
+ });
+ $addC.before($rulesC);
+ });
+ };
+ redraw();
+
+ var hintDiv = h('div.cp-form-conditional-hint', [
+ h('div.cp-form-conditional-hint', Messages.form_condition_hint)
+ ]);
+ var $hint = $(hintDiv).prependTo(tag);
+
+ $addC.click(function () {
+ var rulesC = h('div.cp-form-condition-rule');
+ var $rulesC = $(rulesC);
+ getConditions($rulesC, true);
+ $addC.before($rulesC);
+ });
+
+ var cursorGetter = function () {
+ var $activeDrop = $condition.find('.cp-dropdown-content:visible').first();
+ if (!$activeDrop.length) { return; }
+ var uid = $activeDrop.closest('.cp-form-condition').attr('data-uid');
+ var type = $activeDrop.closest('.cp-dropdown-container').attr('data-drop');
+ var $btn = $activeDrop.closest('.cp-dropdown-container').find('button');
+ var y = $btn && $btn.length && $btn[0].getBoundingClientRect().y;
+ return {
+ uid: uid,
+ type: type,
+ y: y
+ };
+ };
+
+ Sortable.create(sortable, {
+ group: {
+ name: 'nested',
+ put: function (to, from, el) {
+ // Make sure sections dan't be dropped into other sections
+ return $(el).attr('data-type') !== 'section';
+ }
+ },
+ direction: "vertical",
+ filter: "input, button, .CodeMirror, .cp-form-type-sort, .cp-form-block-type.editable",
+ preventOnFilter: false,
+ draggable: ".cp-form-block",
+ //forceFallback: true,
+ fallbackTolerance: 5,
+ onStart: function () {
+ var $container = $('div.cp-form-creator-content');
+ $container.find('.cp-form-creator-add-inline').remove();
+ },
+ store: {
+ set: function (s) {
+ opts.questions = s.toArray();
+ setTimeout(APP.framework.localChange);
+ if (APP.updateAddInline) { APP.updateAddInline(); }
+ }
+ }
+ });
+
+ // If "needRedraw" is false, we only want to know if we can add conditions and
+ // if we can't, make sure we delete incomplete conditions before hiding the button
+ // If "needRedraw" is true, it means we ant to redraw a section because some
+ // conditions are invalid
+ var updateState = function (needRedraw, _uid) {
+ if (needRedraw && uid !== _uid) { return; }
+
+ values = getConditionsValues();
+ var available = values.length;
+ if (available) {
+ $condition.show();
+ $hint.hide();
+ } else {
+ $condition.hide();
+ $hint.show();
+ }
+
+ if (needRedraw) {
+ $condition.find('.cp-form-condition-rule').remove();
+ redraw();
+ return true;
+ } else {
+ if (available) {
+ // Questions may have moved. We need to redraw our dropdowns
+ // to make sure we use the correct list
+ $condition.find('.cp-form-condition').each(function (i, el) {
+ // Update question dropdown
+ var $q = $(el).find('.cp-dropdown-container[data-drop="q"]');
+ var drop = $q[0] && $q[0].dropdown;
+ if (!drop) { return; }
+ var qOptions = values.map(function (obj) {
+ return {
+ tag: 'a',
+ attributes: {
+ 'class': 'cp-form-condition-question',
+ 'data-value': obj.uid,
+ 'href': '#',
+ },
+ content: obj.q
+ };
+ });
+ var val = drop.getValue();
+ drop.setOptions(qOptions);
+ drop.setValue(val);
+
+ // Update values dropdown
+ var $v = $(el).find('.cp-dropdown-container[data-drop="v"]');
+ if (!$v.length) { return; }
+ var dropV = $v[0] && $v[0].dropdown;
+ if (!dropV) { return; }
+ var res, type;
+ values.some(function (obj) {
+ if (String(obj.uid) === String(val)) {
+ res = obj.values;
+ type = obj.type;
+ return true;
+ }
+ });
+ var vOptions = res.map(function (str) {
+ return {
+ tag: 'a',
+ attributes: {
+ 'class': 'cp-form-condition-value',
+ 'data-value': str,
+ 'href': '#',
+ },
+ content: str
+ };
+ });
+ var valV = dropV.getValue();
+ dropV.setOptions(vOptions);
+ if (valV && res.indexOf(valV) === -1) {
+ dropV.setValue('', Messages.form_condition_v);
+ dropV.onChange.fire();
+ dropV.find('button').removeClass('btn-default')
+ .addClass('btn-secondary');
+ }
+ });
+ } else {
+ // We don't have invalid condition but we may have incomplete
+ // conditions to delete
+ block.opts.when = [];
+ $condition.find('.cp-form-condition-rule').remove();
+ }
+ }
+ };
+ updateState();
+
+ return {
+ updateState: updateState,
+ tag: tag,
+ noViewMode: true,
+ getCursor: cursorGetter,
+ };
+ },
+ printResults: function () { return; },
+ icon: h('i.cptools.cptools-form-conditional')
+ },
};
var arrayMax = function (A) {
return Array.isArray(A)? Math.max.apply(null, A): NaN;
};
- var CLASSIC_MODE = true;
- var renderTally = function (tally, empty, caption) {
+ var renderTally = function (tally, empty, showBar) {
var rows = [];
- if (CLASSIC_MODE) {
- Object.keys(tally).forEach(function (value) {
- rows.push(h('div.cp-form-results-type-radio-data', [
- h('span.cp-value', value),
- h('span.cp-count', tally[value])
- ]));
- });
- if (empty) { rows.push(getEmpty(empty)); }
- return rows;
- }
-
var counts = Util.values(tally);
var max = arrayMax(counts);
-
- Object.keys(tally).forEach(function (answer) {
- rows.push(Charts.row(answer, tally[answer] / max, tally[answer]));
+ if (empty) { rows.push(getEmpty(empty)); }
+ Object.keys(tally).forEach(function (value) {
+ var itemCount = tally[value];
+ var itemScale = (itemCount / max);
+
+ rows.push(h('div.cp-charts-row', [
+ h('span.cp-value', {'title': value}, value),
+ h('span.cp-count', itemCount),
+ showBar? barGraphic(itemScale): undefined,
+ ]));
});
- var hasCaption = typeof(caption) !== 'undefined';
- var table = Charts.table([
- hasCaption ? h('caption', caption): undefined,
- h('tbody', rows)
- ], [
- 'charts-css',
- 'bar',
- hasCaption? 'show-heading': undefined,
- 'show-labels',
- 'show-data-on-hover',
- ]);
-
- return [
- table,
- empty? getEmpty(empty): undefined,
- ];
+ return rows;
};
- var TYPES = {
+ var TYPES = APP.TYPES = {
input: {
defaultOpts: {
type: 'text'
@@ -1017,12 +1604,17 @@ define([
var setCursorGetter = function (f) { cursorGetter = f; };
return {
tag: tag,
+ isEmpty: function () { return !$tag.val().trim(); },
getValue: function () {
//var invalid = $tag.is(':invalid');
//if (invalid) { return; }
return $tag.val();
},
setValue: function (val) { $tag.val(val); },
+ setEditable: function (state) {
+ if (state) { $tag.removeAttr('disabled'); }
+ else { $tag.attr('disabled', 'disabled');Â }
+ },
edit: function (cb, tmp) {
var v = Util.clone(opts);
return editTextOptions(v, setCursorGetter, cb, tmp);
@@ -1031,33 +1623,34 @@ define([
reset: function () { $tag.val(''); }
};
},
- printResults: function (answers, uid) {
+ printResults: function (answers, uid) { // results text
var results = [];
var empty = 0;
var tally = {};
+ var isEmpty = function (answer) {
+ return !answer || !answer.trim();
+ };
+
Object.keys(answers).forEach(function (author) {
var obj = answers[author];
var answer = obj.msg[uid];
- if (!answer || !answer.trim()) { return empty++; }
+ if (isEmpty(answer)) { return empty++; }
Util.inc(tally, answer);
});
- var counts = Util.values(tally);
- var max = arrayMax(counts);
+ //var counts = Util.values(tally);
+ //var max = arrayMax(counts);
- if (CLASSIC_MODE || max < 2) { // there are no duplicates, so just return text
+ //if (max < 2) { // there are no duplicates, so just return text
+ results.push(getEmpty(empty));
Object.keys(answers).forEach(function (author) {
var obj = answers[author];
var answer = obj.msg[uid];
if (!answer || !answer.trim()) { return empty++; }
- results.push(h('div.cp-form-results-type-text-data', answer));
+ results.push(h('div.cp-charts-row', h('span.cp-value', answer)));
});
- results.push(getEmpty(empty));
- return h('div.cp-form-results-type-text', results);
- }
-
- var rendered = renderTally(tally, empty /*, caption */);
- return h('div.cp-form-results-type-text', rendered);
+ return h('div.cp-form-results-contained', h('div.cp-charts.cp-text-table', results));
+ //}
},
icon: h('i.cptools.cptools-form-text')
},
@@ -1066,7 +1659,7 @@ define([
maxLength: 1000
},
get: function (opts, a, n, evOnChange) {
- if (!opts) { opts = TYPES.textarea.defaultOpts; }
+ if (!opts || typeof(opts.maxLength) === "undefined") { opts = TYPES.textarea.defaultOpts; }
var text = h('textarea', {maxlength: opts.maxLength});
var $text = $(text);
var charCount = h('div.cp-form-type-textarea-charcount');
@@ -1099,11 +1692,16 @@ define([
var setCursorGetter = function (f) { cursorGetter = f; };
return {
tag: tag,
+ isEmpty: function () { return !$text.val().trim(); },
getValue: function () { return $text.val().slice(0, opts.maxLength); },
setValue: function (val) {
$text.val(val);
updateChar();
},
+ setEditable: function (state) {
+ if (state) { $(tag).find('textarea').removeAttr('disabled'); }
+ else { $(tag).find('textarea').attr('disabled', 'disabled');Â }
+ },
edit: function (cb, tmp) {
var v = Util.clone(opts);
return editTextOptions(v, setCursorGetter, cb, tmp);
@@ -1119,27 +1717,32 @@ define([
var obj = answers[author];
var answer = obj.msg[uid];
if (!answer || !answer.trim()) { return empty++; }
- results.push(h('div.cp-form-results-type-textarea-data', answer));
+ results.push(h('div.cp-charts-row', h('span.cp-value', answer)));
});
- results.push(getEmpty(empty));
+ results.unshift(getEmpty(empty));
- return h('div.cp-form-results-type-text', results);
+ return h('div.cp-form-results-contained', h('div.cp-charts.cp-text-table', results));
},
icon: h('i.cptools.cptools-form-paragraph')
},
radio: {
+ compatible: ['radio', 'checkbox', 'sort'],
defaultOpts: {
values: [1,2].map(function (i) {
- return Messages._getKey('form_defaultOption', [i]);
+ return {
+ uid: Util.uid(),
+ v: Messages._getKey('form_defaultOption', [i])
+ };
})
},
get: function (opts, a, n, evOnChange) {
+ var isDefaultOpts = !opts;
if (!opts) { opts = TYPES.radio.defaultOpts; }
if (!Array.isArray(opts.values)) { return; }
var name = Util.uid();
- var els = opts.values.map(function (data, i) {
+ var els = extractValues(opts.values).map(function (data, i) {
var radio = UI.createRadio(name, 'cp-form-'+name+'-'+i,
- data, false, { mark: { tabindex:1 } });
+ data, false, {});
$(radio).find('input').data('val', data);
return radio;
});
@@ -1147,10 +1750,11 @@ define([
var cursorGetter;
var setCursorGetter = function (f) { cursorGetter = f; };
$(tag).find('input[type="radio"]').on('change', function () {
- evOnChange.fire();
+ evOnChange.fire(false, false, true);
});
return {
tag: tag,
+ isEmpty: function () { return !this.getValue(); },
getValue: function () {
var res;
els.some(function (el) {
@@ -1163,9 +1767,13 @@ define([
return res;
},
reset: function () { $(tag).find('input').removeAttr('checked'); },
+ setEditable: function (state) {
+ if (state) { $(tag).find('input').removeAttr('disabled'); }
+ else { $(tag).find('input').attr('disabled', 'disabled');Â }
+ },
edit: function (cb, tmp) {
var v = Util.clone(opts);
- return editOptions(v, setCursorGetter, cb, tmp);
+ return editOptions(v, isDefaultOpts, setCursorGetter, cb, tmp);
},
getCursor: function () { return cursorGetter(); },
setValue: function (val) {
@@ -1181,25 +1789,29 @@ define([
};
},
- printResults: function (answers, uid) {
+ printResults: function (answers, uid, form, content) {
// results radio
var empty = 0;
var count = {};
+
+ var opts = form[uid].opts || TYPES.radio.defaultOpts;
+ extractValues(opts.values).forEach(function (v) { count[v] = 0; });
+
Object.keys(answers).forEach(function (author) {
var obj = answers[author];
var answer = obj.msg[uid];
- if (!answer || !answer.trim()) { return empty++; }
+ if (!answer || !answer.trim || !answer.trim()) { return empty++; }
Util.inc(count, answer);
});
- var rendered = renderTally(count, empty/*, caption */);
- return h('div.cp-form-results-type-radio', {
- style: CLASSIC_MODE? '': 'width: 100%',
- }, rendered);
+ var showBars = Boolean(content);
+ var rendered = renderTally(count, empty, showBars);
+ return h('div.cp-charts.cp-bar-table', rendered);
},
icon: h('i.cptools.cptools-form-list-radio')
},
multiradio: {
+ compatible: ['multiradio', 'multicheck'],
defaultOpts: {
items: [1,2].map(function (i) {
return {
@@ -1208,18 +1820,22 @@ define([
};
}),
values: [1,2].map(function (i) {
- return Messages._getKey('form_defaultOption', [i]);
+ return {
+ uid: Util.uid(),
+ v: Messages._getKey('form_defaultOption', [i])
+ };
})
},
get: function (opts, a, n, evOnChange) {
+ var isDefaultOpts = !opts;
if (!opts) { opts = TYPES.multiradio.defaultOpts; }
if (!Array.isArray(opts.items) || !Array.isArray(opts.values)) { return; }
var lines = opts.items.map(function (itemData) {
var name = itemData.uid;
var item = itemData.v;
- var els = opts.values.map(function (data, i) {
+ var els = extractValues(opts.values).map(function (data, i) {
var radio = UI.createRadio(name, 'cp-form-'+name+'-'+i,
- '', false, { mark: { tabindex:1 } });
+ '', false, {});
$(radio).find('input').data('uid', name);
$(radio).find('input').data('val', data);
return radio;
@@ -1227,18 +1843,25 @@ define([
els.unshift(h('div.cp-form-multiradio-item', item));
return h('div.radio-group', {'data-uid':name}, els);
});
- var header = opts.values.map(function (v) { return h('span', v); });
+ var header = extractValues(opts.values).map(function (v) { return h('span', v); });
header.unshift(h('span'));
lines.unshift(h('div.cp-form-multiradio-header', header));
var tag = h('div.radio-group.cp-form-type-multiradio', lines);
var cursorGetter;
var setCursorGetter = function (f) { cursorGetter = f; };
- $(tag).find('input[type="radio"]').on('change', function () {
+ var $tag = $(tag);
+ $tag.find('input[type="radio"]').on('change', function () {
evOnChange.fire();
});
return {
tag: tag,
+ isEmpty: function () {
+ var v = this.getValue();
+ return !Object.keys(v).length || Object.keys(v).some(function (uid) {
+ return !v[uid];
+ });
+ },
getValue: function () {
var res = {};
var l = lines.slice(1);
@@ -1248,15 +1871,20 @@ define([
$el.find('input').each(function (i, input) {
var $i = $(input);
if (res[uid]) { return; }
+ res[uid] = undefined;
if (Util.isChecked($i)) { res[uid] = $i.data('val'); }
});
});
return res;
},
reset: function () { $(tag).find('input').removeAttr('checked'); },
+ setEditable: function (state) {
+ if (state) { $tag.find('input').removeAttr('disabled'); }
+ else { $tag.find('input').attr('disabled', 'disabled');Â }
+ },
edit: function (cb, tmp) {
var v = Util.clone(opts);
- return editOptions(v, setCursorGetter, cb, tmp);
+ return editOptions(v, isDefaultOpts, setCursorGetter, cb, tmp);
},
getCursor: function () { return cursorGetter(); },
setValue: function (val) {
@@ -1271,7 +1899,7 @@ define([
};
},
- printResults: function (answers, uid, form) {
+ printResults: function (answers, uid, form, content) {
// results multiradio
var structure = form[uid];
if (!structure) { return; }
@@ -1279,15 +1907,21 @@ define([
var results = [];
var empty = 0;
var count = {};
+
+ var showBars = Boolean(content);
Object.keys(answers).forEach(function (author) {
var obj = answers[author];
var answer = obj.msg[uid];
if (!answer || !Object.keys(answer).length) { return empty++; }
//count[answer] = count[answer] ||Â {};
Object.keys(answer).forEach(function (q_uid) {
- var c = count[q_uid] = count[q_uid] || {};
+ var c = count[q_uid];
+ if (!c) {
+ count[q_uid] = c = {};
+ extractValues(opts.values).forEach(function (v) { c[v] = 0; });
+ }
var res = answer[q_uid];
- if (!res || !res.trim()) { return; }
+ if (!res || !res.trim || !res.trim()) { return; }
Util.inc(c, res);
});
});
@@ -1300,49 +1934,17 @@ define([
max = arrayMax(counts);
});
+ results.push(getEmpty(empty));
count_keys.forEach(function (q_uid) {
var q = findItem(opts.items, q_uid);
var c = count[q_uid];
-
-
- if (CLASSIC_MODE) {
- var values = Object.keys(c).map(function (res) {
- return h('div.cp-form-results-type-radio-data', [
- h('span.cp-value', res),
- h('span.cp-count', c[res])
- ]);
- });
- results.push(h('div.cp-form-results-type-multiradio-data', [
- h('span.cp-mr-q', q),
- h('span.cp-mr-value', values)
- ]));
- return;
- }
-
- var table = Charts.table([
- h('caption', {
- style: 'color: var(--msg-color)',
- }, q),
- h('tbody', Object.keys(c).map(function (res) {
- return Charts.row(res, c[res] / max, c[res]);
- })),
- ], [
- 'charts-css',
- 'bar',
- 'show-heading',
- 'show-data-on-hover',
- 'show-labels',
- ]);
-
- results.push(h('div.cp-form-results-type-multiradio-data', {
- style: 'width: 100%',
- }, table));
+ results.push(multiAnswerSubHeading(q));
+ Object.keys(c).forEach(function (res) {
+ results.push(barRow(res, c[res], max, showBars));
+ });
});
- results.push(getEmpty(empty));
- return h('div.cp-form-results-type-radio', {
- style: CLASSIC_MODE? '': 'width: 100%',
- }, results);
+ return h('div.cp-charts.cp-bar-table', results);
},
exportCSV: function (answer, form) {
var opts = form.opts || {};
@@ -1361,40 +1963,53 @@ define([
icon: h('i.cptools.cptools-form-grid-radio')
},
checkbox: {
+ compatible: ['radio', 'checkbox', 'sort'],
defaultOpts: {
max: 3,
values: [1, 2, 3].map(function (i) {
- return Messages._getKey('form_defaultOption', [i]);
+ return {
+ uid: Util.uid(),
+ v: Messages._getKey('form_defaultOption', [i])
+ };
})
},
get: function (opts, a, n, evOnChange) {
+ var isDefaultOpts = !opts;
if (!opts) { opts = TYPES.checkbox.defaultOpts; }
if (!Array.isArray(opts.values)) { return; }
var name = Util.uid();
- var els = opts.values.map(function (data, i) {
+ var els = extractValues(opts.values).map(function (data, i) {
var cbox = UI.createCheckbox('cp-form-'+name+'-'+i,
- data, false, { mark: { tabindex:1 } });
+ data, false, {});
$(cbox).find('input').data('val', data);
return cbox;
});
+ if (!opts.max) { opts.max = TYPES.checkbox.defaultOpts.max; }
var tag = h('div', [
h('div.cp-form-max-options', Messages._getKey('form_maxOptions', [opts.max])),
h('div.radio-group.cp-form-type-checkbox', els)
]);
var $tag = $(tag);
- $tag.find('input').on('change', function () {
+ var checkDisabled = function () {
var selected = $tag.find('input:checked').length;
if (selected >= opts.max) {
$tag.find('input:not(:checked)').attr('disabled', 'disabled');
} else {
$tag.find('input').removeAttr('disabled');
}
- evOnChange.fire();
+ };
+ $tag.find('input').on('change', function () {
+ checkDisabled();
+ evOnChange.fire(false, false, true);
});
var cursorGetter;
var setCursorGetter = function (f) { cursorGetter = f; };
return {
tag: tag,
+ isEmpty: function () {
+ var v = this.getValue();
+ return !v.length;
+ },
getValue: function () {
var res = [];
els.forEach(function (el) {
@@ -1405,10 +2020,17 @@ define([
});
return res;
},
- reset: function () { $(tag).find('input').removeAttr('checked'); },
+ reset: function () {
+ $(tag).find('input').removeAttr('checked');
+ checkDisabled();
+ },
+ setEditable: function (state) {
+ if (state) { checkDisabled(); }
+ else { $tag.find('input').attr('disabled', 'disabled');Â }
+ },
edit: function (cb, tmp) {
var v = Util.clone(opts);
- return editOptions(v, setCursorGetter, cb, tmp);
+ return editOptions(v, isDefaultOpts, setCursorGetter, cb, tmp);
},
getCursor: function () { return cursorGetter(); },
setValue: function (val) {
@@ -1420,29 +2042,37 @@ define([
$el.prop('checked', true);
}
});
+ checkDisabled();
}
};
},
- printResults: function (answers, uid) {
+ printResults: function (answers, uid, form, content) {
// results checkbox
var empty = 0;
var count = {};
+
+ var opts = form[uid].opts || TYPES.checkbox.defaultOpts;
+ extractValues(opts.values || []).forEach(function (v) { count[v] = 0; });
+
+ var showBars = Boolean(content);
Object.keys(answers).forEach(function (author) {
var obj = answers[author];
var answer = obj.msg[uid];
+ if (answer && typeof(answer) === "string") { answer = [answer]; }
if (!Array.isArray(answer) || !answer.length) { return empty++; }
answer.forEach(function (val) {
Util.inc(count, val);
});
});
- var rendered = renderTally(count, empty /*, caption */);
- return h('div.cp-form-results-type-radio', rendered);
+ var rendered = renderTally(count, empty, showBars);
+ return h('div.cp-charts.cp-bar-table', rendered);
},
icon: h('i.cptools.cptools-form-list-check')
},
multicheck: {
+ compatible: ['multiradio', 'multicheck'],
defaultOpts: {
max: 3,
items: [1,2].map(function (i) {
@@ -1452,18 +2082,22 @@ define([
};
}),
values: [1,2,3].map(function (i) {
- return Messages._getKey('form_defaultOption', [i]);
+ return {
+ uid: Util.uid(),
+ v: Messages._getKey('form_defaultOption', [i])
+ };
})
},
get: function (opts, a, n, evOnChange) {
+ var isDefaultOpts = !opts;
if (!opts) { opts = TYPES.multicheck.defaultOpts; }
if (!Array.isArray(opts.items) || !Array.isArray(opts.values)) { return; }
var lines = opts.items.map(function (itemData) {
var name = itemData.uid;
var item = itemData.v;
- var els = opts.values.map(function (data, i) {
+ var els = extractValues(opts.values).map(function (data, i) {
var cbox = UI.createCheckbox('cp-form-'+name+'-'+i,
- '', false, { mark: { tabindex:1 } });
+ '', false, {});
$(cbox).find('input').data('uid', name);
$(cbox).find('input').data('val', data);
return cbox;
@@ -1472,19 +2106,25 @@ define([
return h('div.radio-group', {'data-uid':name}, els);
});
+ if (!opts.max) { opts.max = TYPES.multicheck.defaultOpts.max; }
+
+ var checkDisabled = function (l) {
+ var selected = $(l).find('input:checked').length;
+ if (selected >= opts.max) {
+ $(l).find('input:not(:checked)').attr('disabled', 'disabled');
+ } else {
+ $(l).find('input').removeAttr('disabled');
+ }
+ };
+
lines.forEach(function (l) {
$(l).find('input').on('change', function () {
- var selected = $(l).find('input:checked').length;
- if (selected >= opts.max) {
- $(l).find('input:not(:checked)').attr('disabled', 'disabled');
- } else {
- $(l).find('input').removeAttr('disabled');
- }
+ checkDisabled(l);
evOnChange.fire();
});
});
- var header = opts.values.map(function (v) { return h('span', v); });
+ var header = extractValues(opts.values).map(function (v) { return h('span', v); });
header.unshift(h('span'));
lines.unshift(h('div.cp-form-multiradio-header', header));
@@ -1493,6 +2133,12 @@ define([
var setCursorGetter = function (f) { cursorGetter = f; };
return {
tag: tag,
+ isEmpty: function () {
+ var v = this.getValue();
+ return Object.keys(v).some(function (uid) {
+ return !v[uid].length;
+ });
+ },
getValue: function () {
var res = {};
var l = lines.slice(1);
@@ -1507,10 +2153,17 @@ define([
});
return res;
},
- reset: function () { $(tag).find('input').removeAttr('checked'); },
+ reset: function () {
+ $(tag).find('input').removeAttr('checked');
+ lines.forEach(checkDisabled);
+ },
+ setEditable: function (state) {
+ if (state) { lines.forEach(checkDisabled); }
+ else { $(tag).find('input').attr('disabled', 'disabled');Â }
+ },
edit: function (cb, tmp) {
var v = Util.clone(opts);
- return editOptions(v, setCursorGetter, cb, tmp);
+ return editOptions(v, isDefaultOpts, setCursorGetter, cb, tmp);
},
getCursor: function () { return cursorGetter(); },
setValue: function (val) {
@@ -1522,11 +2175,12 @@ define([
$(el).prop('checked', true);
});
});
+ lines.forEach(checkDisabled);
}
};
},
- printResults: function (answers, uid, form) {
+ printResults: function (answers, uid, form, content ) {
// results multicheckbox
var structure = form[uid];
if (!structure) { return; }
@@ -1534,13 +2188,28 @@ define([
var results = [];
var empty = 0;
var count = {};
+ var showBars = Boolean(content);
+
+ var isEmpty = function (answer) {
+ if (!answer) { return true; }
+ return !Object.keys(answer).some(function (k) {
+ var A = answer[k];
+ return Array.isArray(A) && A.length;
+ });
+ };
+
Object.keys(answers).forEach(function (author) {
var obj = answers[author];
var answer = obj.msg[uid];
- if (!answer || !Object.keys(answer).length) { return empty++; }
+ if (isEmpty(answer)) { return empty++; }
Object.keys(answer).forEach(function (q_uid) {
- var c = count[q_uid] = count[q_uid] || {};
+ var c = count[q_uid];
+ if (!c) {
+ count[q_uid] = c = {};
+ extractValues(opts.values || []).forEach(function (v) { c[v] = 0; });
+ }
var res = answer[q_uid];
+ if (res && typeof(res) === "string") { res = [res]; }
if (!Array.isArray(res) || !res.length) { return; }
res.forEach(function (v) {
Util.inc(c, v);
@@ -1556,49 +2225,17 @@ define([
max = arrayMax(counts);
});
+ results.push(getEmpty(empty));
count_keys.forEach(function (q_uid) {
var q = findItem(opts.items, q_uid);
var c = count[q_uid];
-
-
- if (CLASSIC_MODE) {
- var values = Object.keys(c).map(function (res) {
- return h('div.cp-form-results-type-radio-data', [
- h('span.cp-value', res),
- h('span.cp-count', c[res])
- ]);
- });
- results.push(h('div.cp-form-results-type-multiradio-data', [
- h('span.cp-mr-q', q),
- h('span.cp-mr-value', values)
- ]));
- return;
- }
-
- var table = Charts.table([
- h('caption', {
- style: 'color: var(--msg-color)',
- }, q),
- h('tbody', Object.keys(c).map(function (res) {
- return Charts.row(res, c[res] / max, c[res]);
- })),
- ], [
- 'charts-css',
- 'bar',
- 'show-heading',
- 'show-data-on-hover',
- 'show-labels',
- ]);
-
- results.push(h('div.cp-form-results-type-multiradio-data', {
- style: 'width: 100%',
- }, table));
+ results.push(multiAnswerSubHeading(q));
+ Object.keys(c).forEach(function (res) {
+ results.push(barRow(res, c[res], max, showBars));
+ });
});
- results.push(getEmpty(empty));
- return h('div.cp-form-results-type-radio', {
- style: CLASSIC_MODE? '': 'width: 100%',
- }, results);
+ return h('div.cp-charts.cp-bar-table', results);
},
exportCSV: function (answer, form) {
var opts = form.opts || {};
@@ -1617,12 +2254,17 @@ define([
icon: h('i.cptools.cptools-form-grid-check')
},
sort: {
+ compatible: ['radio', 'checkbox', 'sort'],
defaultOpts: {
values: [1,2].map(function (i) {
- return Messages._getKey('form_defaultOption', [i]);
+ return {
+ uid: Util.uid(),
+ v: Messages._getKey('form_defaultOption', [i])
+ };
})
},
get: function (opts, a, n, evOnChange) {
+ var isDefaultOpts = !opts;
if (!opts) { opts = TYPES.sort.defaultOpts; }
if (!Array.isArray(opts.values)) { return; }
var map = {};
@@ -1636,9 +2278,9 @@ define([
into concatenating strings, which quickly turns the sortable list
into complete nonsense.
*/
- Util.shuffleArray(opts.values); // XXX
+ Util.shuffleArray(opts.values);
}
- var els = opts.values.map(function (data) {
+ var els = extractValues(opts.values).map(function (data) {
var uid = Util.uid();
map[uid] = data;
invMap[data] = uid;
@@ -1673,17 +2315,14 @@ define([
forceFallback: true,
store: {
set: function () {
- evOnChange.fire();
reorder();
+ evOnChange.fire();
}
}
});
-
- $(tag).find('input[type="radio"]').on('change', function () {
- evOnChange.fire();
- });
return {
tag: tag,
+ isEmpty: function () { return !this.getValue(); },
getValue: function () {
if (!sorted) { return; }
return sortable.toArray().map(function (id) {
@@ -1692,19 +2331,24 @@ define([
},
reset: function () {
Util.shuffleArray(opts.values);
- var toSort = (opts.values).map(function (val) {
+ var toSort = extractValues(opts.values).map(function (val) {
return invMap[val];
});
sortable.sort(toSort);
reorder(true);
},
+ setEditable: function (state) {
+ sortable.options.disabled = !state;
+ $(tag).toggleClass('cp-form-disabled', !state);
+ },
edit: function (cb, tmp) {
var v = Util.clone(opts);
- return editOptions(v, setCursorGetter, cb, tmp);
+ return editOptions(v, isDefaultOpts, setCursorGetter, cb, tmp);
},
getCursor: function () { return cursorGetter(); },
setValue: function (val) {
- var toSort = (val ||Â []).map(function (val) {
+ if (!Array.isArray(val)) { val = []; }
+ var toSort = val.map(function (val) {
return invMap[val];
});
sortable.sort(toSort);
@@ -1713,16 +2357,18 @@ define([
};
},
- printResults: function (answers, uid, form) {
+ printResults: function (answers, uid, form, content) {
// results sort
var opts = form[uid].opts || TYPES.sort.defaultOpts;
var l = (opts.values || []).length;
- //var results = [];
var empty = 0;
var count = {};
+ extractValues(opts.values || []).forEach(function (v) { count[v] = 0; });
+ var showBars = Boolean(content);
Object.keys(answers).forEach(function (author) {
var obj = answers[author];
var answer = obj.msg[uid];
+ if (answer && typeof(answer) === "string") { answer = [answer]; }
if (!Array.isArray(answer) || !answer.length) { return empty++; }
answer.forEach(function (el, i) {
var score = l - i;
@@ -1730,10 +2376,8 @@ define([
});
});
- var rendered = renderTally(count, empty /*, caption */);
- return h('div.cp-form-results-type-radio', {
- style: CLASSIC_MODE? '': 'width: 100%',
- }, rendered);
+ var rendered = renderTally(count, empty, showBars);
+ return h('div.cp-charts.cp-bar-table', rendered);
},
icon: h('i.cptools.cptools-form-list-ordered')
},
@@ -1741,17 +2385,23 @@ define([
defaultOpts: {
type: 'text', // Text or Days or Time
values: [1, 2, 3].map(function (i) {
- return Messages._getKey('form_defaultOption', [i]);
+ return {
+ uid: Util.uid(),
+ v: Messages._getKey('form_defaultOption', [i])
+ };
})
},
get: function (opts, answers, username, evOnChange) {
+ var isDefaultOpts = !opts;
if (!opts) { opts = TYPES.poll.defaultOpts; }
if (!Array.isArray(opts.values)) { return; }
+ if (APP.isEditor) { answers = {}; }
var lines = makePollTable(answers, opts, false);
+ var disabled = false;
// Add form
- var addLine = opts.values.map(function (data) {
+ var addLine = extractValues(opts.values).map(function (data) {
var cell = h('div.cp-poll-cell.cp-form-poll-choice', [
h('i.fa.fa-times.cp-no'),
h('i.fa.fa-check.cp-yes'),
@@ -1762,6 +2412,7 @@ define([
var val = 0;
$c.attr('data-value', val);
$c.click(function () {
+ if (disabled) { return; }
val = (val+1)%3;
$c.attr('data-value', val);
evOnChange.fire();
@@ -1814,9 +2465,13 @@ define([
reset: function () {
$tag.find('.cp-form-poll-choice').attr('data-value', 0);
},
+ setEditable: function (state) {
+ disabled = !state;
+ $tag.toggleClass('cp-form-disabled', disabled);
+ },
edit: function (cb, tmp) {
var v = Util.clone(opts);
- return editOptions(v, setCursorGetter, cb, tmp);
+ return editOptions(v, isDefaultOpts, setCursorGetter, cb, tmp);
},
getCursor: function () { return cursorGetter(); },
setValue: function (res) {
@@ -1852,7 +2507,7 @@ define([
var opts = form.opts || TYPES.poll.defaultOpts;
var q = form.q || Messages.form_default;
if (answer === false) {
- var cols = opts.values.map(function (key) {
+ var cols = extractValues(opts.values).map(function (key) {
return q + ' | ' + key;
});
cols.unshift(q);
@@ -1868,7 +2523,7 @@ define([
if (i !== 0) { str += ';'; }
str += k.replace(';', '').replace(':', '') + ':' + answer.values[k];
});
- var res = opts.values.map(function (key) {
+ var res = extractValues(opts.values).map(function (key) {
return answer.values[key] || '';
});
res.unshift(str);
@@ -1897,8 +2552,7 @@ define([
return A;
};
- Messages.form_timelineLabel = "{0} ({1})"; // XXX
- Messages.form_totalResponses = "Total responses: {0}"; // XXX
+ Messages.form_timelineLabel = "{0} ({1})"; // TODO investigate whether this needs translation
var makeTimeline = APP.makeTimeline = function (answers) {
// Randomly changing date of answers to get a more realistic example of timeline
@@ -1945,7 +2599,11 @@ define([
};
var renderResults = APP.renderResults = function (content, answers, showUser) {
- var $container = $('div.cp-form-creator-results').empty();
+ var $container = $('div.cp-form-creator-results').empty().css('display', '');
+
+ var framework = APP.framework;
+ var title = framework._.title.title || framework._.title.defaultTitle;
+ $container.append(h('h1.cp-form-view-title', title));
var answerCount = Object.keys(answers || {}).length;
@@ -1954,12 +2612,6 @@ define([
return;
}
- if (content.answers.msg) {
- var description = h('div.cp-form-creator-results-description#cp-form-response-msg');
- var $desc = $(description).appendTo($container);
- DiffMd.apply(DiffMd.render(content.answers.msg), $desc, APP.common);
- }
-
var heading = h('h2#cp-title', Messages._getKey('form_totalResponses', [answerCount]));
$(heading).appendTo($container);
var timeline = h('div.cp-form-creator-results-timeline');
@@ -2108,10 +2760,17 @@ define([
}
};
- var addResultsButton = function (framework, content) {
- var $res = $(h('button.cp-toolbar-appmenu.cp-toolbar-form-button', [
+ var getAnswersLength = function (answers) {
+ return Object.keys(answers || {}).filter(function (key)Â {
+ return key && key.slice(0,1) !== "_";
+ }).length;
+ };
+ var addResultsButton = function (framework, content, answers) {
+ var $container = $('.cp-forms-results-participant');
+ var l = getAnswersLength(answers);
+ var $res = $(h('button.btn.btn-default.cp-toolbar-form-button', [
h('i.fa.fa-bar-chart'),
- h('span.cp-button-name', Messages.form_results)
+ h('span.cp-button-name', Messages._getKey('form_results', [l])),
]));
$res.click(function () {
$res.attr('disabled', 'disabled');
@@ -2123,32 +2782,218 @@ define([
$('body').addClass('cp-app-form-results');
renderResults(content, answers);
$res.remove();
- var $editor = $(h('button.cp-toolbar-appmenu', [
+ var $editor = $(h('button.btn.btn-default', [
h('i.fa.fa-pencil'),
- h('span.cp-button-name', APP.isEditor ? Messages.form_editor : Messages.form_form)
+ h('span.cp-button-name', Messages.form_editor)
]));
$editor.click(function () {
$('body').removeClass('cp-app-form-results');
$editor.remove();
- addResultsButton(framework, content);
+ sframeChan.query("Q_FORM_FETCH_ANSWERS", content.answers, function (err, obj) {
+ var answers = obj && obj.results;
+ addResultsButton(framework, content, answers);
+ });
});
- framework._.toolbar.$bottomL.append($editor);
+ $container.prepend($editor);
+ });
+
+ });
+ $container.prepend($res);
+ };
+
+ var getLogo = function () {
+ var logo = h('div.cp-form-view-logo', [
+ h('img', {
+ src:'/customize/CryptPad_logo_grey.svg?'+ApiConfig.requireConf.urlArgs,
+ alt:'CryptPad_logo'
+ }),
+ h('span', 'CryptPad')
+ ]);
+ $(logo).click(function () {
+ APP.framework._.sfCommon.gotoURL('/');
+ });
+ var footer = h('div.cp-form-view-footer', [logo]);
+ return footer;
+ };
+
+ var showAnsweredPage = function (framework, content, answers) {
+ var $formContainer = $('div.cp-form-creator-content').hide();
+ var $resContainer = $('div.cp-form-creator-results').hide();
+ var $container = $('div.cp-form-creator-answered').empty().css('display', '');
+
+ if (APP.answeredInForm) {
+ $container.hide();
+ $formContainer.css('display', '');
+ } else if (APP.answeredInResponses) {
+ $container.hide();
+ $resContainer.css('display', '');
+ }
+
+ var viewOnly = content.answers.cantEdit || APP.isClosed;
+ var action = h(viewOnly ? 'button.btn.btn-secondary' : 'button.btn.btn-primary', [
+ viewOnly ? h('i.fa.fa-bar-chart') : h('i.fa.fa-pencil'),
+ h('span', viewOnly ? Messages.form_viewAnswer : Messages.form_editAnswer)
+ ]);
+
+ $(action).click(function () {
+ $formContainer.css('display', '');
+ $container.hide();
+ APP.answeredInForm = true;
+ if (viewOnly) {
+ $formContainer.find('.cp-form-send-container .cp-open').hide();
+ if (Array.isArray(APP.formBlocks)) {
+ APP.formBlocks.forEach(function (b) {
+ if (!b.setEditable) { return; }
+ b.setEditable(false);
+ });
+ }
+ }
+ });
+
+ if (answers._time)Â { APP.lastAnswerTime = answers._time; }
+
+ // If responses are public, show button to view them
+ var responses;
+ if (content.answers.privateKey) {
+ var l = getAnswersLength(answers);
+ responses = h('button.btn.btn-secondary', [
+ h('i.fa.fa-bar-chart'),
+ h('span.cp-button-name', Messages._getKey('form_viewAllAnswers', [l]))
+ ]);
+ var sframeChan = framework._.sfCommon.getSframeChannel();
+ sframeChan.query("Q_FORM_FETCH_ANSWERS", content.answers, function (err, obj) {
+ var answers = obj && obj.results;
+ var l = getAnswersLength(answers);
+ $(responses).find('.cp-button-name').text(Messages._getKey('form_viewAllAnswers', [l]));
+ });
+ $(responses).click(function () {
+ sframeChan.query("Q_FORM_FETCH_ANSWERS", content.answers, function (err, obj) {
+ APP.answeredInResponses = true;
+ var answers = obj && obj.results;
+ if (answers) { APP.answers = answers; }
+ $('body').addClass('cp-app-form-results');
+ renderResults(content, answers);
+ $container.hide();
+ });
+ });
+ }
+
+ var description = h('div.cp-form-creator-results-description#cp-form-response-msg');
+ if (content.answers.msg) {
+ var $desc = $(description);
+ DiffMd.apply(DiffMd.render(content.answers.msg), $desc, APP.common);
+ }
+
+ var actions = h('div.cp-form-submit-actions', [
+ action,
+ responses || undefined
+ ]);
+
+ var title = framework._.title.title || framework._.title.defaultTitle;
+ $container.append(h('div.cp-form-submit-success', [
+ h('h3.cp-form-view-title', title),
+ h('div.alert.alert-info', Messages._getKey('form_alreadyAnswered', [
+ new Date(APP.lastAnswerTime).toLocaleString()])),
+ description,
+ actions
+ ]));
+ $container.append(getLogo());
+ };
+
+ var getFormResults = function () {
+ if (!Array.isArray(APP.formBlocks)) { return; }
+ var results = {};
+ APP.formBlocks.some(function (data) {
+ if (!data.getValue) { return; }
+ results[data.uid] = data.getValue();
+ });
+ return results;
+ };
+
+ var getSectionFromQ = function (content, uid) {
+ var arr = content.order;
+ var idx = content.order.indexOf(uid);
+ var sectionUid;
+ if (idx === -1) { // If it's not in the main array, check in sections
+ getSections(content).some(function (_uid) {
+ var block = content.form[_uid];
+ if (!block.opts || !Array.isArray(block.opts.questions)) { return; }
+ var _idx = block.opts.questions.indexOf(uid);
+ if (_idx !== -1) {
+ arr = block.opts.questions;
+ sectionUid = _uid;
+ idx = _idx;
+ return true;
+ }
+ });
+ }
+
+ return {
+ uid: sectionUid,
+ arr: arr,
+ idx: idx
+ };
+ };
+ var removeQuestion = function (content, uid) {
+ delete content.form[uid];
+ var idx = content.order.indexOf(uid);
+ if (idx !== -1) {
+ content.order.splice(idx, 1);
+ } else {
+ getSections(content).some(function (_uid) {
+ var block = content.form[_uid];
+ if (!block.opts || !Array.isArray(block.opts.questions)) { return; }
+ var _idx = block.opts.questions.indexOf(uid);
+ if (_idx !== -1) {
+ block.opts.questions.splice(_idx, 1);
+ return true;
+ }
});
-
- });
- framework._.toolbar.$bottomL.append($res);
+ }
};
- var getFormResults = function () {
- if (!Array.isArray(APP.formBlocks)) { return; }
- var results = {};
- APP.formBlocks.forEach(function (data) {
- if (!data.getValue) { return; }
- results[data.uid] = data.getValue();
+ var checkResults = {};
+ var checkCondition = function (block) {
+ if (!block || block.type !== 'section') { return; }
+ if (!block.opts || !Array.isArray(block.opts.questions) || !block.opts.when) {
+ return true;
+ }
+
+ // This function may be called multiple times synchronously to check the conditions
+ // of multiple sections. These sections may require the result of the same question
+ // so we store the results in an object outside.
+ // To make sure the results are cleared on the next change in the form, we
+ // clear it just after the current synchronous actions are done.
+ setTimeout(function () { checkResults = {}; });
+
+ var results = checkResults;
+ var findResult = function (uid) {
+ if (results.hasOwnProperty(uid)) { return results[uid]; }
+ APP.formBlocks.some(function (data) {
+ if (!data.getValue) { return; }
+ if (data.uid === String(uid)) {
+ results[uid] = data.getValue();
+ return true;
+ }
+ });
+ return results[uid];
+ };
+ var w = block.opts.when;
+ return !w.length || w.some(function (rules) {
+ return rules.every(function (rule) {
+ var res = findResult(rule.q);
+ // Checkbox
+ if (Array.isArray(res)) {
+ var idx = res.indexOf(rule.v);
+ return rule.is ? idx !== -1 : idx === -1;
+ }
+ // Radio
+ return rule.is ? res === rule.v : res !== rule.v;
+ });
});
- return results;
};
- var makeFormControls = function (framework, content, update, evOnChange) {
+
+ var makeFormControls = function (framework, content, evOnChange) {
var loggedIn = framework._.sfCommon.isLoggedIn();
var metadataMgr = framework._.cpNfInner.metadataMgr;
var user = metadataMgr.getUserData();
@@ -2158,28 +3003,69 @@ define([
var cbox;
var anonName, $anonName;
cbox = UI.createCheckbox('cp-form-anonymous',
- Messages.form_anonymousBox, true, { mark: { tabindex:1 } });
- var $anonBox = $(cbox).find('input');
- if (loggedIn) {
- if (!content.answers.anonymous || APP.cantAnon) {
- $(cbox).hide().find('input').attr('disabled', 'disabled').prop('checked', false);
+ Messages.form_anonymousBox, true, {});
+ var $cbox = $(cbox);
+ var $anonBox = $cbox.find('input');
+ if (content.answers.makeAnonymous) {
+ // If we make all answers anonymous, hide the checkbox and display a message
+ $cbox.hide();
+ $anonBox.attr('disabled', 'disabled').prop('checked', true);
+ setTimeout(function () {
+ // We need to wait for cbox to be added into the DOM before using .after()
+ $cbox.after(h('div.alert.alert-info', Messages.form_anonAnswer));
+ });
+ } else if (content.answers.anonymous) {
+ // Answers aren't anonymous and guests are allowed
+ // Guests can set a username and logged in users can answer anonymously
+ var $anon;
+ if (!loggedIn) {
+ anonName = h('div.cp-form-anon-answer-input', [
+ Messages.form_answerAs,
+ h('input', {
+ value: user.name || '',
+ placeholder: Messages.form_anonName
+ })
+ ]);
+ $anonName = $(anonName).hide();
+ } else if (APP.cantAnon) {
+ // You've already answered with your credentials
+ $cbox.hide();
+ $anonBox.attr('disabled', 'disabled').prop('checked', false);
+ }
+ if (!anonName) {
+ anonName = h('div.cp-form-anon-answer-input', [
+ Messages.form_answerAs,
+ h('span.cp-form-anon-answer-registered', user.name || Messages.anonymous)
+ ]);
+ }
+ if (!APP.cantAnon) {
+ $anon = $(anonName).hide();
+ $anonBox.on('change', function () {
+ if (Util.isChecked($anonBox)) { $anon.hide(); }
+ else { $anon.show(); }
+ });
}
} else {
+ // Answers don't have to be anonymous and only logged in users can answer
+ // ==> they have to answer with their keys so we know their name too
+ $cbox.hide();
+ $anonBox.attr('disabled', 'disabled').prop('checked', false);
+ setTimeout(function () {
+ // We need to wait for cbox to be added into the DOM before using .after()
+ if (content.answers.cantEdit) { return; }
+ $cbox.after(h('div.alert.alert-info', Messages.form_authAnswer));
+ });
anonName = h('div.cp-form-anon-answer-input', [
Messages.form_answerAs,
- h('input', {
- value: user.name || '',
- placeholder: Messages.form_anonName
- })
+ h('span.cp-form-anon-answer-registered', user.name || Messages.anonymous)
]);
- $anonName = $(anonName).hide();
- $anonBox.on('change', function () {
- if (Util.isChecked($anonBox)) { $anonName.hide(); }
- else { $anonName.show(); }
- });
+ }
+ if (APP.hasAnswered && content.answers.cantEdit || APP.isClosed) {
+ $cbox.hide();
+ anonName = undefined;
}
- var send = h('button.cp-open.btn.btn-primary', update ? Messages.form_update : Messages.form_submit);
+ var send = h('button.cp-open.btn.btn-primary', APP.hasAnswered ? Messages.form_update : Messages.form_submit);
var reset = h('button.cp-open.cp-reset-button.btn.btn-danger-alt', Messages.form_reset);
$(reset).click(function () {
if (!Array.isArray(APP.formBlocks)) { return; }
@@ -2187,6 +3073,7 @@ define([
if (typeof(data.reset) === "function") { data.reset(); }
});
$(reset).attr('disabled', 'disabled');
+ evOnChange.fire();
});
var $send = $(send).click(function () {
$send.attr('disabled', 'disabled');
@@ -2194,7 +3081,7 @@ define([
if (!results) { return; }
var user = metadataMgr.getUserData();
- if (!Util.isChecked($anonBox)) {
+ if (!Util.isChecked($anonBox) && !content.answers.makeAnonymous) {
results._userdata = loggedIn ? {
avatar: user.avatar,
name: user.name,
@@ -2210,7 +3097,8 @@ define([
sframeChan.query('Q_FORM_SUBMIT', {
mailbox: content.answers,
results: results,
- anonymous: !loggedIn || Util.isChecked($(cbox).find('input'))
+ anonymous: content.answers.makeAnonymous || !loggedIn
+ || (Util.isChecked($anonBox) && !APP.cantAnon) // use ephemeral keys
}, function (err, data) {
$send.attr('disabled', 'disabled');
if (err || (data && data.error)) {
@@ -2222,13 +3110,16 @@ define([
}
evOnChange.fire(false, true);
window.onbeforeunload = undefined;
- if (!update && content.answers.privateKey) {
- // Add results button
- addResultsButton(framework, content);
- }
+
$send.removeAttr('disabled');
- UI.alert(Messages.form_sent);
$send.text(Messages.form_update);
+ APP.hasAnswered = true;
+ APP.answeredInForm = false;
+ showAnsweredPage(framework, content, { '_time': +new Date() });
+ if (content.answers.cantEdit) {
+ $cbox.hide();
+ if ($anonName) { $anonName.hide(); }
+ }
});
});
@@ -2237,6 +3128,8 @@ define([
reset = undefined;
}
+ var errors = h('div.cp-form-invalid-warning');
+ var $errors = $(errors);
var invalid = h('div.cp-form-invalid-warning');
var $invalid = $(invalid);
if (evOnChange) {
@@ -2245,31 +3138,36 @@ define([
priv = metadataMgr.getPrivateData();
origin = priv.origin;
}
+
+ var gotoQuestion = function (el) {
+ var $el = $(el).closest('.cp-form-block');
+ var number = $el.find('.cp-form-block-question-number').text();
+ var a = h('a', {
+ href: origin + '#' + Messages._getKey('form_invalidQuestion', [number])
+ }, Messages._getKey('form_invalidQuestion', [number]));
+ $(a).click(function (e) {
+ e.preventDefault();
+ if (!$el.is(':visible')) {
+ var pages = $el.closest('.cp-form-page').index();
+ if (APP.refreshPage) { APP.refreshPage(pages + 1); }
+ }
+ $el[0].scrollIntoView();
+ });
+ return h('li', a);
+ };
+
+ // Check invalid inputs
evOnChange.reg(function () {
var $container = $('div.cp-form-creator-content');
var $inputs = $container.find('input:invalid');
if (!$inputs.length) {
- $send.text(update ? Messages.form_update : Messages.form_submit);
+ $send.text(APP.hasAnswered ? Messages.form_update : Messages.form_submit);
return void $invalid.empty();
}
- $send.text(update ? Messages.form_updateWarning : Messages.form_submitWarning);
+ $send.text(APP.hasAnswered ? Messages.form_updateWarning : Messages.form_submitWarning);
var lis = [];
$inputs.each(function (i, el) {
- var $el = $(el).closest('.cp-form-block');
- var number = $el.find('.cp-form-block-question-number').text();
- var a = h('a', {
- href: origin + '#' + Messages._getKey('form_invalidQuestion', [number])
- }, Messages._getKey('form_invalidQuestion', [number]));
- $(a).click(function (e) {
- e.preventDefault();
- if (!$el.is(':visible')) {
- var pages = $el.closest('.cp-form-page').index();
- if (APP.refreshPage) { APP.refreshPage(pages + 1); }
- }
- $el[0].scrollIntoView();
- });
- var li = h('li', a);
- lis.push(li);
+ lis.push(gotoQuestion(el));
});
var list = h('ul', lis);
var content = [
@@ -2278,11 +3176,56 @@ define([
];
$invalid.empty().append(content);
});
+ // Check empty required questions
+ evOnChange.reg(function () {
+ if (!Array.isArray(APP.formBlocks)) { return; }
+ var form = content.form;
+ var errorBlocks = APP.formBlocks.filter(function (data) {
+ var uid = data.uid;
+ var block = form[uid];
+ if (!data.isEmpty) { return; }
+ if (!block) { return; }
+ if (!block.opts || !block.opts.required) { return; }
+
+ // Don't require questions that are in a hidden section
+ var section = getSectionFromQ(content, uid);
+ if (section.uid) {
+ // Check if section is hidden
+ var sBlock = form[section.uid];
+ var visible = checkCondition(sBlock);
+ if (!visible) { return; }
+ }
+
+
+ var isEmpty = data.isEmpty();
+ var $el = $(data.tag).closest('.cp-form-block');
+ $el.find('.cp-form-required-tag').toggleClass('cp-is-empty', isEmpty);
+ return isEmpty;
+ });
+ if (!errorBlocks.length) {
+ $send.removeAttr('disabled');
+ return void $errors.empty();
+ }
+ $send.attr('disabled', 'disabled');
+ var lis = [];
+ errorBlocks.forEach(function (data) {
+ lis.push(gotoQuestion(data.tag));
+ });
+ var list = h('ul', lis);
+ var divContent = [
+ h('div.alert.alert-danger', [
+ Messages.form_requiredWarning,
+ list
+ ])
+ ];
+ $errors.empty().append(divContent);
+ });
evOnChange.fire(true);
}
return h('div.cp-form-send-container', [
invalid,
+ errors,
cbox ? h('div.cp-form-anon-answer', [
cbox,
anonName
@@ -2295,10 +3238,22 @@ define([
if (!$container.length) { return; } // Not ready
var form = content.form;
+ $('body').find('.flatpickr-calendar').remove();
APP.formBlocks = [];
- if (APP.isClosed && content.answers.privateKey && !APP.isEditor) {
+ var color = content.answers.color || 'nocolor';
+ var $body = $('body');
+ $body[0].classList.forEach(function (cls) {
+ if (/^cp-form-palette/.test(cls)) {
+ $body.removeClass(cls);
+ }
+ });
+ $body.addClass('cp-form-palette-'+color);
+
+ $container.attr('class', 'cp-form-creator-content');
+
+ if (APP.isClosed && content.answers.privateKey && !APP.isEditor && !APP.hasAnswered) {
var sframeChan = framework._.sfCommon.getSframeChannel();
sframeChan.query("Q_FORM_FETCH_ANSWERS", content.answers, function (err, obj) {
var answers = obj && obj.results;
@@ -2334,28 +3289,48 @@ define([
}
- var getFormCreator = function (uid)Â {
+ var getFormCreator = function (uid, inSection)Â {
if (!APP.isEditor) { return; }
var full = !uid;
- var idx = content.order.indexOf(uid);
var addControl = function (type) {
var btn = h('button.btn.btn-secondary', {
- title: full ? '' : Messages['form_type_'+type]
+ title: full ? '' : Messages['form_type_'+type],
+ 'data-type': type
}, [
(TYPES[type] || STATIC_TYPES[type]).icon.cloneNode(),
full ? h('span', Messages['form_type_'+type]) : undefined
]);
$(btn).click(function () {
- var uid = Util.uid();
- content.form[uid] = {
+ // Get the array in which we want to create the new block
+ // and the position in this array
+ var arr = content.order;
+ var idx = content.order.indexOf(uid);
+ if (!full) {
+ if (inSection) {
+ var section = content.form[uid];
+ section.opts = section.opts || STATIC_TYPES.section.opts;
+ arr = section.opts.questions;
+ } else {
+ var obj = getSectionFromQ(content, uid);
+ arr = obj.arr;
+ idx = obj.idx;
+ }
+ }
+
+ var _uid = Util.uid();
+
+ // Make sure we can't create a section inside another one
+ if (type === 'section' && arr !== content.order) { return; }
+
+ content.form[_uid] = {
//q: Messages.form_default,
//opts: opts
type: type,
};
- if (full) {
- content.order.push(uid);
+ if (full || inSection) {
+ arr.push(_uid);
} else {
- content.order.splice(idx, 0, uid);
+ arr.splice(idx, 0, _uid);
}
framework.localChange();
updateForm(framework, content, true);
@@ -2396,19 +3371,29 @@ define([
};
- var updateAddInline = function () {
+ var updateAddInline = APP.updateAddInline = function () {
$container.find('.cp-form-creator-add-inline').remove();
+ // Add before existing question
$container.find('.cp-form-block').each(function (i, el) {
var $el = $(el);
var uid = $el.attr('data-id');
$el.before(getFormCreator(uid));
});
+ // Add to the end of a section
+ $container.find('.cp-form-section-sortable').each(function (i, el) {
+ var $el = $(el);
+ var uid = $el.closest('.cp-form-block').attr('data-id');
+ $el.append(getFormCreator(uid, true));
+ });
};
var elements = [];
var n = 1; // Question number
- content.order.forEach(function (uid) {
+
+ var order = getFullOrder(content);
+
+ order.forEach(function (uid) {
var block = form[uid];
var type = block.type;
var model = TYPES[type] || STATIC_TYPES[type];
@@ -2425,7 +3410,12 @@ define([
name = user.name;
}
- var data = model.get(block.opts, _answers, name, evOnChange);
+ var data = model.get(block.opts, _answers, name, evOnChange, {
+ block: block,
+ content: content,
+ uid: uid,
+ tmp: temp && temp[uid]
+ });
if (!data) { return; }
data.uid = uid;
if (answers && answers[uid] && data.setValue) { data.setValue(answers[uid]); }
@@ -2434,12 +3424,21 @@ define([
elements.push(data);
return;
}
+ if (data.noViewMode && !editable) {
+ elements.push(data);
+ return;
+ }
+ var requiredTag;
+ if (block.opts && block.opts.required) {
+ requiredTag = h('span.cp-form-required-tag', Messages.form_required_on);
+ }
var dragHandle;
var q = h('div.cp-form-block-question', [
h('span.cp-form-block-question-number', (n++)+'.'),
- h('span', block.q || Messages.form_default)
+ h('span.cp-form-block-question-text', block.q || Messages.form_default),
+ requiredTag
]);
// Static blocks don't have questions ("q" is not used) so we can decrement n
if (isStatic) { n--; }
@@ -2448,6 +3447,45 @@ define([
APP.formBlocks.push(data);
+ var previewDiv = h('div.cp-form-preview', Messages.form_preview_button);
+
+ // Required radio displayed only for types that have an "isEmpty" function
+ var requiredDiv;
+ if (APP.isEditor && !isStatic && data.isEmpty) {
+ if (!block.opts) { block.opts = TYPES[type].defaultOpts; }
+ var isRequired = Boolean(block.opts.required);
+ var radioOn = UI.createRadio('cp-form-required-'+uid, 'cp-form-required-on',
+ Messages.form_required_on, isRequired, {
+ input: { value: 1 },
+ });
+ var radioOff = UI.createRadio('cp-form-required-'+uid, 'cp-form-required-off',
+ Messages.form_required_off, !isRequired, {
+ input: { value: 0 },
+ });
+ var radioContainer = h('div.cp-form-required-radio', [
+ h('span', Messages.form_required_answer),
+ radioOff,
+ radioOn
+ ]);
+ requiredDiv = h('div.cp-form-required', [
+ radioContainer
+ ]);
+ $(radioContainer).find('input[type="radio"]').on('change', function() {
+ var val = $('input:radio[name="cp-form-required-'+uid+'"]:checked').val();
+ val = Number(val) || 0;
+ block.opts.required = Boolean(val);
+ framework.localChange();
+ framework._.cpNfInner.chainpad.onSettle(function () {
+ UI.log(Messages.saved);
+ });
+ });
+ }
+
+ if (APP.isEditor && type === "section") {
+ data.editing = true;
+ }
+
+ var changeType;
if (editable) {
// Drag handle
dragHandle = h('span.cp-form-block-drag-handle', [
@@ -2504,7 +3542,7 @@ define([
q = h('div.cp-form-input-block', [inputQ]);
// Delete question
- var edit = h('span');
+ var fakeEdit = h('span');
var del = h('button.btn.btn-danger-alt', [
h('i.fa.fa-trash-o'),
h('span', Messages.form_delete)
@@ -2513,75 +3551,138 @@ define([
classes: 'btn-danger',
new: true
}, function () {
- delete content.form[uid];
- var idx = content.order.indexOf(uid);
- content.order.splice(idx, 1);
+ removeQuestion(content, uid);
$('.cp-form-block[data-id="'+uid+'"]').remove();
framework.localChange();
updateAddInline();
});
+ editButtons = h('div.cp-form-edit-buttons-container', [ fakeEdit, del ]);
+
+ changeType = h('div.cp-form-block-type', [
+ model.icon.cloneNode(),
+ h('span', Messages['form_type_'+type])
+ ]);
+
// Values
if (data.edit) {
- edit = h('button.btn.btn-default.cp-form-edit-button', [
+ var edit = h('button.btn.btn-default.cp-form-edit-button', [
h('i.fa.fa-pencil'),
h('span', Messages.form_editBlock)
]);
+ editButtons = h('div.cp-form-edit-buttons-container', [ edit, del ]);
editContainer = h('div');
- var onSave = function (newOpts) {
- data.editing = false;
- if (!newOpts) { // Cancel edit
+ var onSave = function (newOpts, close) {
+ if (close) { // Cancel edit
+ data.editing = false;
$(editContainer).empty();
- $(editButtons).show();
- $(data.tag).show();
+ var $oldTag = $(data.tag);
+ $(edit).show();
+ $(previewDiv).show();
+ $(requiredDiv).hide();
+
+ $(editButtons).find('.cp-form-preview-button').remove();
+
+ _answers = getBlockAnswers(APP.answers, uid);
+ data = model.get(block.opts, _answers, null, evOnChange);
+ if (!data) { data = {}; }
+ $oldTag.before(data.tag).remove();
+ return;
+ }
+ if (!newOpts) {
+ // invalid options, nothing to save
return;
}
- $(editContainer).empty();
block.opts = newOpts;
framework.localChange();
- var $oldTag = $(data.tag);
- framework._.cpNfInner.chainpad.onSettle(function () {
- $(editButtons).show();
- UI.log(Messages.saved);
- _answers = getBlockAnswers(APP.answers, uid);
- data = model.get(newOpts, _answers, null, evOnChange);
- if (!data) { data = {}; }
- $oldTag.before(data.tag).remove();
- });
};
var onEdit = function (tmp) {
data.editing = true;
+ $(requiredDiv).show();
+ $(previewDiv).hide();
$(data.tag).hide();
$(editContainer).append(data.edit(onSave, tmp, framework));
- $(editButtons).hide();
+
+ $(editContainer).find('.cp-form-preview-button').prependTo(editButtons);
+
+ $(edit).hide();
};
$(edit).click(function () {
onEdit();
});
+ $(requiredDiv).hide();
// If we were editing this field, recover our unsaved changes
if (temp && temp[uid]) {
- setTimeout(function () {
- onEdit(temp[uid]);
+ onEdit(temp[uid]);
+ }
+
+ if (Array.isArray(model.compatible)) {
+ changeType = h('div.cp-form-block-type.editable', [
+ model.icon.cloneNode(),
+ h('span', Messages['form_type_'+type]),
+ h('i.fa.fa-caret-down')
+ ]);
+ $(changeType).click(function () {
+ var name = Util.uid();
+ var els = model.compatible.map(function (data, i) {
+ var text = Messages['form_type_'+data];
+ if (!text) { return; }
+ var radio = UI.createRadio(name, 'cp-form-changetype-'+i,
+ text, data===type, {});
+ $(radio).find('input').data('val', data);
+ return radio;
+ });
+ var tag = h('div.radio-group', els);
+ var changeTypeContent = [
+ APP.answers && Object.keys(APP.answers).length ?
+ h('div.alert.alert-warning', Messages.form_corruptAnswers) :
+ undefined,
+ h('p', Messages.form_changeTypeConfirm),
+ tag
+ ];
+ UI.confirm(changeTypeContent, function (yes) {
+ if (!yes) { return; }
+ var res;
+ els.some(function (el) {
+ var $i = $(el).find('input');
+ if (Util.isChecked($i)) {
+ res = $i.data('val');
+ return true;
+ }
+ });
+ if (res === type || !TYPES[res]) { return; }
+ model = TYPES[res];
+ type = res;
+ if (!data) { data = {}; }
+ block.type = res;
+ framework.localChange();
+ var $oldTag = $(data.tag);
+ framework._.cpNfInner.chainpad.onSettle(function () {
+ $(changeType).find('span').text(Messages['form_type_'+type]);
+ data = model.get(block.opts, _answers, null, evOnChange);
+ $oldTag.before(data.tag).remove();
+ });
+ });
});
}
}
-
- editButtons = h('div.cp-form-edit-buttons-container', [
- edit, del
- ]);
}
var editableCls = editable ? ".editable" : "";
elements.push(h('div.cp-form-block'+editableCls, {
- 'data-id':uid
+ 'data-id':uid,
+ 'data-type':type
}, [
APP.isEditor ? dragHandle : undefined,
+ changeType,
isStatic ? undefined : q,
h('div.cp-form-block-content', [
+ APP.isEditor && !isStatic ? requiredDiv : undefined,
+ APP.isEditor && !isStatic ? previewDiv : undefined,
data.tag,
+ editContainer,
editButtons
]),
- editContainer
]));
});
@@ -2644,12 +3745,76 @@ define([
}
$container.empty().append(_content);
+
+ getSections(content).forEach(function (uid) {
+ var block = content.form[uid];
+ if (!block.opts || !Array.isArray(block.opts.questions)) { return; }
+ var $block = $container.find('.cp-form-block[data-id="'+uid+'"] .cp-form-section-sortable');
+ block.opts.questions.forEach(function (_uid) {
+ $container.find('.cp-form-block[data-id="'+_uid+'"]').appendTo($block);
+ });
+ });
updateAddInline();
+ // Fix cursor in conditions dropdown
+ // If we had a condition dropdown displayed, we're going to make sure
+ // it doesn't move on the screen after the redraw
+ // To do so, we need to adjust the "scrollTop" value saved before redrawing
+ getSections(content).some(function (uid) {
+ if (!temp) { return true; }
+ var block = content.form[uid];
+ if (!block.opts || !Array.isArray(block.opts.questions)) { return; }
+ var $block = $container.find('.cp-form-block[data-id="'+uid+'"] .cp-form-section-sortable');
+
+ if (temp && temp[uid]) {
+ var tmp = temp[uid];
+ var u = tmp.uid;
+ var t = tmp.type;
+ var $c = $block.closest('.cp-form-block').find('.cp-form-condition[data-uid="'+u+'"]');
+ var $b = $c.find('[data-drop="'+t+'"]').find('button');
+ var pos = $b && $b.length && $b[0].getBoundingClientRect().y;
+ // If we know the old position of the button and the new one, we can fix the scroll
+ // accordingly
+ if (typeof(pos) === "number" && typeof(tmp.y) === "number") {
+ var diff = pos - tmp.y;
+ APP.sTop += diff;
+ }
+ return true;
+ }
+ });
+ // Fix cursor with flatpickr
+ APP.formBlocks.some(function (b) {
+ if (!temp) { return true; }
+ var uid = b.uid;
+ var block = form[uid];
+ if (!block) { return; }
+ if (block.type !== "poll") { return; }
+ var opts = block.opts;
+ if (!opts) { return; }
+ if (opts.type !== "time") { return; }
+ var tmp = temp[uid];
+ if (!tmp || !tmp.cursor || !tmp.cursor.flatpickr) { return; }
+ var $block = $container.find('.cp-form-block[data-id="'+uid+'"]');
+ var $i = $block.find('.flatpickr-input[value="'+tmp.cursor.val+'"]');
+ if (!$i.length) { return; }
+ APP.afterScroll = function () {
+ $i[0]._flatpickr.open();
+ delete APP.afterScroll;
+ };
+ var pos = $i && $i.length && $i[0].getBoundingClientRect().y;
+ if (typeof(pos) === "number" && typeof(tmp.cursor.y) === "number") {
+ var diff = pos - tmp.cursor.y;
+ APP.sTop += diff;
+ }
+ return true;
+ });
+
if (editable) {
+ if (APP.mainSortable) { APP.mainSortable.destroy(); }
APP.mainSortable = Sortable.create($container[0], {
+ group: 'nested',
direction: "vertical",
- filter: "input, button, .CodeMirror, .cp-form-type-sort",
+ filter: "input, button, .CodeMirror, .cp-form-type-sort, .cp-form-block-type.editable",
preventOnFilter: false,
draggable: ".cp-form-block",
//forceFallback: true,
@@ -2660,7 +3825,7 @@ define([
store: {
set: function (s) {
content.order = s.toArray();
- framework.localChange();
+ setTimeout(framework.localChange);
updateAddInline();
}
}
@@ -2668,8 +3833,65 @@ define([
return;
}
+ // In view mode, hide sections when conditions aren't met
+ evOnChange.reg(function (reset, save, condition) {
+ if (!reset && !condition) { return; }
+ getSections(content).forEach(function (uid) {
+ var block = content.form[uid];
+ if (block.type !== 'section') { return; }
+ if (!block.opts || !Array.isArray(block.opts.questions) || !block.opts.when) {
+ return;
+ }
+ var show = checkCondition(block);
+ block.opts.questions.forEach(function (_uid) {
+ $container.find('.cp-form-block[data-id="'+_uid+'"]').toggle(show);
+ });
+ });
+ });
+
+ // If the form is already submitted, show an info message
+ if (APP.hasAnswered) {
+ showAnsweredPage(framework, content, answers);
+ $container.prepend(h('div.alert.alert-info',
+ Messages._getKey('form_alreadyAnswered', [
+ new Date(answers._time || APP.lastAnswerTime).toLocaleString()])));
+ }
+
+ if (APP.isClosed) {
+ APP.formBlocks.forEach(function (b) {
+ if (!b.setEditable) { return; }
+ b.setEditable(false);
+ });
+ }
+
// In view mode, add "Submit" and "reset" buttons
- $container.append(makeFormControls(framework, content, Boolean(answers), evOnChange));
+ $container.append(makeFormControls(framework, content, evOnChange));
+
+ // In view mode, tell the user if answers are forced to be anonymous or authenticated
+ var infoTxt;
+ var loggedIn = framework._.sfCommon.isLoggedIn();
+ if (content.answers.makeAnonymous) {
+ infoTxt = Messages.form_anonAnswer;
+ } else if (!content.answers.anonymous && loggedIn && !content.answers.cantEdit) {
+ infoTxt = Messages.form_authAnswer;
+ }
+ if (infoTxt) {
+ $container.prepend(h('div.alert.alert-info', infoTxt));
+ }
+
+ if (!loggedIn && !content.answers.anonymous) {
+ APP.formBlocks.forEach(function (b) {
+ if (!b.setEditable) { return; }
+ b.setEditable(false);
+ });
+ }
+
+ // Embed mode is enforced so we add the title at the top and a CryptPad logo
+ // at the bottom
+ var title = framework._.title.title || framework._.title.defaultTitle;
+ $container.prepend(h('h1.cp-form-view-title', title));
+ $container.append(getLogo());
+
if (!answers) {
$container.find('.cp-reset-button').attr('disabled', 'disabled');
}
@@ -2703,9 +3925,13 @@ define([
var $body = $('body');
var $toolbarContainer = $('#cp-toolbar');
+
var helpMenu = framework._.sfCommon.createHelpMenu(['text', 'pad']);
$toolbarContainer.after(helpMenu.menu);
framework._.toolbar.$drawer.append(helpMenu.button);
+ if (!APP.isEditor && !priv.form_auditorKey) {
+ $(helpMenu.menu).hide();
+ }
var offlineEl = h('div.alert.alert-danger.cp-burn-after-reading', Messages.disconnected);
framework.onEditableChange(function (editable) {
@@ -2733,6 +3959,25 @@ define([
}
var makeFormSettings = function () {
+ var previewBtn = h('button.btn.btn-primary', [
+ h('i.fa.fa-eye'),
+ Messages.form_preview
+ ]);
+ var participantBtn = h('button.btn.btn-primary',[
+ h('i.fa.fa-link'),
+ Messages.form_geturl
+ ]);
+ var preview = h('div.cp-forms-results-participant', [previewBtn, participantBtn]);
+ $(previewBtn).click(function () {
+ sframeChan.event('EV_OPEN_VIEW_URL');
+ });
+ $(participantBtn).click(function () {
+ sframeChan.query('Q_COPY_VIEW_URL', null, function (err, success) {
+ if (success) { return void UI.log(Messages.shareSuccess); }
+ UI.warn(Messages.error);
+ });
+ });
+
// Private / public status
var resultsType = h('div.cp-form-results-type-container');
var $results = $(resultsType);
@@ -2763,23 +4008,30 @@ define([
var responseMsg = h('div.cp-form-response-msg-container');
var $responseMsg = $(responseMsg);
var refreshResponse = function () {
- if (true) { return; } // XXX 4.10.0
$responseMsg.empty();
- Messages.form_updateMsg = "Update response message"; // XXX 4.10.0
- Messages.form_addMsg = "Add response message"; // XXX 4.10.0
- Messages.form_responseMsg = "Add a message that will be displayed in the response page."; // XXX 4.10.0
var text = content.answers.msg ? Messages.form_updateMsg : Messages.form_addMsg;
var btn = h('button.btn.btn-secondary', text);
$(btn).click(function () {
var editor;
if (!APP.responseModal) {
var t = h('textarea');
+ var p = h('p', Messages.form_responseMsg);
var div = h('div', [
- h('p', Messages.form_responseMsg),
- t
+ p,
+ h('div.cp-form-response-modal', t),
]);
- var cm = SFCodeMirror.create("gfm", CMeditor, t);
+ var cm = window.my_cm = SFCodeMirror.create("gfm", CMeditor, t);
editor = APP.responseEditor = cm.editor;
+ var markdownTb = APP.common.createMarkdownToolbar(editor, {
+ embed: function (mt) {
+ editor.focus();
+ editor.replaceSelection($(mt)[0].outerHTML);
+ }
+ });
+ $(markdownTb.toolbar).insertAfter($(p));
+ $(markdownTb.toolbar).show();
+
+ cm.configureTheme(APP.common, function () {});
editor.setOption('lineNumbers', true);
editor.setOption('lineWrapping', true);
editor.setOption('styleActiveLine', true);
@@ -2792,11 +4044,17 @@ define([
});
var buttons = [{
+ className: 'cancel',
+ name: Messages.cancel,
+ onClick: function () {},
+ keys: [27]
+ },
+ {
className: 'primary',
name: Messages.settings_save,
onClick: function () {
var v = editor.getValue();
- content.answers.msg = v.trim(0, 2000); // XXX 4.10.0 max length?
+ content.answers.msg = v.slice(0, 2000); // XXX 4.11.0 max length?
framework.localChange();
framework._.cpNfInner.chainpad.onSettle(function () {
UI.log(Messages.saved);
@@ -2804,11 +4062,6 @@ define([
});
},
//keys: []
- }, {
- className: 'cancel',
- name: Messages.cancel,
- onClick: function () {},
- keys: [27]
}];
APP.responseModal = UI.dialog.customModal(div, { buttons: buttons });
} else {
@@ -2822,11 +4075,32 @@ define([
}
UI.openCustomModal(APP.responseModal);
});
- // $responseMsg.append(btn); // XXX 4.10.0
+ $responseMsg.append(btn);
+ };
+ refreshResponse();
+
+ // Make answers anonymous
+ var anonContainer = h('div.cp-form-anon-container');
+ var $anon = $(anonContainer);
+ var refreshAnon = function () {
+ $anon.empty();
+ var anonymous = content.answers.makeAnonymous;
+ var cbox = UI.createCheckbox('cp-form-make-anon',
+ Messages.form_makeAnon, anonymous, {});
+ var radioContainer = h('div.cp-form-anon-radio', [cbox]);
+ var $r = $(radioContainer).find('input').on('change', function() {
+ var val = Util.isChecked($r);
+ content.answers.makeAnonymous = val;
+ framework.localChange();
+ framework._.cpNfInner.chainpad.onSettle(function () {
+ UI.log(Messages.saved);
+ });
+ });
+ $anon.append(h('div.cp-form-actions', radioContainer));
};
- //refreshResponse();
+ refreshAnon();
- // Allow anonymous answers
+ // Allow guest(anonymous) answers
var privacyContainer = h('div.cp-form-privacy-container');
var $privacy = $(privacyContainer);
var refreshPrivacy = function () {
@@ -2835,12 +4109,10 @@ define([
var radioOn = UI.createRadio('cp-form-privacy', 'cp-form-privacy-on',
Messages.form_anonymous_on, Boolean(anonymous), {
input: { value: 1 },
- mark: { tabindex:1 }
});
var radioOff = UI.createRadio('cp-form-privacy', 'cp-form-privacy-off',
Messages.form_anonymous_off, !anonymous, {
input: { value: 0 },
- mark: { tabindex:1 }
});
var radioContainer = h('div.cp-form-privacy-radio', [radioOn, radioOff]);
$(radioContainer).find('input[type="radio"]').on('change', function() {
@@ -2857,6 +4129,35 @@ define([
};
refreshPrivacy();
+ // Allow responses edition
+ var editableContainer = h('div.cp-form-editable-container');
+ var $editable = $(editableContainer);
+ var refreshEditable = function () {
+ $editable.empty();
+ var editable = !content.answers.cantEdit;
+ var radioOn = UI.createRadio('cp-form-editable', 'cp-form-editable-on',
+ Messages.form_anonymous_on, Boolean(editable), {
+ input: { value: 1 },
+ });
+ var radioOff = UI.createRadio('cp-form-editable', 'cp-form-editable-off',
+ Messages.form_anonymous_off, !editable, {
+ input: { value: 0 },
+ });
+ var radioContainer = h('div.cp-form-editable-radio', [radioOn, radioOff]);
+ $(radioContainer).find('input[type="radio"]').on('change', function() {
+ var val = $('input:radio[name="cp-form-editable"]:checked').val();
+ val = Number(val) || 0;
+ content.answers.cantEdit = !val;
+ framework.localChange();
+ framework._.cpNfInner.chainpad.onSettle(function () {
+ UI.log(Messages.saved);
+ });
+ });
+ $editable.append(h('div.cp-form-status', Messages.form_editable));
+ $editable.append(h('div.cp-form-actions', radioContainer));
+ };
+ refreshEditable();
+
// End date / Closed state
var endDateContainer = h('div.cp-form-status-container');
var $endDate = $(endDateContainer);
@@ -2897,14 +4198,23 @@ define([
});
var save = h('button.btn.btn-primary', Messages.settings_save);
$(save).click(function () {
+ if (datePicker.value === '') {
+ return void refreshEndDate();
+ }
var d = picker.parseDate(datePicker.value);
content.answers.endDate = +d;
framework.localChange();
+ framework._.cpNfInner.chainpad.onSettle(function () {
+ refreshEndDate();
+ });
+ });
+ var cancel = h('button.btn.btn-danger', h('i.fa.fa-times.nomargin'));
+ $(cancel).click(function () {
refreshEndDate();
});
var confirmContent = h('div', [
h('div', Messages.form_setEnd),
- h('div.cp-form-input-block', [datePicker, save]),
+ h('div.cp-form-input-block', [datePicker, save, cancel]),
]);
$button.after(confirmContent);
$button.remove();
@@ -2917,38 +4227,168 @@ define([
};
refreshEndDate();
+ var colorLine1 = h('div');
+ var colorLine2 = h('div');
+ var colorContainer = h('div.cp-form-color-container', [
+ colorLine1,
+ colorLine2
+ ]);
+ var colorTheme = h('div.cp-form-color-theme-container', [
+ h('span', Messages.form_colors),
+ colorContainer
+ ]);
+ var $colors = $(colorContainer);
+ var refreshColorTheme = function () {
+ $(colorLine1).empty();
+ $(colorLine2).empty();
+ var palette = ['nocolor'];
+ for (var i=1; i<=8; i++) { palette.push('color'+i); }
+ var color = content.answers.color || 'nocolor';
+ var selectedColor = color;
+ var currentContainer = colorLine1;
+ palette.forEach(function (_color, i) {
+ if (i === 5) { currentContainer = colorLine2; }
+ var $color = $(h('span.cp-form-palette.fa'));
+ $color.addClass('cp-form-palette-'+(_color || 'nocolor'));
+ if (selectedColor === _color) { $color.addClass('fa-check'); }
+ $color.click(function () {
+ if (_color === selectedColor) { return; }
+ content.answers.color = _color;
+ framework.localChange();
+ framework._.cpNfInner.chainpad.onSettle(function () {
+ UI.log(Messages.saved);
+ selectedColor = _color;
+ $colors.find('.cp-form-palette').removeClass('fa-check');
+ $color.addClass('fa-check');
+
+ var $body = $('body');
+ $body[0].classList.forEach(function (cls) {
+ if (/^cp-form-palette/.test(cls)) {
+ $body.removeClass(cls);
+ }
+ });
+ $body.addClass('cp-form-palette-'+_color);
+ });
+ }).appendTo(currentContainer);
+ });
+ };
+ refreshColorTheme();
evOnChange.reg(refreshPublic);
evOnChange.reg(refreshPrivacy);
+ evOnChange.reg(refreshAnon);
+ evOnChange.reg(refreshEditable);
evOnChange.reg(refreshEndDate);
+ evOnChange.reg(refreshColorTheme);
//evOnChange.reg(refreshResponse);
return [
+ preview,
endDateContainer,
+ anonContainer,
privacyContainer,
+ editableContainer,
resultsType,
- responseMsg
+ responseMsg,
+ colorTheme
];
};
var checkIntegrity = function (getter) {
if (!content.order || !content.form) { return; }
var changed = false;
- content.order.forEach(function (uid) {
- if (!content.form[uid]) {
- var idx = content.order.indexOf(uid);
- content.order.splice(idx, 1);
- changed = true;
- }
+ var deduplicate = [];
+ // Check if the questions in the lists (content.order or sections) exist in
+ // content.form and remove duplicates
+ var check1 = function (arr) {
+ arr.forEach(function (uid) {
+ if (!content.form[uid] || deduplicate.indexOf(uid) !== -1) {
+ var idx = arr.indexOf(uid);
+ arr.splice(idx, 1);
+ changed = true;
+ return;
+ }
+ deduplicate.push(uid);
+ });
+ };
+ check1(content.order);
+ getSections(content).forEach(function (uid) {
+ var block = content.form[uid];
+ if (!block.opts || !Array.isArray(block.opts.questions)) { return; }
+ check1(block.opts.questions);
});
+
+ // Make sure all the questions are displayed in the main list or a section and add
+ // the missing ones
Object.keys(content.form).forEach(function (uid) {
- var idx = content.order.indexOf(uid);
+ var idx = deduplicate.indexOf(uid);
if (idx === -1) {
changed = true;
content.order.push(uid);
}
});
+ // Check if conditions on sections are valid
+ var order = getFullOrder(content);
+ getSections(content).forEach(function (uid) {
+ var block = content.form[uid];
+ if (!block.opts || !Array.isArray(block.opts.when)) { return; }
+ var sectionIdx = order.indexOf(uid);
+ if (sectionIdx === -1) { return; }
+ var available = order.slice(0, sectionIdx);
+ var errors = false;
+ block.opts.when.forEach(function (rules) {
+ if (!Array.isArray(rules)) {
+ var idx = block.opts.when.indexOf(rules);
+ block.opts.when.splice(idx, 1);
+ errors = true;
+ return;
+ }
+ rules.forEach(function (obj) {
+ if (!obj.q) { return; }
+ var idx = available.indexOf(String(obj.q));
+ // If this question doesn't exist before the section, remove the condition
+ if (idx === -1) {
+ var cIdx = rules.indexOf(obj);
+ rules.splice(cIdx, 1);
+ errors = true;
+ return;
+ }
+ });
+ if (!rules.length) {
+ var rIdx = block.opts.when.indexOf(rules);
+ block.opts.when.splice(rIdx, 1);
+ errors = true;
+ }
+ });
+ if (errors) {
+ evCheckConditions.fire(uid);
+ changed = true;
+ }
+ });
+
+ evShowConditions.fire();
+
+ // Migrate opts.values from string to object
+ if (!content.version) {
+ Object.keys(content.form).forEach(function (uid) {
+ var block = content.form[uid];
+ var values = Util.find(block, ['opts', 'values']);
+ if (!Array.isArray(values)) { return; }
+ if (block.opts.type === 'day') { return; }
+ block.opts.values = values.map(function (data) {
+ if (Util.isObject(data)) { return data; }
+ return {
+ uid: Util.uid(),
+ v: data || Messages.form_newOption
+ };
+ });
+ });
+ content.version = 1;
+ changed = true;
+ }
+
+
if (!getter && changed) { framework.localChange(); }
};
@@ -2967,10 +4407,14 @@ define([
var contentContainer = h('div.cp-form-creator-content');
var resultsContainer = h('div.cp-form-creator-results');
+ var answeredContainer = h('div.cp-form-creator-answered', {
+ style: 'display: none;'
+ });
var div = h('div.cp-form-creator-container', [
controlContainer,
contentContainer,
resultsContainer,
+ answeredContainer,
fillerContainer
]);
return div;
@@ -3032,7 +4476,7 @@ define([
UI.alert(content);
};
- framework.onReady(function () {
+ framework.onReady(function (isNew) {
var priv = metadataMgr.getPrivateData();
if (APP.isEditor) {
@@ -3048,15 +4492,18 @@ define([
framework.localChange();
}
if (!content.answers || !content.answers.channel || !content.answers.publicKey || !content.answers.validateKey) {
- content.answers = {
- channel: Hash.createChannelId(),
- publicKey: priv.form_public,
- validateKey: priv.form_answerValidateKey
- };
+ // Don't override other settings (anonymous, makeAnonymous, etc.) from templates
+ content.answers = content.answers || {};
+ content.answers.channel = Hash.createChannelId();
+ content.answers.publicKey = priv.form_public;
+ content.answers.validateKey = priv.form_answerValidateKey;
framework.localChange();
}
checkIntegrity();
}
+ if (isNew && content.answers && typeof(content.answers.anonymous) === "undefined") {
+ content.answers.anonymous = true;
+ }
sframeChan.event('EV_FORM_PIN', {channel: content.answers.channel});
@@ -3072,7 +4519,8 @@ define([
channel: content.answers.channel,
validateKey: content.answers.validateKey,
publicKey: content.answers.publicKey,
- privateKey: key
+ privateKey: key,
+ cantEdit: content.answers.cantEdit
}, function (err, obj) {
var answers = obj && obj.results;
if (answers) { APP.answers = answers; }
@@ -3087,13 +4535,14 @@ define([
}
if (APP.isEditor) {
- addResultsButton(framework, content);
sframeChan.query("Q_FORM_FETCH_ANSWERS", {
channel: content.answers.channel,
validateKey: content.answers.validateKey,
- publicKey: content.answers.publicKey
+ publicKey: content.answers.publicKey,
+ cantEdit: content.answers.cantEdit
}, function (err, obj) {
var answers = obj && obj.results;
+ addResultsButton(framework, content, answers);
if (answers) { APP.answers = answers; }
checkIntegrity(false);
updateForm(framework, content, true);
@@ -3117,6 +4566,7 @@ define([
validateKey: content.answers.validateKey,
publicKey: content.answers.publicKey,
privateKey: content.answers.privateKey,
+ cantEdit: content.answers.cantEdit
}, function (err, obj) {
var answers = obj && obj.results;
if (answers) { APP.answers = answers; }
@@ -3138,15 +4588,14 @@ define([
if (answers) {
var myAnswersObj = answers[curve1] || answers[curve2] || undefined;
if (myAnswersObj) {
+ APP.hasAnswered = true;
myAnswers = myAnswersObj.msg;
+ myAnswers._time = myAnswersObj.time;
}
}
// If we have a non-anon answer, we can't answer anonymously later
if (answers[curve1]) { APP.cantAnon = true; }
- // Add results button
- if (myAnswers) { addResultsButton(framework, content); }
-
updateForm(framework, content, false, myAnswers);
});
return;
@@ -3171,11 +4620,9 @@ define([
var answers;
if (obj && !obj.error) {
answers = obj;
+ APP.hasAnswered = true;
// If we have a non-anon answer, we can't answer anonymously later
if (!obj._isAnon) { APP.cantAnon = true; }
-
- // Add results button
- if (content.answers.privateKey) { addResultsButton(framework, content); }
}
checkIntegrity(false);
updateForm(framework, content, false, answers);
@@ -3183,14 +4630,42 @@ define([
});
- framework.onContentUpdate(function (newContent) {
- content = newContent;
- evOnChange.fire();
- refreshEndDateBanner();
+ // Only redraw once every 500ms on remote change.
+ // If we try to redraw in the first 500ms following a redraw, we'll
+ // redraw again when the timer allows it. If we call "redrawRemote"
+ // repeatedly, we'll only "redraw" once with the latest content.
+ var _redraw = Util.notAgainForAnother(function (framework, content) {
var answers, temp;
if (!APP.isEditor) { answers = getFormResults(); }
else { temp = getTempFields(); }
updateForm(framework, content, APP.isEditor, answers, temp);
+ }, 500);
+ var redrawTo;
+ var redrawRemote = function () {
+ var $main = $('.cp-form-creator-container');
+ var args = Array.prototype.slice.call(arguments);
+ APP.sTop = $main.scrollTop();
+ var until = _redraw.apply(null, args);
+ if (until) {
+ clearTimeout(redrawTo);
+ redrawTo = setTimeout(function (){
+ APP.sTop = $main.scrollTop();
+ _redraw.apply(null, args);
+ $main.scrollTop(APP.sTop);
+ if (typeof(APP.afterScroll) === "function") { APP.afterScroll(); }
+ }, until+1);
+ return;
+ }
+ // Only restore scroll if we were able to redraw
+ $main.scrollTop(APP.sTop);
+ if (typeof(APP.afterScroll) === "function") { APP.afterScroll(); }
+ };
+ framework.onContentUpdate(function (newContent) {
+ content = newContent;
+ evOnChange.fire();
+ refreshEndDateBanner();
+
+ redrawRemote(framework, content);
});
framework.setContentGetter(function () {
diff --git a/www/form/main.js b/www/form/main.js
index de2c311ef..7204435d2 100644
--- a/www/form/main.js
+++ b/www/form/main.js
@@ -125,7 +125,7 @@ define([
var noDriveAnswered = false;
nThen(function (w) {
require([
- '/bower_components/chainpad-netflux/chainpad-netflux.js',
+ 'chainpad-netflux',
'/common/pinpad.js',
], w(function (_CPNetflux, _Pinpad) {
CPNetflux = _CPNetflux;
@@ -176,7 +176,7 @@ define([
validateKey: keys.secondaryValidateKey,
owners: [myKeys.edPublic],
crypto: crypto,
- //Cache: Utils.Cache // XXX 4.10.0
+ //Cache: Utils.Cache // TODO enable cache for form responses when the cache stops evicting old answers
};
var results = {};
config.onError = function (info) {
@@ -221,6 +221,7 @@ define([
delete results[parsed._proof.key];
}
}
+ if (data.cantEdit && results[senderCurve]) { return; }
results[senderCurve] = {
msg: parsed,
hash: hash,
@@ -266,14 +267,21 @@ define([
if (obj && obj.error) { return void cb(obj); }
var messages = obj.messages;
if (!messages.length) { return void cb(); }
- var res = Utils.Crypto.Mailbox.openOwnSecretLetter(messages[0].msg, {
- validateKey: data.validateKey,
- ephemeral_private: Nacl.util.decodeBase64(answer.curvePrivate),
- my_private: Nacl.util.decodeBase64(myKeys.curvePrivate),
- their_public: Nacl.util.decodeBase64(data.publicKey)
- });
- res.content._isAnon = answer.anonymous;
- cb(JSON.parse(res.content));
+ if (obj.lastKnownHash !== answer.hash) { return void cb(); }
+ try {
+ var res = Utils.Crypto.Mailbox.openOwnSecretLetter(messages[0].msg, {
+ validateKey: data.validateKey,
+ ephemeral_private: Nacl.util.decodeBase64(answer.curvePrivate),
+ my_private: Nacl.util.decodeBase64(myKeys.curvePrivate),
+ their_public: Nacl.util.decodeBase64(data.publicKey)
+ });
+ var parsed = JSON.parse(res.content);
+ parsed._isAnon = answer.anonymous;
+ parsed._time = messages[0].time;
+ cb(parsed);
+ } catch (e) {
+ cb({error: e});
+ }
});
});
diff --git a/www/form/templates.js b/www/form/templates.js
index 6ff3249b8..2aef99c24 100644
--- a/www/form/templates.js
+++ b/www/form/templates.js
@@ -1,17 +1,43 @@
define([
'/customize/messages.js'
], function (Messages)Â {
+ var pollValues = [];
+ var d8 = new Date();
+ d8.setDate(d8.getDate() - d8.getDay() + 7); // set sunday
+ d8.setHours(8);
+ d8.setMinutes(0);
+ d8.setSeconds(0);
+ d8.setMilliseconds(0);
+ var d14 = new Date(d8);
+ d14.setHours(14);
+ [0,1,2].forEach(function (el) {
+ d8.setDate(d8.getDate() + 1);
+ d14.setDate(d14.getDate() + 1);
+ if (el === 2) {
+ d8.setHours(10);
+ }
+ pollValues.push(+d8);
+ if (el === 2) { return; }
+ pollValues.push(+d14);
+ });
return [{
id: 'a',
used: 1,
- name: Messages.form_type_poll,
+ name: Messages.form_template_poll,
content: {
+ answers: {
+ anonymous: true,
+ },
form: {
"1": {
type: 'md'
},
"2": {
- type: 'poll'
+ type: 'poll',
+ opts:Â {
+ type: 'time',
+ values: pollValues
+ }
}
},
order: ["1", "2"]
diff --git a/www/kanban/app-kanban.less b/www/kanban/app-kanban.less
index 69924ef77..79d5a87a3 100644
--- a/www/kanban/app-kanban.less
+++ b/www/kanban/app-kanban.less
@@ -159,6 +159,14 @@
margin-right: 5px;
.tools_unselectable();
cursor: default;
+ &.cp-cursor.cp-tippy-html {
+ .avatar_vars(20px);
+ background-color: var(--red);
+ font-size: @avatar-font-size;
+ &.animal {
+ font-size: @avatar-font-size-animal;
+ }
+ }
}
}
.kanban-item {
diff --git a/www/kanban/inner.js b/www/kanban/inner.js
index 38e933cf1..c3de0e0e8 100644
--- a/www/kanban/inner.js
+++ b/www/kanban/inner.js
@@ -97,16 +97,28 @@ define([
// Tippy
var html = MT.getCursorAvatar(cursor);
- var l = Util.getFirstCharacter(cursor.name || Messages.anonymous);
+ var name = UI.getDisplayName(cursor.name);
+
+ var l; // label?
+ var animal = '';
+ if (cursor.name === Messages.anonymous && typeof(cursor.uid) === 'string') {
+ l = MT.getPseudorandomAnimal(cursor.uid);
+ if (l) {
+ animal = '.animal';
+ }
+ }
+ if (!l) {
+ l = MT.getPrettyInitials(name);
+ }
var text = '';
if (cursor.color) {
- text = 'color:'+getTextColor(cursor.color)+';';
+ text = 'background-color:' + cursor.color + '; color:'+getTextColor(cursor.color)+';';
}
- var avatar = h('span.cp-cursor.cp-tippy-html', {
- style: "background-color: " + (cursor.color || 'red') + ";"+text,
+ var avatar = h('span.cp-cursor.cp-tippy-html' + animal, {
+ style: text,
'data-cptippy-html': true,
- title: html
+ title: html,
}, l);
if (!noClear) {
cursor.clear = function () {
@@ -563,12 +575,12 @@ define([
"12": {
"id": 12,
"title": Messages.kanban_working,
- "item": [3, 4]
+ "item": [],
},
"13": {
"id": 13,
"title": Messages.kanban_done,
- "item": [5, 6]
+ "item": [],
}
},
items: items
@@ -1009,8 +1021,8 @@ define([
var common = framework._.sfCommon;
var $button = common.createButton('toggle', true, {
element: $(container),
- //icon: 'fa-tags', // FIXME
- //text: Messages.fm_tagsName, // FIXME
+ icon: 'fa-tags',
+ text: Messages.fm_tagsName,
}, function () {
$button.toggleClass('cp-toolbar-button-active');
@@ -1295,12 +1307,12 @@ define([
// Add new cursor
var avatar = getAvatar(cursor);
var $item = $('.kanban-item[data-eid="'+cursor.item+'"]');
- var $board = $('.kanban-board[data-id="'+cursor.board+'"]');
if ($item.length) {
remoteCursors[id] = cursor;
$item.find('.cp-kanban-cursors').append(avatar);
return;
}
+ var $board = $('.kanban-board[data-id="'+cursor.board+'"]');
if ($board.length) {
remoteCursors[id] = cursor;
$board.find('header .cp-kanban-cursors').append(avatar);
diff --git a/www/lib/chart/charts.min.css b/www/lib/chart/charts.min.css
deleted file mode 100644
index 322319ec5..000000000
--- a/www/lib/chart/charts.min.css
+++ /dev/null
@@ -1 +0,0 @@
-.charts-css{--color-1:rgba(240,50,50,0.75);--color-2:rgba(255,180,50,0.75);--color-3:rgba(255,220,90,0.75);--color-4:rgba(100,210,80,0.75);--color-5:rgba(90,165,255,0.75);--color-6:rgba(170,90,240,0.75);--color-7:hsla(0,0%,70.6%,0.75);--color-8:hsla(0,0%,43.1%,0.75);--color-9:rgba(170,150,110,0.75);--color-10:rgba(130,50,20,0.75);--chart-bg-color:#f5f5f5;--heading-size:0px;--primary-axis-color:#000;--primary-axis-style:solid;--primary-axis-width:1px;--secondary-axes-color:rgba(0,0,0,0.15);--secondary-axes-style:solid;--secondary-axes-width:1px;--data-axes-color:rgba(0,0,0,0.15);--data-axes-style:solid;--data-axes-width:1px;--legend-border-color:#c8c8c8;position:relative;display:block;width:100%;height:100%;margin:0 auto;padding:0;border:0;-webkit-print-color-adjust:exact;color-adjust:exact}.charts-css,.charts-css *,.charts-css::after,.charts-css ::after,.charts-css::before,.charts-css ::before{-webkit-box-sizing:border-box;box-sizing:border-box}table.charts-css{border-collapse:collapse;border-spacing:0;empty-cells:show;overflow:initial;background-color:transparent}table.charts-css caption,table.charts-css colgroup,table.charts-css tbody,table.charts-css td,table.charts-css th,table.charts-css thead,table.charts-css tr{display:block;margin:0;padding:0;border:0;background-color:transparent}table.charts-css colgroup,table.charts-css tfoot,table.charts-css thead{display:none}ol.charts-css,ul.charts-css{list-style-type:none}ol.charts-css li,ul.charts-css li{margin:0;padding:0;border:0}.charts-css:not(.show-heading) caption{display:none}.charts-css.show-heading{--heading-size:1.5rem}.charts-css.show-heading caption{display:block;width:100%;height:var(--heading-size)}.charts-css.area tbody tr td:nth-of-type(10n+1)::before,.charts-css.bar.multiple tbody tr td:nth-of-type(10n+1),.charts-css.bar tbody tr:nth-of-type(10n+1) td,.charts-css.column.multiple tbody tr td:nth-of-type(10n+1),.charts-css.column tbody tr:nth-of-type(10n+1) td,.charts-css.line tbody tr td:nth-of-type(10n+1)::before{background:var(--color,var(--color-1))}.charts-css.area tbody tr td:nth-of-type(10n+2)::before,.charts-css.bar.multiple tbody tr td:nth-of-type(10n+2),.charts-css.bar tbody tr:nth-of-type(10n+2) td,.charts-css.column.multiple tbody tr td:nth-of-type(10n+2),.charts-css.column tbody tr:nth-of-type(10n+2) td,.charts-css.line tbody tr td:nth-of-type(10n+2)::before{background:var(--color,var(--color-2))}.charts-css.area tbody tr td:nth-of-type(10n+3)::before,.charts-css.bar.multiple tbody tr td:nth-of-type(10n+3),.charts-css.bar tbody tr:nth-of-type(10n+3) td,.charts-css.column.multiple tbody tr td:nth-of-type(10n+3),.charts-css.column tbody tr:nth-of-type(10n+3) td,.charts-css.line tbody tr td:nth-of-type(10n+3)::before{background:var(--color,var(--color-3))}.charts-css.area tbody tr td:nth-of-type(10n+4)::before,.charts-css.bar.multiple tbody tr td:nth-of-type(10n+4),.charts-css.bar tbody tr:nth-of-type(10n+4) td,.charts-css.column.multiple tbody tr td:nth-of-type(10n+4),.charts-css.column tbody tr:nth-of-type(10n+4) td,.charts-css.line tbody tr td:nth-of-type(10n+4)::before{background:var(--color,var(--color-4))}.charts-css.area tbody tr td:nth-of-type(10n+5)::before,.charts-css.bar.multiple tbody tr td:nth-of-type(10n+5),.charts-css.bar tbody tr:nth-of-type(10n+5) td,.charts-css.column.multiple tbody tr td:nth-of-type(10n+5),.charts-css.column tbody tr:nth-of-type(10n+5) td,.charts-css.line tbody tr td:nth-of-type(10n+5)::before{background:var(--color,var(--color-5))}.charts-css.area tbody tr td:nth-of-type(10n+6)::before,.charts-css.bar.multiple tbody tr td:nth-of-type(10n+6),.charts-css.bar tbody tr:nth-of-type(10n+6) td,.charts-css.column.multiple tbody tr td:nth-of-type(10n+6),.charts-css.column tbody tr:nth-of-type(10n+6) td,.charts-css.line tbody tr td:nth-of-type(10n+6)::before{background:var(--color,var(--color-6))}.charts-css.area tbody tr td:nth-of-type(10n+7)::before,.charts-css.bar.multiple tbody tr td:nth-of-type(10n+7),.charts-css.bar tbody tr:nth-of-type(10n+7) td,.charts-css.column.multiple tbody tr td:nth-of-type(10n+7),.charts-css.column tbody tr:nth-of-type(10n+7) td,.charts-css.line tbody tr td:nth-of-type(10n+7)::before{background:var(--color,var(--color-7))}.charts-css.area tbody tr td:nth-of-type(10n+8)::before,.charts-css.bar.multiple tbody tr td:nth-of-type(10n+8),.charts-css.bar tbody tr:nth-of-type(10n+8) td,.charts-css.column.multiple tbody tr td:nth-of-type(10n+8),.charts-css.column tbody tr:nth-of-type(10n+8) td,.charts-css.line tbody tr td:nth-of-type(10n+8)::before{background:var(--color,var(--color-8))}.charts-css.area tbody tr td:nth-of-type(10n+9)::before,.charts-css.bar.multiple tbody tr td:nth-of-type(10n+9),.charts-css.bar tbody tr:nth-of-type(10n+9) td,.charts-css.column.multiple tbody tr td:nth-of-type(10n+9),.charts-css.column tbody tr:nth-of-type(10n+9) td,.charts-css.line tbody tr td:nth-of-type(10n+9)::before{background:var(--color,var(--color-9))}.charts-css.area tbody tr td:nth-of-type(10n+10)::before,.charts-css.bar.multiple tbody tr td:nth-of-type(10n+10),.charts-css.bar tbody tr:nth-of-type(10n+10) td,.charts-css.column.multiple tbody tr td:nth-of-type(10n+10),.charts-css.column tbody tr:nth-of-type(10n+10) td,.charts-css.line tbody tr td:nth-of-type(10n+10)::before{background:var(--color,var(--color-10))}.charts-css.hide-data .data{opacity:0}.charts-css.show-data-on-hover .data{-webkit-transition-duration:.3s;transition-duration:.3s;opacity:0}.charts-css.show-data-on-hover tr:hover .data{-webkit-transition-duration:.3s;transition-duration:.3s;opacity:1}.charts-css.bar:not(.show-labels){--labels-size:0}.charts-css.bar:not(.show-labels) tbody tr th{display:none}.charts-css.bar.show-labels{--labels-size:80px}.charts-css.bar.show-labels tbody tr th{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:var(--labels-align,center);-ms-flex-pack:var(--labels-align,center);justify-content:var(--labels-align,center);-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.charts-css.bar.show-labels th.hide-label,.charts-css.bar.show-labels tr.hide-label th{display:none}.charts-css.bar.labels-align-start tbody tr th{-webkit-box-align:var(--labels-align,flex-start);-ms-flex-align:var(--labels-align,flex-start);align-items:var(--labels-align,flex-start)}.charts-css.bar.labels-align-end tbody tr th{-webkit-box-align:var(--labels-align,flex-end);-ms-flex-align:var(--labels-align,flex-end);align-items:var(--labels-align,flex-end)}.charts-css.bar.labels-align-center tbody tr th{-webkit-box-align:var(--labels-align,center);-ms-flex-align:var(--labels-align,center);align-items:var(--labels-align,center)}.charts-css.area:not(.show-labels),.charts-css.column:not(.show-labels),.charts-css.line:not(.show-labels){--labels-size:0}.charts-css.area:not(.show-labels) tbody tr th,.charts-css.column:not(.show-labels) tbody tr th,.charts-css.line:not(.show-labels) tbody tr th{display:none}.charts-css.area.show-labels,.charts-css.column.show-labels,.charts-css.line.show-labels{--labels-size:1.5rem}.charts-css.area.show-labels tbody tr th,.charts-css.column.show-labels tbody tr th,.charts-css.line.show-labels tbody tr th{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:var(--labels-align,center);-ms-flex-pack:var(--labels-align,center);justify-content:var(--labels-align,center);-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.charts-css.area.show-labels th.hide-label,.charts-css.area.show-labels tr.hide-label th,.charts-css.column.show-labels th.hide-label,.charts-css.column.show-labels tr.hide-label th,.charts-css.line.show-labels th.hide-label,.charts-css.line.show-labels tr.hide-label th{display:none}.charts-css.area.labels-align-start tbody tr th,.charts-css.column.labels-align-start tbody tr th,.charts-css.line.labels-align-start tbody tr th{-webkit-box-pack:var(--labels-align,flex-start);-ms-flex-pack:var(--labels-align,flex-start);justify-content:var(--labels-align,flex-start)}.charts-css.area.labels-align-end tbody tr th,.charts-css.column.labels-align-end tbody tr th,.charts-css.line.labels-align-end tbody tr th{-webkit-box-pack:var(--labels-align,flex-end);-ms-flex-pack:var(--labels-align,flex-end);justify-content:var(--labels-align,flex-end)}.charts-css.area.labels-align-center tbody tr th,.charts-css.column.labels-align-center tbody tr th,.charts-css.line.labels-align-center tbody tr th{-webkit-box-pack:var(--labels-align,center);-ms-flex-pack:var(--labels-align,center);justify-content:var(--labels-align,center)}.charts-css.area.show-primary-axis:not(.reverse) tbody tr,.charts-css.column.show-primary-axis:not(.reverse) tbody tr,.charts-css.line.show-primary-axis:not(.reverse) tbody tr{-webkit-border-after:var(--primary-axis-width) var(--primary-axis-style) var(--primary-axis-color);border-block-end:var(--primary-axis-width) var(--primary-axis-style) var(--primary-axis-color)}.charts-css.area.show-primary-axis.reverse tbody tr,.charts-css.column.show-primary-axis.reverse tbody tr,.charts-css.line.show-primary-axis.reverse tbody tr{-webkit-border-before:var(--primary-axis-width) var(--primary-axis-style) var(--primary-axis-color);border-block-start:var(--primary-axis-width) var(--primary-axis-style) var(--primary-axis-color)}.charts-css.area.show-1-secondary-axes:not(.reverse) tbody tr,.charts-css.column.show-1-secondary-axes:not(.reverse) tbody tr,.charts-css.line.show-1-secondary-axes:not(.reverse) tbody tr{background-size:100% 100%;background-image:-webkit-gradient(linear,left top,left bottom,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.area.show-1-secondary-axes.reverse tbody tr,.charts-css.column.show-1-secondary-axes.reverse tbody tr,.charts-css.line.show-1-secondary-axes.reverse tbody tr{background-size:100% 100%;background-image:-webkit-gradient(linear,left bottom,left top,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(0deg,var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.area.show-2-secondary-axes:not(.reverse) tbody tr,.charts-css.column.show-2-secondary-axes:not(.reverse) tbody tr,.charts-css.line.show-2-secondary-axes:not(.reverse) tbody tr{background-size:100% 50%;background-image:-webkit-gradient(linear,left top,left bottom,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.area.show-2-secondary-axes.reverse tbody tr,.charts-css.column.show-2-secondary-axes.reverse tbody tr,.charts-css.line.show-2-secondary-axes.reverse tbody tr{background-size:100% 50%;background-image:-webkit-gradient(linear,left bottom,left top,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(0deg,var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.area.show-3-secondary-axes:not(.reverse) tbody tr,.charts-css.column.show-3-secondary-axes:not(.reverse) tbody tr,.charts-css.line.show-3-secondary-axes:not(.reverse) tbody tr{background-size:100% 33.333333%;background-image:-webkit-gradient(linear,left top,left bottom,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.area.show-3-secondary-axes.reverse tbody tr,.charts-css.column.show-3-secondary-axes.reverse tbody tr,.charts-css.line.show-3-secondary-axes.reverse tbody tr{background-size:100% 33.333333%;background-image:-webkit-gradient(linear,left bottom,left top,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(0deg,var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.area.show-4-secondary-axes:not(.reverse) tbody tr,.charts-css.column.show-4-secondary-axes:not(.reverse) tbody tr,.charts-css.line.show-4-secondary-axes:not(.reverse) tbody tr{background-size:100% 25%;background-image:-webkit-gradient(linear,left top,left bottom,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.area.show-4-secondary-axes.reverse tbody tr,.charts-css.column.show-4-secondary-axes.reverse tbody tr,.charts-css.line.show-4-secondary-axes.reverse tbody tr{background-size:100% 25%;background-image:-webkit-gradient(linear,left bottom,left top,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(0deg,var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.area.show-5-secondary-axes:not(.reverse) tbody tr,.charts-css.column.show-5-secondary-axes:not(.reverse) tbody tr,.charts-css.line.show-5-secondary-axes:not(.reverse) tbody tr{background-size:100% 20%;background-image:-webkit-gradient(linear,left top,left bottom,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.area.show-5-secondary-axes.reverse tbody tr,.charts-css.column.show-5-secondary-axes.reverse tbody tr,.charts-css.line.show-5-secondary-axes.reverse tbody tr{background-size:100% 20%;background-image:-webkit-gradient(linear,left bottom,left top,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(0deg,var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.area.show-6-secondary-axes:not(.reverse) tbody tr,.charts-css.column.show-6-secondary-axes:not(.reverse) tbody tr,.charts-css.line.show-6-secondary-axes:not(.reverse) tbody tr{background-size:100% 16.666667%;background-image:-webkit-gradient(linear,left top,left bottom,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.area.show-6-secondary-axes.reverse tbody tr,.charts-css.column.show-6-secondary-axes.reverse tbody tr,.charts-css.line.show-6-secondary-axes.reverse tbody tr{background-size:100% 16.666667%;background-image:-webkit-gradient(linear,left bottom,left top,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(0deg,var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.area.show-7-secondary-axes:not(.reverse) tbody tr,.charts-css.column.show-7-secondary-axes:not(.reverse) tbody tr,.charts-css.line.show-7-secondary-axes:not(.reverse) tbody tr{background-size:100% 14.285714%;background-image:-webkit-gradient(linear,left top,left bottom,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.area.show-7-secondary-axes.reverse tbody tr,.charts-css.column.show-7-secondary-axes.reverse tbody tr,.charts-css.line.show-7-secondary-axes.reverse tbody tr{background-size:100% 14.285714%;background-image:-webkit-gradient(linear,left bottom,left top,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(0deg,var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.area.show-8-secondary-axes:not(.reverse) tbody tr,.charts-css.column.show-8-secondary-axes:not(.reverse) tbody tr,.charts-css.line.show-8-secondary-axes:not(.reverse) tbody tr{background-size:100% 12.5%;background-image:-webkit-gradient(linear,left top,left bottom,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.area.show-8-secondary-axes.reverse tbody tr,.charts-css.column.show-8-secondary-axes.reverse tbody tr,.charts-css.line.show-8-secondary-axes.reverse tbody tr{background-size:100% 12.5%;background-image:-webkit-gradient(linear,left bottom,left top,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(0deg,var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.area.show-9-secondary-axes:not(.reverse) tbody tr,.charts-css.column.show-9-secondary-axes:not(.reverse) tbody tr,.charts-css.line.show-9-secondary-axes:not(.reverse) tbody tr{background-size:100% 11.111111%;background-image:-webkit-gradient(linear,left top,left bottom,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.area.show-9-secondary-axes.reverse tbody tr,.charts-css.column.show-9-secondary-axes.reverse tbody tr,.charts-css.line.show-9-secondary-axes.reverse tbody tr{background-size:100% 11.111111%;background-image:-webkit-gradient(linear,left bottom,left top,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(0deg,var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.area.show-10-secondary-axes:not(.reverse) tbody tr,.charts-css.column.show-10-secondary-axes:not(.reverse) tbody tr,.charts-css.line.show-10-secondary-axes:not(.reverse) tbody tr{background-size:100% 10%;background-image:-webkit-gradient(linear,left top,left bottom,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.area.show-10-secondary-axes.reverse tbody tr,.charts-css.column.show-10-secondary-axes.reverse tbody tr,.charts-css.line.show-10-secondary-axes.reverse tbody tr{background-size:100% 10%;background-image:-webkit-gradient(linear,left bottom,left top,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(0deg,var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.area.show-data-axes tbody tr,.charts-css.column.show-data-axes tbody tr,.charts-css.line.show-data-axes tbody tr{-webkit-border-end:var(--data-axes-width) var(--data-axes-style) var(--data-axes-color);border-inline-end:var(--data-axes-width) var(--data-axes-style) var(--data-axes-color)}.charts-css.area.show-data-axes.reverse-data tbody tr:last-of-type,.charts-css.area.show-data-axes:not(.reverse-data) tbody tr:first-of-type,.charts-css.column.show-data-axes.reverse-data tbody tr:last-of-type,.charts-css.column.show-data-axes:not(.reverse-data) tbody tr:first-of-type,.charts-css.line.show-data-axes.reverse-data tbody tr:last-of-type,.charts-css.line.show-data-axes:not(.reverse-data) tbody tr:first-of-type{-webkit-border-start:var(--data-axes-width) var(--data-axes-style) var(--data-axes-color);border-inline-start:var(--data-axes-width) var(--data-axes-style) var(--data-axes-color)}.charts-css.area.show-dataset-axes tbody tr td,.charts-css.column.show-dataset-axes tbody tr td,.charts-css.line.show-dataset-axes tbody tr td{-webkit-border-end:var(--data-axes-width) var(--data-axes-style) var(--data-axes-color);border-inline-end:var(--data-axes-width) var(--data-axes-style) var(--data-axes-color)}.charts-css.area.show-dataset-axes.reverse-data tbody tr:last-of-type td,.charts-css.area.show-dataset-axes:not(.reverse-data) tbody tr:first-of-type td,.charts-css.column.show-dataset-axes.reverse-data tbody tr:last-of-type td,.charts-css.column.show-dataset-axes:not(.reverse-data) tbody tr:first-of-type td,.charts-css.line.show-dataset-axes.reverse-data tbody tr:last-of-type td,.charts-css.line.show-dataset-axes:not(.reverse-data) tbody tr:first-of-type td{-webkit-border-start:var(--data-axes-width) var(--data-axes-style) var(--data-axes-color);border-inline-start:var(--data-axes-width) var(--data-axes-style) var(--data-axes-color)}.charts-css.bar.show-primary-axis:not(.reverse) tbody tr{-webkit-border-start:var(--primary-axis-width) var(--primary-axis-style) var(--primary-axis-color);border-inline-start:var(--primary-axis-width) var(--primary-axis-style) var(--primary-axis-color)}.charts-css.bar.show-primary-axis.reverse tbody tr{-webkit-border-end:var(--primary-axis-width) var(--primary-axis-style) var(--primary-axis-color);border-inline-end:var(--primary-axis-width) var(--primary-axis-style) var(--primary-axis-color)}.charts-css.bar.show-1-secondary-axes:not(.reverse) tbody tr{background-size:100% 100%;background-image:-webkit-gradient(linear,right top,left top,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(-90deg,var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.bar.show-1-secondary-axes.reverse tbody tr{background-size:100% 100%;background-image:-webkit-gradient(linear,left top,right top,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(90deg,var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.bar.show-2-secondary-axes:not(.reverse) tbody tr{background-size:50% 100%;background-image:-webkit-gradient(linear,right top,left top,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(-90deg,var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.bar.show-2-secondary-axes.reverse tbody tr{background-size:50% 100%;background-image:-webkit-gradient(linear,left top,right top,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(90deg,var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.bar.show-3-secondary-axes:not(.reverse) tbody tr{background-size:33.333333% 100%;background-image:-webkit-gradient(linear,right top,left top,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(-90deg,var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.bar.show-3-secondary-axes.reverse tbody tr{background-size:33.333333% 100%;background-image:-webkit-gradient(linear,left top,right top,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(90deg,var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.bar.show-4-secondary-axes:not(.reverse) tbody tr{background-size:25% 100%;background-image:-webkit-gradient(linear,right top,left top,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(-90deg,var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.bar.show-4-secondary-axes.reverse tbody tr{background-size:25% 100%;background-image:-webkit-gradient(linear,left top,right top,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(90deg,var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.bar.show-5-secondary-axes:not(.reverse) tbody tr{background-size:20% 100%;background-image:-webkit-gradient(linear,right top,left top,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(-90deg,var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.bar.show-5-secondary-axes.reverse tbody tr{background-size:20% 100%;background-image:-webkit-gradient(linear,left top,right top,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(90deg,var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.bar.show-6-secondary-axes:not(.reverse) tbody tr{background-size:16.666667% 100%;background-image:-webkit-gradient(linear,right top,left top,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(-90deg,var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.bar.show-6-secondary-axes.reverse tbody tr{background-size:16.666667% 100%;background-image:-webkit-gradient(linear,left top,right top,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(90deg,var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.bar.show-7-secondary-axes:not(.reverse) tbody tr{background-size:14.285714% 100%;background-image:-webkit-gradient(linear,right top,left top,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(-90deg,var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.bar.show-7-secondary-axes.reverse tbody tr{background-size:14.285714% 100%;background-image:-webkit-gradient(linear,left top,right top,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(90deg,var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.bar.show-8-secondary-axes:not(.reverse) tbody tr{background-size:12.5% 100%;background-image:-webkit-gradient(linear,right top,left top,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(-90deg,var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.bar.show-8-secondary-axes.reverse tbody tr{background-size:12.5% 100%;background-image:-webkit-gradient(linear,left top,right top,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(90deg,var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.bar.show-9-secondary-axes:not(.reverse) tbody tr{background-size:11.111111% 100%;background-image:-webkit-gradient(linear,right top,left top,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(-90deg,var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.bar.show-9-secondary-axes.reverse tbody tr{background-size:11.111111% 100%;background-image:-webkit-gradient(linear,left top,right top,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(90deg,var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.bar.show-10-secondary-axes:not(.reverse) tbody tr{background-size:10% 100%;background-image:-webkit-gradient(linear,right top,left top,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(-90deg,var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.bar.show-10-secondary-axes.reverse tbody tr{background-size:10% 100%;background-image:-webkit-gradient(linear,left top,right top,from(var(--secondary-axes-color)),to(transparent));background-image:linear-gradient(90deg,var(--secondary-axes-color) var(--secondary-axes-width),transparent var(--secondary-axes-width))}.charts-css.bar.show-data-axes tbody tr{-webkit-border-after:var(--data-axes-width) var(--data-axes-style) var(--data-axes-color);border-block-end:var(--data-axes-width) var(--data-axes-style) var(--data-axes-color)}.charts-css.bar.show-data-axes.reverse-data tbody tr:last-of-type,.charts-css.bar.show-data-axes:not(.reverse-data) tbody tr:first-of-type{-webkit-border-before:var(--data-axes-width) var(--data-axes-style) var(--data-axes-color);border-block-start:var(--data-axes-width) var(--data-axes-style) var(--data-axes-color)}.charts-css.bar.show-dataset-axes tbody tr td{-webkit-border-after:var(--data-axes-width) var(--data-axes-style) var(--data-axes-color);border-block-end:var(--data-axes-width) var(--data-axes-style) var(--data-axes-color)}.charts-css.bar.show-dataset-axes.reverse-data tbody tr:last-of-type td,.charts-css.bar.show-dataset-axes:not(.reverse-data) tbody tr:first-of-type td{-webkit-border-before:var(--data-axes-width) var(--data-axes-style) var(--data-axes-color);border-block-start:var(--data-axes-width) var(--data-axes-style) var(--data-axes-color)}.charts-css.legend{padding:1rem;border:1px solid var(--legend-border-color);list-style:none;font-size:1rem}.charts-css.legend li{line-height:2;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.charts-css.legend li::before{content:"";display:inline-block;vertical-align:middle;-webkit-margin-end:.5rem;margin-inline-end:.5rem;border-width:2px;border-style:solid}.charts-css.legend li:first-child::before{background-color:var(--color-1,transparent);border-color:var(--border-color-1,var(--border-color,#000))}.charts-css.legend li:nth-child(2)::before{background-color:var(--color-2,transparent);border-color:var(--border-color-2,var(--border-color,#000))}.charts-css.legend li:nth-child(3)::before{background-color:var(--color-3,transparent);border-color:var(--border-color-3,var(--border-color,#000))}.charts-css.legend li:nth-child(4)::before{background-color:var(--color-4,transparent);border-color:var(--border-color-4,var(--border-color,#000))}.charts-css.legend li:nth-child(5)::before{background-color:var(--color-5,transparent);border-color:var(--border-color-5,var(--border-color,#000))}.charts-css.legend li:nth-child(6)::before{background-color:var(--color-6,transparent);border-color:var(--border-color-6,var(--border-color,#000))}.charts-css.legend li:nth-child(7)::before{background-color:var(--color-7,transparent);border-color:var(--border-color-7,var(--border-color,#000))}.charts-css.legend li:nth-child(8)::before{background-color:var(--color-8,transparent);border-color:var(--border-color-8,var(--border-color,#000))}.charts-css.legend li:nth-child(9)::before{background-color:var(--color-9,transparent);border-color:var(--border-color-9,var(--border-color,#000))}.charts-css.legend li:nth-child(10)::before{background-color:var(--color-10,transparent);border-color:var(--border-color-10,var(--border-color,#000))}.charts-css:not(.legend-inline){-webkit-box-orient:vertical;-ms-flex-direction:column;flex-direction:column;-ms-flex-wrap:nowrap;flex-wrap:nowrap}.charts-css.legend-inline,.charts-css:not(.legend-inline){display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-direction:normal}.charts-css.legend-inline{-webkit-box-orient:horizontal;-ms-flex-direction:row;flex-direction:row;-ms-flex-wrap:wrap;flex-wrap:wrap}.charts-css.legend-inline li{-webkit-margin-end:1rem;margin-inline-end:1rem}.charts-css.legend-circle li::before{width:1rem;height:1rem;border-radius:50%}.charts-css.legend-ellipse li::before{width:2rem;height:1rem;border-radius:50%}.charts-css.legend-rhombus li::before,.charts-css.legend-square li::before{width:1rem;height:1rem;border-radius:3px}.charts-css.legend-rhombus li::before{-webkit-transform:rotate(45deg) scale(.85);transform:rotate(45deg) scale(.85)}.charts-css.legend-rectangle li::before{width:2rem;height:1rem;border-radius:3px}.charts-css.legend-line li::before{width:2rem;height:3px;border-radius:2px;-webkit-box-sizing:content-box;box-sizing:content-box}.charts-css .tooltip{position:absolute;z-index:1;bottom:50%;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%);width:-webkit-max-content;width:-moz-max-content;width:max-content;padding:5px 10px;border-radius:6px;visibility:hidden;opacity:0;-webkit-transition:opacity .3s;transition:opacity .3s;background-color:#555;color:#fff;text-align:center;font-size:.9rem}.charts-css .tooltip::after{content:"";position:absolute;top:100%;left:50%;margin-left:-5px;border:5px solid transparent;border-top-color:#555}.charts-css td:hover .tooltip{visibility:visible;opacity:1}.charts-css.bar tbody{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:stretch;-ms-flex-align:stretch;align-items:stretch;width:100%;height:calc(100% - var(--heading-size))}.charts-css.bar tbody,.charts-css.bar tbody tr{display:-webkit-box;display:-ms-flexbox;display:flex}.charts-css.bar tbody tr{position:relative;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;-ms-flex-negative:1;flex-shrink:1;-ms-flex-preferred-size:0;flex-basis:0;overflow-wrap:anywhere;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.charts-css.bar tbody tr th{position:absolute;top:0;bottom:0}.charts-css.bar tbody tr td{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;width:calc(100%*var(--size, 1));height:100%;position:relative}.charts-css.bar:not(.reverse) tbody tr{-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start;-webkit-margin-start:var(--labels-size);margin-inline-start:var(--labels-size)}.charts-css.bar:not(.reverse) tbody tr th{left:calc(var(--labels-size)*-1 - var(--primary-axis-width));width:var(--labels-size)}.charts-css.bar:not(.reverse) tbody tr td{-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}.charts-css.bar.reverse tbody tr{-webkit-box-align:end;-ms-flex-align:end;align-items:flex-end;-webkit-margin-end:var(--labels-size);margin-inline-end:var(--labels-size)}.charts-css.bar.reverse tbody tr th{right:calc(var(--labels-size)*-1 - var(--primary-axis-width));width:var(--labels-size)}.charts-css.bar.reverse tbody tr td{-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.charts-css.bar:not(.stacked) tbody tr td{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;-ms-flex-negative:1;flex-shrink:1;-ms-flex-preferred-size:0;flex-basis:0}.charts-css.bar.stacked tbody tr td{-webkit-box-flex:unset;-ms-flex-positive:unset;flex-grow:unset;-ms-flex-negative:unset;flex-shrink:unset;-ms-flex-preferred-size:unset;flex-basis:unset}.charts-css.bar.stacked.reverse-datasets tbody tr{-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}.charts-css.bar:not(.reverse-data) tbody{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.charts-css.bar.reverse-data tbody{-webkit-box-orient:vertical;-webkit-box-direction:reverse;-ms-flex-direction:column-reverse;flex-direction:column-reverse}.charts-css.bar:not(.reverse-datasets):not(.stacked) tbody tr{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.charts-css.bar:not(.reverse-datasets).stacked:not(.reverse) tbody tr{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.charts-css.bar:not(.reverse-datasets).stacked.reverse tbody tr{-webkit-box-orient:horizontal;-webkit-box-direction:reverse;-ms-flex-direction:row-reverse;flex-direction:row-reverse}.charts-css.bar.reverse-datasets:not(.stacked) tbody tr{-webkit-box-orient:vertical;-webkit-box-direction:reverse;-ms-flex-direction:column-reverse;flex-direction:column-reverse}.charts-css.bar.reverse-datasets.stacked:not(.reverse) tbody tr{-webkit-box-orient:horizontal;-webkit-box-direction:reverse;-ms-flex-direction:row-reverse;flex-direction:row-reverse}.charts-css.bar.reverse-datasets.stacked.reverse tbody tr{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.charts-css.bar.data-spacing-1 tbody tr{-webkit-padding-before:1px;padding-block-start:1px;-webkit-padding-after:1px;padding-block-end:1px}.charts-css.bar.data-spacing-2 tbody tr{-webkit-padding-before:2px;padding-block-start:2px;-webkit-padding-after:2px;padding-block-end:2px}.charts-css.bar.data-spacing-3 tbody tr{-webkit-padding-before:3px;padding-block-start:3px;-webkit-padding-after:3px;padding-block-end:3px}.charts-css.bar.data-spacing-4 tbody tr{-webkit-padding-before:4px;padding-block-start:4px;-webkit-padding-after:4px;padding-block-end:4px}.charts-css.bar.data-spacing-5 tbody tr{-webkit-padding-before:5px;padding-block-start:5px;-webkit-padding-after:5px;padding-block-end:5px}.charts-css.bar.data-spacing-6 tbody tr{-webkit-padding-before:6px;padding-block-start:6px;-webkit-padding-after:6px;padding-block-end:6px}.charts-css.bar.data-spacing-7 tbody tr{-webkit-padding-before:7px;padding-block-start:7px;-webkit-padding-after:7px;padding-block-end:7px}.charts-css.bar.data-spacing-8 tbody tr{-webkit-padding-before:8px;padding-block-start:8px;-webkit-padding-after:8px;padding-block-end:8px}.charts-css.bar.data-spacing-9 tbody tr{-webkit-padding-before:9px;padding-block-start:9px;-webkit-padding-after:9px;padding-block-end:9px}.charts-css.bar.data-spacing-10 tbody tr{-webkit-padding-before:10px;padding-block-start:10px;-webkit-padding-after:10px;padding-block-end:10px}.charts-css.bar.data-spacing-11 tbody tr{-webkit-padding-before:11px;padding-block-start:11px;-webkit-padding-after:11px;padding-block-end:11px}.charts-css.bar.data-spacing-12 tbody tr{-webkit-padding-before:12px;padding-block-start:12px;-webkit-padding-after:12px;padding-block-end:12px}.charts-css.bar.data-spacing-13 tbody tr{-webkit-padding-before:13px;padding-block-start:13px;-webkit-padding-after:13px;padding-block-end:13px}.charts-css.bar.data-spacing-14 tbody tr{-webkit-padding-before:14px;padding-block-start:14px;-webkit-padding-after:14px;padding-block-end:14px}.charts-css.bar.data-spacing-15 tbody tr{-webkit-padding-before:15px;padding-block-start:15px;-webkit-padding-after:15px;padding-block-end:15px}.charts-css.bar.data-spacing-16 tbody tr{-webkit-padding-before:16px;padding-block-start:16px;-webkit-padding-after:16px;padding-block-end:16px}.charts-css.bar.data-spacing-17 tbody tr{-webkit-padding-before:17px;padding-block-start:17px;-webkit-padding-after:17px;padding-block-end:17px}.charts-css.bar.data-spacing-18 tbody tr{-webkit-padding-before:18px;padding-block-start:18px;-webkit-padding-after:18px;padding-block-end:18px}.charts-css.bar.data-spacing-19 tbody tr{-webkit-padding-before:19px;padding-block-start:19px;-webkit-padding-after:19px;padding-block-end:19px}.charts-css.bar.data-spacing-20 tbody tr{-webkit-padding-before:20px;padding-block-start:20px;-webkit-padding-after:20px;padding-block-end:20px}.charts-css.bar.datasets-spacing-1 tbody tr td{-webkit-margin-before:1px;margin-block-start:1px;-webkit-margin-after:1px;margin-block-end:1px}.charts-css.bar.datasets-spacing-2 tbody tr td{-webkit-margin-before:2px;margin-block-start:2px;-webkit-margin-after:2px;margin-block-end:2px}.charts-css.bar.datasets-spacing-3 tbody tr td{-webkit-margin-before:3px;margin-block-start:3px;-webkit-margin-after:3px;margin-block-end:3px}.charts-css.bar.datasets-spacing-4 tbody tr td{-webkit-margin-before:4px;margin-block-start:4px;-webkit-margin-after:4px;margin-block-end:4px}.charts-css.bar.datasets-spacing-5 tbody tr td{-webkit-margin-before:5px;margin-block-start:5px;-webkit-margin-after:5px;margin-block-end:5px}.charts-css.bar.datasets-spacing-6 tbody tr td{-webkit-margin-before:6px;margin-block-start:6px;-webkit-margin-after:6px;margin-block-end:6px}.charts-css.bar.datasets-spacing-7 tbody tr td{-webkit-margin-before:7px;margin-block-start:7px;-webkit-margin-after:7px;margin-block-end:7px}.charts-css.bar.datasets-spacing-8 tbody tr td{-webkit-margin-before:8px;margin-block-start:8px;-webkit-margin-after:8px;margin-block-end:8px}.charts-css.bar.datasets-spacing-9 tbody tr td{-webkit-margin-before:9px;margin-block-start:9px;-webkit-margin-after:9px;margin-block-end:9px}.charts-css.bar.datasets-spacing-10 tbody tr td{-webkit-margin-before:10px;margin-block-start:10px;-webkit-margin-after:10px;margin-block-end:10px}.charts-css.bar.datasets-spacing-11 tbody tr td{-webkit-margin-before:11px;margin-block-start:11px;-webkit-margin-after:11px;margin-block-end:11px}.charts-css.bar.datasets-spacing-12 tbody tr td{-webkit-margin-before:12px;margin-block-start:12px;-webkit-margin-after:12px;margin-block-end:12px}.charts-css.bar.datasets-spacing-13 tbody tr td{-webkit-margin-before:13px;margin-block-start:13px;-webkit-margin-after:13px;margin-block-end:13px}.charts-css.bar.datasets-spacing-14 tbody tr td{-webkit-margin-before:14px;margin-block-start:14px;-webkit-margin-after:14px;margin-block-end:14px}.charts-css.bar.datasets-spacing-15 tbody tr td{-webkit-margin-before:15px;margin-block-start:15px;-webkit-margin-after:15px;margin-block-end:15px}.charts-css.bar.datasets-spacing-16 tbody tr td{-webkit-margin-before:16px;margin-block-start:16px;-webkit-margin-after:16px;margin-block-end:16px}.charts-css.bar.datasets-spacing-17 tbody tr td{-webkit-margin-before:17px;margin-block-start:17px;-webkit-margin-after:17px;margin-block-end:17px}.charts-css.bar.datasets-spacing-18 tbody tr td{-webkit-margin-before:18px;margin-block-start:18px;-webkit-margin-after:18px;margin-block-end:18px}.charts-css.bar.datasets-spacing-19 tbody tr td{-webkit-margin-before:19px;margin-block-start:19px;-webkit-margin-after:19px;margin-block-end:19px}.charts-css.bar.datasets-spacing-20 tbody tr td{-webkit-margin-before:20px;margin-block-start:20px;-webkit-margin-after:20px;margin-block-end:20px}.charts-css.column tbody{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:stretch;-ms-flex-align:stretch;align-items:stretch;width:100%;height:calc(100% - var(--heading-size))}.charts-css.column tbody tr{position:relative;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;-ms-flex-negative:1;flex-shrink:1;-ms-flex-preferred-size:0;flex-basis:0;overflow-wrap:anywhere;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.charts-css.column tbody tr th{position:absolute;right:0;left:0}.charts-css.column tbody tr td{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;width:100%;height:calc(100%*var(--size, 1));position:relative}.charts-css.column:not(.reverse) tbody tr{-webkit-box-align:end;-ms-flex-align:end;align-items:flex-end;-webkit-margin-after:var(--labels-size);margin-block-end:var(--labels-size)}.charts-css.column:not(.reverse) tbody tr th{bottom:calc(var(--labels-size)*-1 - var(--primary-axis-width));height:var(--labels-size)}.charts-css.column.reverse tbody tr,.charts-css.column:not(.reverse) tbody tr td{-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start}.charts-css.column.reverse tbody tr{-webkit-margin-before:var(--labels-size);margin-block-start:var(--labels-size)}.charts-css.column.reverse tbody tr th{top:calc(var(--labels-size)*-1 - var(--primary-axis-width));height:var(--labels-size)}.charts-css.column.reverse tbody tr td{-webkit-box-align:end;-ms-flex-align:end;align-items:flex-end}.charts-css.column:not(.stacked) tbody tr td{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;-ms-flex-negative:1;flex-shrink:1;-ms-flex-preferred-size:0;flex-basis:0}.charts-css.column.stacked tbody tr td{-webkit-box-flex:unset;-ms-flex-positive:unset;flex-grow:unset;-ms-flex-negative:unset;flex-shrink:unset;-ms-flex-preferred-size:unset;flex-basis:unset}.charts-css.column.stacked.reverse-datasets tbody tr{-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}.charts-css.column:not(.reverse-data) tbody{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.charts-css.column.reverse-data tbody{-webkit-box-orient:horizontal;-webkit-box-direction:reverse;-ms-flex-direction:row-reverse;flex-direction:row-reverse}.charts-css.column:not(.reverse-datasets):not(.stacked) tbody tr{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.charts-css.column:not(.reverse-datasets).stacked:not(.reverse) tbody tr{-webkit-box-orient:vertical;-webkit-box-direction:reverse;-ms-flex-direction:column-reverse;flex-direction:column-reverse}.charts-css.column:not(.reverse-datasets).stacked.reverse tbody tr{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.charts-css.column.reverse-datasets:not(.stacked) tbody tr{-webkit-box-orient:horizontal;-webkit-box-direction:reverse;-ms-flex-direction:row-reverse;flex-direction:row-reverse}.charts-css.column.reverse-datasets.stacked:not(.reverse) tbody tr{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.charts-css.column.reverse-datasets.stacked.reverse tbody tr{-webkit-box-orient:vertical;-webkit-box-direction:reverse;-ms-flex-direction:column-reverse;flex-direction:column-reverse}.charts-css.column.data-spacing-1 tbody tr{-webkit-padding-start:1px;padding-inline-start:1px;-webkit-padding-end:1px;padding-inline-end:1px}.charts-css.column.data-spacing-2 tbody tr{-webkit-padding-start:2px;padding-inline-start:2px;-webkit-padding-end:2px;padding-inline-end:2px}.charts-css.column.data-spacing-3 tbody tr{-webkit-padding-start:3px;padding-inline-start:3px;-webkit-padding-end:3px;padding-inline-end:3px}.charts-css.column.data-spacing-4 tbody tr{-webkit-padding-start:4px;padding-inline-start:4px;-webkit-padding-end:4px;padding-inline-end:4px}.charts-css.column.data-spacing-5 tbody tr{-webkit-padding-start:5px;padding-inline-start:5px;-webkit-padding-end:5px;padding-inline-end:5px}.charts-css.column.data-spacing-6 tbody tr{-webkit-padding-start:6px;padding-inline-start:6px;-webkit-padding-end:6px;padding-inline-end:6px}.charts-css.column.data-spacing-7 tbody tr{-webkit-padding-start:7px;padding-inline-start:7px;-webkit-padding-end:7px;padding-inline-end:7px}.charts-css.column.data-spacing-8 tbody tr{-webkit-padding-start:8px;padding-inline-start:8px;-webkit-padding-end:8px;padding-inline-end:8px}.charts-css.column.data-spacing-9 tbody tr{-webkit-padding-start:9px;padding-inline-start:9px;-webkit-padding-end:9px;padding-inline-end:9px}.charts-css.column.data-spacing-10 tbody tr{-webkit-padding-start:10px;padding-inline-start:10px;-webkit-padding-end:10px;padding-inline-end:10px}.charts-css.column.data-spacing-11 tbody tr{-webkit-padding-start:11px;padding-inline-start:11px;-webkit-padding-end:11px;padding-inline-end:11px}.charts-css.column.data-spacing-12 tbody tr{-webkit-padding-start:12px;padding-inline-start:12px;-webkit-padding-end:12px;padding-inline-end:12px}.charts-css.column.data-spacing-13 tbody tr{-webkit-padding-start:13px;padding-inline-start:13px;-webkit-padding-end:13px;padding-inline-end:13px}.charts-css.column.data-spacing-14 tbody tr{-webkit-padding-start:14px;padding-inline-start:14px;-webkit-padding-end:14px;padding-inline-end:14px}.charts-css.column.data-spacing-15 tbody tr{-webkit-padding-start:15px;padding-inline-start:15px;-webkit-padding-end:15px;padding-inline-end:15px}.charts-css.column.data-spacing-16 tbody tr{-webkit-padding-start:16px;padding-inline-start:16px;-webkit-padding-end:16px;padding-inline-end:16px}.charts-css.column.data-spacing-17 tbody tr{-webkit-padding-start:17px;padding-inline-start:17px;-webkit-padding-end:17px;padding-inline-end:17px}.charts-css.column.data-spacing-18 tbody tr{-webkit-padding-start:18px;padding-inline-start:18px;-webkit-padding-end:18px;padding-inline-end:18px}.charts-css.column.data-spacing-19 tbody tr{-webkit-padding-start:19px;padding-inline-start:19px;-webkit-padding-end:19px;padding-inline-end:19px}.charts-css.column.data-spacing-20 tbody tr{-webkit-padding-start:20px;padding-inline-start:20px;-webkit-padding-end:20px;padding-inline-end:20px}.charts-css.column.datasets-spacing-1 tbody tr td{-webkit-margin-start:1px;margin-inline-start:1px;-webkit-margin-end:1px;margin-inline-end:1px}.charts-css.column.datasets-spacing-2 tbody tr td{-webkit-margin-start:2px;margin-inline-start:2px;-webkit-margin-end:2px;margin-inline-end:2px}.charts-css.column.datasets-spacing-3 tbody tr td{-webkit-margin-start:3px;margin-inline-start:3px;-webkit-margin-end:3px;margin-inline-end:3px}.charts-css.column.datasets-spacing-4 tbody tr td{-webkit-margin-start:4px;margin-inline-start:4px;-webkit-margin-end:4px;margin-inline-end:4px}.charts-css.column.datasets-spacing-5 tbody tr td{-webkit-margin-start:5px;margin-inline-start:5px;-webkit-margin-end:5px;margin-inline-end:5px}.charts-css.column.datasets-spacing-6 tbody tr td{-webkit-margin-start:6px;margin-inline-start:6px;-webkit-margin-end:6px;margin-inline-end:6px}.charts-css.column.datasets-spacing-7 tbody tr td{-webkit-margin-start:7px;margin-inline-start:7px;-webkit-margin-end:7px;margin-inline-end:7px}.charts-css.column.datasets-spacing-8 tbody tr td{-webkit-margin-start:8px;margin-inline-start:8px;-webkit-margin-end:8px;margin-inline-end:8px}.charts-css.column.datasets-spacing-9 tbody tr td{-webkit-margin-start:9px;margin-inline-start:9px;-webkit-margin-end:9px;margin-inline-end:9px}.charts-css.column.datasets-spacing-10 tbody tr td{-webkit-margin-start:10px;margin-inline-start:10px;-webkit-margin-end:10px;margin-inline-end:10px}.charts-css.column.datasets-spacing-11 tbody tr td{-webkit-margin-start:11px;margin-inline-start:11px;-webkit-margin-end:11px;margin-inline-end:11px}.charts-css.column.datasets-spacing-12 tbody tr td{-webkit-margin-start:12px;margin-inline-start:12px;-webkit-margin-end:12px;margin-inline-end:12px}.charts-css.column.datasets-spacing-13 tbody tr td{-webkit-margin-start:13px;margin-inline-start:13px;-webkit-margin-end:13px;margin-inline-end:13px}.charts-css.column.datasets-spacing-14 tbody tr td{-webkit-margin-start:14px;margin-inline-start:14px;-webkit-margin-end:14px;margin-inline-end:14px}.charts-css.column.datasets-spacing-15 tbody tr td{-webkit-margin-start:15px;margin-inline-start:15px;-webkit-margin-end:15px;margin-inline-end:15px}.charts-css.column.datasets-spacing-16 tbody tr td{-webkit-margin-start:16px;margin-inline-start:16px;-webkit-margin-end:16px;margin-inline-end:16px}.charts-css.column.datasets-spacing-17 tbody tr td{-webkit-margin-start:17px;margin-inline-start:17px;-webkit-margin-end:17px;margin-inline-end:17px}.charts-css.column.datasets-spacing-18 tbody tr td{-webkit-margin-start:18px;margin-inline-start:18px;-webkit-margin-end:18px;margin-inline-end:18px}.charts-css.column.datasets-spacing-19 tbody tr td{-webkit-margin-start:19px;margin-inline-start:19px;-webkit-margin-end:19px;margin-inline-end:19px}.charts-css.column.datasets-spacing-20 tbody tr td{-webkit-margin-start:20px;margin-inline-start:20px;-webkit-margin-end:20px;margin-inline-end:20px}.charts-css.area tbody{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:stretch;-ms-flex-align:stretch;align-items:stretch;width:100%;height:calc(100% - var(--heading-size))}.charts-css.area tbody,.charts-css.area tbody tr{display:-webkit-box;display:-ms-flexbox;display:flex}.charts-css.area tbody tr{position:relative;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;-ms-flex-negative:1;flex-shrink:1;-ms-flex-preferred-size:0;flex-basis:0;overflow-wrap:anywhere;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.charts-css.area tbody tr th{position:absolute;right:0;left:0}.charts-css.area tbody tr td{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-flow:column;flex-flow:column;width:100%;height:100%;position:absolute;top:0;right:0;bottom:0;left:0;z-index:0}.charts-css.area tbody tr td::before{content:"";position:absolute;top:0;right:0;bottom:0;left:0;z-index:-1}.charts-css.area tbody tr td::after{content:"";width:100%}.charts-css.area:not(.reverse) tbody tr{-webkit-box-align:end;-ms-flex-align:end;align-items:flex-end;-webkit-margin-after:var(--labels-size);margin-block-end:var(--labels-size)}.charts-css.area:not(.reverse) tbody tr th{bottom:calc(var(--labels-size)*-1 - var(--primary-axis-width));height:var(--labels-size)}.charts-css.area.reverse tbody tr,.charts-css.area:not(.reverse) tbody tr td{-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start}.charts-css.area.reverse tbody tr{-webkit-margin-before:var(--labels-size);margin-block-start:var(--labels-size)}.charts-css.area.reverse tbody tr th{top:calc(var(--labels-size)*-1 - var(--primary-axis-width));height:var(--labels-size)}.charts-css.area.reverse tbody tr td{-webkit-box-align:end;-ms-flex-align:end;align-items:flex-end}.charts-css.area:not(.reverse-data) tbody{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.charts-css.area.reverse-data tbody{-webkit-box-orient:horizontal;-webkit-box-direction:reverse;-ms-flex-direction:row-reverse;flex-direction:row-reverse}.charts-css.area:not(.reverse-datasets) tbody tr{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.charts-css.area.reverse-datasets tbody tr{-webkit-box-orient:horizontal;-webkit-box-direction:reverse;-ms-flex-direction:row-reverse;flex-direction:row-reverse}.charts-css.area:not(.reverse):not(.reverse-data) tbody tr td{-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end;-webkit-box-align:end;-ms-flex-align:end;align-items:flex-end}.charts-css.area:not(.reverse):not(.reverse-data) tbody tr td::before{-webkit-clip-path:polygon(0 calc(100%*(1 - var(--start, var(--size)))),100% calc(100%*(1 - var(--size))),100% 100%,0 100%);clip-path:polygon(0 calc(100%*(1 - var(--start, var(--size)))),100% calc(100%*(1 - var(--size))),100% 100%,0 100%)}.charts-css.area:not(.reverse):not(.reverse-data) tbody tr td .data{-webkit-transform:translateX(50%);transform:translateX(50%)}.charts-css.area:not(.reverse):not(.reverse-data) tbody tr td::after{height:calc(100%*var(--size))}.charts-css.area:not(.reverse).reverse-data tbody tr td{-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end;-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start}.charts-css.area:not(.reverse).reverse-data tbody tr td::before{-webkit-clip-path:polygon(0 calc(100%*(1 - var(--size))),100% calc(100%*(1 - var(--start, var(--size)))),100% 100%,0 100%);clip-path:polygon(0 calc(100%*(1 - var(--size))),100% calc(100%*(1 - var(--start, var(--size)))),100% 100%,0 100%)}.charts-css.area:not(.reverse).reverse-data tbody tr td .data{-webkit-transform:translateX(-50%);transform:translateX(-50%)}.charts-css.area:not(.reverse).reverse-data tbody tr td::after{height:calc(100%*var(--size))}.charts-css.area.reverse:not(.reverse-data) tbody tr td{-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end;-webkit-box-align:end;-ms-flex-align:end;align-items:flex-end}.charts-css.area.reverse:not(.reverse-data) tbody tr td::before{-webkit-clip-path:polygon(0 0,100% 0,100% calc(100%*var(--size)),0 calc(100%*var(--start, var(--size))));clip-path:polygon(0 0,100% 0,100% calc(100%*var(--size)),0 calc(100%*var(--start, var(--size))))}.charts-css.area.reverse:not(.reverse-data) tbody tr td .data{-webkit-transform:translateX(50%);transform:translateX(50%)}.charts-css.area.reverse:not(.reverse-data) tbody tr td::after{height:calc(100%*(1 - var(--size)))}.charts-css.area.reverse.reverse-data tbody tr td{-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end;-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start}.charts-css.area.reverse.reverse-data tbody tr td::before{-webkit-clip-path:polygon(0 0,100% 0,100% calc(100%*var(--start, var(--size))),0 calc(100%*var(--size)));clip-path:polygon(0 0,100% 0,100% calc(100%*var(--start, var(--size))),0 calc(100%*var(--size)))}.charts-css.area.reverse.reverse-data tbody tr td .data{-webkit-transform:translateX(-50%);transform:translateX(-50%)}.charts-css.area.reverse.reverse-data tbody tr td::after{height:calc(100%*(1 - var(--size)))}.charts-css.area.data-spacing-1 tbody tr td::before,.charts-css.area.datasets-spacing-1 tbody tr td::before{-webkit-margin-start:1px;margin-inline-start:1px;-webkit-margin-end:1px;margin-inline-end:1px}.charts-css.area.data-spacing-2 tbody tr td::before,.charts-css.area.datasets-spacing-2 tbody tr td::before{-webkit-margin-start:2px;margin-inline-start:2px;-webkit-margin-end:2px;margin-inline-end:2px}.charts-css.area.data-spacing-3 tbody tr td::before,.charts-css.area.datasets-spacing-3 tbody tr td::before{-webkit-margin-start:3px;margin-inline-start:3px;-webkit-margin-end:3px;margin-inline-end:3px}.charts-css.area.data-spacing-4 tbody tr td::before,.charts-css.area.datasets-spacing-4 tbody tr td::before{-webkit-margin-start:4px;margin-inline-start:4px;-webkit-margin-end:4px;margin-inline-end:4px}.charts-css.area.data-spacing-5 tbody tr td::before,.charts-css.area.datasets-spacing-5 tbody tr td::before{-webkit-margin-start:5px;margin-inline-start:5px;-webkit-margin-end:5px;margin-inline-end:5px}.charts-css.area.data-spacing-6 tbody tr td::before,.charts-css.area.datasets-spacing-6 tbody tr td::before{-webkit-margin-start:6px;margin-inline-start:6px;-webkit-margin-end:6px;margin-inline-end:6px}.charts-css.area.data-spacing-7 tbody tr td::before,.charts-css.area.datasets-spacing-7 tbody tr td::before{-webkit-margin-start:7px;margin-inline-start:7px;-webkit-margin-end:7px;margin-inline-end:7px}.charts-css.area.data-spacing-8 tbody tr td::before,.charts-css.area.datasets-spacing-8 tbody tr td::before{-webkit-margin-start:8px;margin-inline-start:8px;-webkit-margin-end:8px;margin-inline-end:8px}.charts-css.area.data-spacing-9 tbody tr td::before,.charts-css.area.datasets-spacing-9 tbody tr td::before{-webkit-margin-start:9px;margin-inline-start:9px;-webkit-margin-end:9px;margin-inline-end:9px}.charts-css.area.data-spacing-10 tbody tr td::before,.charts-css.area.datasets-spacing-10 tbody tr td::before{-webkit-margin-start:10px;margin-inline-start:10px;-webkit-margin-end:10px;margin-inline-end:10px}.charts-css.area.data-spacing-11 tbody tr td::before,.charts-css.area.datasets-spacing-11 tbody tr td::before{-webkit-margin-start:11px;margin-inline-start:11px;-webkit-margin-end:11px;margin-inline-end:11px}.charts-css.area.data-spacing-12 tbody tr td::before,.charts-css.area.datasets-spacing-12 tbody tr td::before{-webkit-margin-start:12px;margin-inline-start:12px;-webkit-margin-end:12px;margin-inline-end:12px}.charts-css.area.data-spacing-13 tbody tr td::before,.charts-css.area.datasets-spacing-13 tbody tr td::before{-webkit-margin-start:13px;margin-inline-start:13px;-webkit-margin-end:13px;margin-inline-end:13px}.charts-css.area.data-spacing-14 tbody tr td::before,.charts-css.area.datasets-spacing-14 tbody tr td::before{-webkit-margin-start:14px;margin-inline-start:14px;-webkit-margin-end:14px;margin-inline-end:14px}.charts-css.area.data-spacing-15 tbody tr td::before,.charts-css.area.datasets-spacing-15 tbody tr td::before{-webkit-margin-start:15px;margin-inline-start:15px;-webkit-margin-end:15px;margin-inline-end:15px}.charts-css.area.data-spacing-16 tbody tr td::before,.charts-css.area.datasets-spacing-16 tbody tr td::before{-webkit-margin-start:16px;margin-inline-start:16px;-webkit-margin-end:16px;margin-inline-end:16px}.charts-css.area.data-spacing-17 tbody tr td::before,.charts-css.area.datasets-spacing-17 tbody tr td::before{-webkit-margin-start:17px;margin-inline-start:17px;-webkit-margin-end:17px;margin-inline-end:17px}.charts-css.area.data-spacing-18 tbody tr td::before,.charts-css.area.datasets-spacing-18 tbody tr td::before{-webkit-margin-start:18px;margin-inline-start:18px;-webkit-margin-end:18px;margin-inline-end:18px}.charts-css.area.data-spacing-19 tbody tr td::before,.charts-css.area.datasets-spacing-19 tbody tr td::before{-webkit-margin-start:19px;margin-inline-start:19px;-webkit-margin-end:19px;margin-inline-end:19px}.charts-css.area.data-spacing-20 tbody tr td::before,.charts-css.area.datasets-spacing-20 tbody tr td::before{-webkit-margin-start:20px;margin-inline-start:20px;-webkit-margin-end:20px;margin-inline-end:20px}.charts-css.line{--line-size:3px}.charts-css.line tbody{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:stretch;-ms-flex-align:stretch;align-items:stretch;width:100%;height:calc(100% - var(--heading-size))}.charts-css.line tbody,.charts-css.line tbody tr{display:-webkit-box;display:-ms-flexbox;display:flex}.charts-css.line tbody tr{position:relative;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;-ms-flex-negative:1;flex-shrink:1;-ms-flex-preferred-size:0;flex-basis:0;overflow-wrap:anywhere;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.charts-css.line tbody tr th{position:absolute;right:0;left:0}.charts-css.line tbody tr td{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-flow:column;flex-flow:column;width:100%;height:100%;position:absolute;top:0;right:0;bottom:0;left:0;z-index:0}.charts-css.line tbody tr td::before{content:"";position:absolute;top:0;right:0;bottom:0;left:0;z-index:-1}.charts-css.line tbody tr td::after{content:"";width:100%}.charts-css.line:not(.reverse) tbody tr{-webkit-box-align:end;-ms-flex-align:end;align-items:flex-end;-webkit-margin-after:var(--labels-size);margin-block-end:var(--labels-size)}.charts-css.line:not(.reverse) tbody tr th{bottom:calc(var(--labels-size)*-1 - var(--primary-axis-width));height:var(--labels-size)}.charts-css.line.reverse tbody tr,.charts-css.line:not(.reverse) tbody tr td{-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start}.charts-css.line.reverse tbody tr{-webkit-margin-before:var(--labels-size);margin-block-start:var(--labels-size)}.charts-css.line.reverse tbody tr th{top:calc(var(--labels-size)*-1 - var(--primary-axis-width));height:var(--labels-size)}.charts-css.line.reverse tbody tr td{-webkit-box-align:end;-ms-flex-align:end;align-items:flex-end}.charts-css.line:not(.reverse-data) tbody{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.charts-css.line.reverse-data tbody{-webkit-box-orient:horizontal;-webkit-box-direction:reverse;-ms-flex-direction:row-reverse;flex-direction:row-reverse}.charts-css.line:not(.reverse-datasets) tbody tr{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.charts-css.line.reverse-datasets tbody tr{-webkit-box-orient:horizontal;-webkit-box-direction:reverse;-ms-flex-direction:row-reverse;flex-direction:row-reverse}.charts-css.line:not(.reverse):not(.reverse-data) tbody tr td{-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end;-webkit-box-align:end;-ms-flex-align:end;align-items:flex-end}.charts-css.line:not(.reverse):not(.reverse-data) tbody tr td::before{-webkit-clip-path:polygon(0 calc(100%*(1 - var(--start, var(--size)))),100% calc(100%*(1 - var(--size))),100% calc(100%*(1 - var(--size)) - var(--line-size)),0 calc(100%*(1 - var(--start, var(--size))) - var(--line-size)));clip-path:polygon(0 calc(100%*(1 - var(--start, var(--size)))),100% calc(100%*(1 - var(--size))),100% calc(100%*(1 - var(--size)) - var(--line-size)),0 calc(100%*(1 - var(--start, var(--size))) - var(--line-size)))}.charts-css.line:not(.reverse):not(.reverse-data) tbody tr td .data{-webkit-transform:translateX(50%);transform:translateX(50%)}.charts-css.line:not(.reverse):not(.reverse-data) tbody tr td::after{height:calc(100%*var(--size))}.charts-css.line:not(.reverse).reverse-data tbody tr td{-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end;-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start}.charts-css.line:not(.reverse).reverse-data tbody tr td::before{-webkit-clip-path:polygon(0 calc(100%*(1 - var(--size))),100% calc(100%*(1 - var(--start, var(--size)))),100% calc(100%*(1 - var(--start, var(--size))) - var(--line-size)),0 calc(100%*(1 - var(--size)) - var(--line-size)));clip-path:polygon(0 calc(100%*(1 - var(--size))),100% calc(100%*(1 - var(--start, var(--size)))),100% calc(100%*(1 - var(--start, var(--size))) - var(--line-size)),0 calc(100%*(1 - var(--size)) - var(--line-size)))}.charts-css.line:not(.reverse).reverse-data tbody tr td .data{-webkit-transform:translateX(-50%);transform:translateX(-50%)}.charts-css.line:not(.reverse).reverse-data tbody tr td::after{height:calc(100%*var(--size))}.charts-css.line.reverse:not(.reverse-data) tbody tr td{-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end;-webkit-box-align:end;-ms-flex-align:end;align-items:flex-end}.charts-css.line.reverse:not(.reverse-data) tbody tr td::before{-webkit-clip-path:polygon(0 calc(100%*var(--start, var(--size)) - var(--line-size)),100% calc(100%*var(--size) - var(--line-size)),100% calc(100%*var(--size)),0 calc(100%*var(--start, var(--size))));clip-path:polygon(0 calc(100%*var(--start, var(--size)) - var(--line-size)),100% calc(100%*var(--size) - var(--line-size)),100% calc(100%*var(--size)),0 calc(100%*var(--start, var(--size))))}.charts-css.line.reverse:not(.reverse-data) tbody tr td .data{-webkit-transform:translateX(50%);transform:translateX(50%)}.charts-css.line.reverse:not(.reverse-data) tbody tr td::after{height:calc(100%*(1 - var(--size)))}.charts-css.line.reverse.reverse-data tbody tr td{-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end;-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start}.charts-css.line.reverse.reverse-data tbody tr td::before{-webkit-clip-path:polygon(0 calc(100%*var(--size) - var(--line-size)),100% calc(100%*var(--start, var(--size)) - var(--line-size)),100% calc(100%*var(--start, var(--size))),0 calc(100%*var(--size)));clip-path:polygon(0 calc(100%*var(--size) - var(--line-size)),100% calc(100%*var(--start, var(--size)) - var(--line-size)),100% calc(100%*var(--start, var(--size))),0 calc(100%*var(--size)))}.charts-css.line.reverse.reverse-data tbody tr td .data{-webkit-transform:translateX(-50%);transform:translateX(-50%)}.charts-css.line.reverse.reverse-data tbody tr td::after{height:calc(100%*(1 - var(--size)))}.charts-css.line.data-spacing-1 tbody tr td::before,.charts-css.line.datasets-spacing-1 tbody tr td::before{-webkit-margin-start:1px;margin-inline-start:1px;-webkit-margin-end:1px;margin-inline-end:1px}.charts-css.line.data-spacing-2 tbody tr td::before,.charts-css.line.datasets-spacing-2 tbody tr td::before{-webkit-margin-start:2px;margin-inline-start:2px;-webkit-margin-end:2px;margin-inline-end:2px}.charts-css.line.data-spacing-3 tbody tr td::before,.charts-css.line.datasets-spacing-3 tbody tr td::before{-webkit-margin-start:3px;margin-inline-start:3px;-webkit-margin-end:3px;margin-inline-end:3px}.charts-css.line.data-spacing-4 tbody tr td::before,.charts-css.line.datasets-spacing-4 tbody tr td::before{-webkit-margin-start:4px;margin-inline-start:4px;-webkit-margin-end:4px;margin-inline-end:4px}.charts-css.line.data-spacing-5 tbody tr td::before,.charts-css.line.datasets-spacing-5 tbody tr td::before{-webkit-margin-start:5px;margin-inline-start:5px;-webkit-margin-end:5px;margin-inline-end:5px}.charts-css.line.data-spacing-6 tbody tr td::before,.charts-css.line.datasets-spacing-6 tbody tr td::before{-webkit-margin-start:6px;margin-inline-start:6px;-webkit-margin-end:6px;margin-inline-end:6px}.charts-css.line.data-spacing-7 tbody tr td::before,.charts-css.line.datasets-spacing-7 tbody tr td::before{-webkit-margin-start:7px;margin-inline-start:7px;-webkit-margin-end:7px;margin-inline-end:7px}.charts-css.line.data-spacing-8 tbody tr td::before,.charts-css.line.datasets-spacing-8 tbody tr td::before{-webkit-margin-start:8px;margin-inline-start:8px;-webkit-margin-end:8px;margin-inline-end:8px}.charts-css.line.data-spacing-9 tbody tr td::before,.charts-css.line.datasets-spacing-9 tbody tr td::before{-webkit-margin-start:9px;margin-inline-start:9px;-webkit-margin-end:9px;margin-inline-end:9px}.charts-css.line.data-spacing-10 tbody tr td::before,.charts-css.line.datasets-spacing-10 tbody tr td::before{-webkit-margin-start:10px;margin-inline-start:10px;-webkit-margin-end:10px;margin-inline-end:10px}.charts-css.line.data-spacing-11 tbody tr td::before,.charts-css.line.datasets-spacing-11 tbody tr td::before{-webkit-margin-start:11px;margin-inline-start:11px;-webkit-margin-end:11px;margin-inline-end:11px}.charts-css.line.data-spacing-12 tbody tr td::before,.charts-css.line.datasets-spacing-12 tbody tr td::before{-webkit-margin-start:12px;margin-inline-start:12px;-webkit-margin-end:12px;margin-inline-end:12px}.charts-css.line.data-spacing-13 tbody tr td::before,.charts-css.line.datasets-spacing-13 tbody tr td::before{-webkit-margin-start:13px;margin-inline-start:13px;-webkit-margin-end:13px;margin-inline-end:13px}.charts-css.line.data-spacing-14 tbody tr td::before,.charts-css.line.datasets-spacing-14 tbody tr td::before{-webkit-margin-start:14px;margin-inline-start:14px;-webkit-margin-end:14px;margin-inline-end:14px}.charts-css.line.data-spacing-15 tbody tr td::before,.charts-css.line.datasets-spacing-15 tbody tr td::before{-webkit-margin-start:15px;margin-inline-start:15px;-webkit-margin-end:15px;margin-inline-end:15px}.charts-css.line.data-spacing-16 tbody tr td::before,.charts-css.line.datasets-spacing-16 tbody tr td::before{-webkit-margin-start:16px;margin-inline-start:16px;-webkit-margin-end:16px;margin-inline-end:16px}.charts-css.line.data-spacing-17 tbody tr td::before,.charts-css.line.datasets-spacing-17 tbody tr td::before{-webkit-margin-start:17px;margin-inline-start:17px;-webkit-margin-end:17px;margin-inline-end:17px}.charts-css.line.data-spacing-18 tbody tr td::before,.charts-css.line.datasets-spacing-18 tbody tr td::before{-webkit-margin-start:18px;margin-inline-start:18px;-webkit-margin-end:18px;margin-inline-end:18px}.charts-css.line.data-spacing-19 tbody tr td::before,.charts-css.line.datasets-spacing-19 tbody tr td::before{-webkit-margin-start:19px;margin-inline-start:19px;-webkit-margin-end:19px;margin-inline-end:19px}.charts-css.line.data-spacing-20 tbody tr td::before,.charts-css.line.datasets-spacing-20 tbody tr td::before{-webkit-margin-start:20px;margin-inline-start:20px;-webkit-margin-end:20px;margin-inline-end:20px}.charts-css.radial tbody{display:block;width:100%;height:0;-webkit-padding-after:100%;padding-block-end:100%;border-radius:50%;background-color:var(--chart-bg-color)}.charts-css.radial tbody tr{display:none}.charts-css.pie tbody{display:block;width:100%;height:0;-webkit-padding-after:100%;padding-block-end:100%;border-radius:50%;background-color:var(--chart-bg-color)}.charts-css.pie tbody tr{display:none}.charts-css.donut tbody{display:block;width:100%;height:0;-webkit-padding-after:100%;padding-block-end:100%;border-radius:50%;background-color:var(--chart-bg-color)}.charts-css.donut tbody tr{display:none}.charts-css.donut tbody::after{content:"";position:absolute;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);width:var(--donut-inner-size,50%);height:var(--donut-inner-size,50%);display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;border-radius:50%;background-color:var(--donut-inner-color,#fff)}.charts-css.polar tbody{display:block;width:100%;height:0;-webkit-padding-after:100%;padding-block-end:100%;border-radius:50%;background-color:var(--chart-bg-color)}.charts-css.polar tbody tr{display:none}.charts-css.radar tbody{display:block;width:100%;height:0;-webkit-padding-after:100%;padding-block-end:100%;border-radius:50%;background-color:var(--chart-bg-color)}.charts-css.radar tbody tr{display:none}
\ No newline at end of file
diff --git a/www/pad/comments.js b/www/pad/comments.js
index 6069aa1d0..6280a72bf 100644
--- a/www/pad/comments.js
+++ b/www/pad/comments.js
@@ -43,18 +43,21 @@ define([
var canonicalize = function(t) { return t.replace(/\r\n/g, '\n'); };
- var getAuthorId = function(Env, curve) {
- return Env.common.getAuthorId(Env.comments.authors, curve);
+ var getAuthorId = function(Env, curve, uid) {
+ return Env.common.getAuthorId(Env.comments.authors, curve, uid);
};
- // Return the author ID and add/update the data for registered users
- // Return the username for unregistered users
+ // Return the author ID and add/update user data
+ // associate data with a curvePublic for registered users and the uid otherwise
var updateAuthorData = function(Env, onChange) {
var userData = Env.metadataMgr.getUserData();
+ var myAuthorId;
if (!Env.common.isLoggedIn()) {
- return userData.name;
+ myAuthorId = getAuthorId(Env, undefined, userData.uid);
+ } else {
+ myAuthorId = getAuthorId(Env, userData.curvePublic);
}
- var myAuthorId = getAuthorId(Env, userData.curvePublic);
+
var data = Env.comments.authors[myAuthorId] = Env.comments.authors[myAuthorId] || {};
var old = Sortify(data);
data.name = userData.name;
@@ -62,6 +65,8 @@ define([
data.profile = userData.profile;
data.curvePublic = userData.curvePublic;
data.notifications = userData.notifications;
+ data.uid = userData.uid;
+
if (typeof(onChange) === "function" && Sortify(data) !== old) {
onChange();
}
@@ -82,6 +87,9 @@ define([
var userData = Env.metadataMgr.getUserData();
var privateData = Env.metadataMgr.getPrivateData();
var others = {};
+
+
+ // XXX mentioned users should be excluded from the list of notified recipients to avoid notifying them twice
// Get all the other registered users with a mailbox
thread.m.forEach(function(obj) {
var u = obj.u;
@@ -93,7 +101,8 @@ define([
curvePublic: author.curvePublic,
comment: obj.m,
content: obj.v,
- notifications: author.notifications
+ notifications: author.notifications,
+ uid: author.uid,
};
});
// Send the notification
@@ -146,7 +155,7 @@ define([
'aria-required': true,
contenteditable: true,
});
- Env.common.displayAvatar($(avatar), userData.avatar, name);
+ Env.common.displayAvatar($(avatar), userData.avatar, name, Util.noop, userData.uid);
var cancel = h('button.btn.btn-cancel', {
tabindex: 1
@@ -224,7 +233,9 @@ define([
if (Env.common.isLoggedIn()) {
var authors = {};
- Object.keys((Env.comments && Env.comments.authors) || Â {}).forEach(function(id) {
+ Object.keys((Env.comments && Env.comments.authors) || Â {})
+ .filter(function (id) { return Util.find(Env, ['commments', 'authors', id, 'curvePublic']); })
+ .forEach(function(id) {
var obj = Util.clone(Env.comments.authors[id]);
authors[obj.curvePublic] = obj;
});
@@ -369,7 +380,7 @@ define([
var name = Util.fixHTML(author.name || Messages.anonymous);
var date = new Date(msg.t);
var avatar = h('span.cp-avatar');
- Env.common.displayAvatar($(avatar), author.avatar, name);
+ Env.common.displayAvatar($(avatar), author.avatar, name, Util.noop, author.uid);
if (author.profile) {
$(avatar).click(function(e) {
Env.common.openURL(Hash.hashToHref(author.profile, 'profile'));
@@ -393,7 +404,7 @@ define([
}
cleanMentions($el);
var avatar = h('span.cp-avatar');
- Env.common.displayAvatar($(avatar), avatarUrl, name);
+ Env.common.displayAvatar($(avatar), avatarUrl, name, Util.noop, author.uid);
$el.append([
avatar,
h('span.cp-mentions-name', name)
diff --git a/www/pad/cursor.js b/www/pad/cursor.js
index 42569838f..b0268336b 100644
--- a/www/pad/cursor.js
+++ b/www/pad/cursor.js
@@ -3,7 +3,9 @@ define([
'/common/common-ui-elements.js',
'/common/common-interface.js',
'/bower_components/chainpad/chainpad.dist.js',
-], function ($, UIElements, UI, ChainPad) {
+ '/customize/messages.js',
+ '/common/inner/common-mediatag.js',
+], function ($, UIElements, UI, ChainPad, Messages, MT) {
var Cursor = {};
Cursor.isCursor = function (el) {
@@ -40,8 +42,17 @@ define([
var cursors = {};
+ // FIXME despite the name of this function this doesn't actually render as a tippy tooltip
+ // that means that emojis will use the system font that shows up in native tooltips
+ // so this might be of limited value/aesthetic appeal compared to other apps' cursors
var makeTippy = function (cursor) {
- return cursor.name;
+ if (typeof(cursor.uid) === 'string' && (!cursor.name || cursor.name === Messages.anonymous)) {
+ var animal = MT.getPseudorandomAnimal(cursor.uid);
+ if (animal) {
+ return animal + ' ' + Messages.anonymous;
+ }
+ }
+ return cursor.name || Messages.anonymous;
};
var makeCursor = function (id, cursor) {
diff --git a/www/poll/inner.js b/www/poll/inner.js
index 53faea7e9..a70ddf648 100644
--- a/www/poll/inner.js
+++ b/www/poll/inner.js
@@ -7,7 +7,7 @@ define([
'/common/sframe-common.js',
'/common/common-realtime.js',
'/customize/application_config.js',
- '/bower_components/chainpad-listmap/chainpad-listmap.js',
+ 'chainpad-listmap',
'/poll/render.js',
'/poll/export.js',
'/common/diffMarked.js',
diff --git a/www/profile/inner.js b/www/profile/inner.js
index 11abd6ae8..2d63d2957 100644
--- a/www/profile/inner.js
+++ b/www/profile/inner.js
@@ -1,7 +1,7 @@
define([
'jquery',
'/bower_components/chainpad-crypto/crypto.js',
- '/bower_components/chainpad-listmap/chainpad-listmap.js',
+ 'chainpad-listmap',
'/common/toolbar.js',
'/bower_components/nthen/index.js',
'/common/sframe-common.js',
@@ -348,8 +348,8 @@ define([
if (!val) {
$(' ', {
src: '/customize/images/avatar.png',
- title: Messages.profile_avatar,
- alt: 'Avatar'
+ title: Messages.profile_defaultAlt,
+ alt: Messages.profile_defaultAlt,
}).appendTo($span);
return;
}
diff --git a/www/report/main.js b/www/report/main.js
index f4dd33429..8f39aa232 100644
--- a/www/report/main.js
+++ b/www/report/main.js
@@ -10,7 +10,7 @@ define([
'/common/cryptpad-common.js',
'/common/outer/cache-store.js',
'/common/common-interface.js',
- '/bower_components/chainpad-netflux/chainpad-netflux.js',
+ 'chainpad-netflux',
'/bower_components/chainpad-crypto/crypto.js',
'/common/userObject.js',
'/common/clipboard.js',
diff --git a/www/secureiframe/app-secure.less b/www/secureiframe/app-secure.less
index e1b9a1a16..76956019b 100644
--- a/www/secureiframe/app-secure.less
+++ b/www/secureiframe/app-secure.less
@@ -22,6 +22,8 @@
.usergrid_main();
.forms_main();
+ .fa-shhare-alt:before { content: "\f1e0"; }
+
#cp-filepicker-dialog {
display: none;
.cp-modal {
diff --git a/www/support/app-support.less b/www/support/app-support.less
index 0aa4c6b61..d4719956c 100644
--- a/www/support/app-support.less
+++ b/www/support/app-support.less
@@ -34,5 +34,14 @@
color: @cryptpad_color_link;
text-decoration: underline;
}
+ .alert-info {
+ font-size: 16px;
+ margin-top: 15px;
+ margin-bottom: 15px;
+ }
+ // add some whitespace to improve readability a bit
+ br {
+ margin: 5px;
+ }
}
diff --git a/www/support/inner.js b/www/support/inner.js
index 6d9e5eae8..a193a2f77 100644
--- a/www/support/inner.js
+++ b/www/support/inner.js
@@ -45,6 +45,7 @@ define([
'cp-support-list',
],
'new': [ // Msg.support_cat_new
+ 'cp-support-subscribe',
'cp-support-language',
'cp-support-form',
],
@@ -166,6 +167,26 @@ define([
return $div;
};
+ create['subscribe'] = function () {
+ if (!Pages.areSubscriptionsAllowed()) { return; }
+ var url = Pages.accounts.upgradeURL;
+ var accountsLink = h('a', {
+ href: url,
+ }, Messages.support_premiumLink);
+ $(accountsLink).click(function (ev) {
+ ev.preventDefault();
+ common.openURL(url);
+ });
+
+ return $(h('div.cp-support-subscribe.cp-sidebarlayout-element', [
+ h('div.alert.alert-info', [
+ Messages.support_premiumPriority,
+ ' ',
+ accountsLink,
+ ]),
+ ]));
+ };
+
// Create a new tickets
create['form'] = function () {
var key = 'form';
diff --git a/www/support/ui.js b/www/support/ui.js
index 31555dc64..2f97ec412 100644
--- a/www/support/ui.js
+++ b/www/support/ui.js
@@ -10,14 +10,12 @@ define([
'/customize/messages.js',
], function ($, ApiConfig, h, UI, Hash, Util, Clipboard, UIElements, Messages) {
- var send = function (ctx, id, type, data, dest) {
+ var getDebuggingData = function (ctx, data) {
var common = ctx.common;
- var supportKey = ApiConfig.supportMailbox;
- var supportChannel = Hash.getChannelIdFromKey(supportKey);
var metadataMgr = common.getMetadataMgr();
- var user = metadataMgr.getUserData();
var privateData = metadataMgr.getPrivateData();
-
+ var user = metadataMgr.getUserData();
+ var teams = privateData.teams || {};
data = data ||Â {};
data.sender = {
@@ -34,14 +32,12 @@ define([
data.sender.quota = ctx.pinUsage;
}
- data.id = id;
- data.time = +new Date();
-
- var teams = privateData.teams || {};
if (!ctx.isAdmin) {
data.sender.userAgent = Util.find(window, ['navigator', 'userAgent']);
data.sender.vendor = Util.find(window, ['navigator', 'vendor']);
data.sender.appVersion = Util.find(window, ['navigator', 'appVersion']);
+ data.sender.screenWidth = Util.find(window, ['screen', 'width']);
+ data.sender.screenHeight = Util.find(window, ['screen', 'height']);
data.sender.blockLocation = privateData.blockLocation || '';
data.sender.teams = Object.keys(teams).map(function (key) {
var team = teams[key];
@@ -55,7 +51,25 @@ define([
}
return ret;
}).filter(Boolean);
+ }
+ return data;
+ };
+
+ var send = function (ctx, id, type, data, dest) {
+ var common = ctx.common;
+ var supportKey = ApiConfig.supportMailbox;
+ var supportChannel = Hash.getChannelIdFromKey(supportKey);
+ var metadataMgr = common.getMetadataMgr();
+ var user = metadataMgr.getUserData();
+ var privateData = metadataMgr.getPrivateData();
+
+ data = getDebuggingData(ctx, data);
+
+ data.id = id;
+ data.time = +new Date();
+
+ if (!ctx.isAdmin) {
// "dest" is the recipient that is not the admin support mailbox.
// In the support page, make sure dest is always ourselves.
dest.channel = privateData.support;
@@ -472,6 +486,10 @@ define([
ui.makeCloseMessage = function (content, hash) {
return makeCloseMessage(ctx, content, hash);
};
+ ui.getDebuggingData = function (data) {
+ return getDebuggingData(ctx, data);
+ };
+
return ui;
};
diff --git a/www/teams/inner.js b/www/teams/inner.js
index 1c5bf9411..c498e4876 100644
--- a/www/teams/inner.js
+++ b/www/teams/inner.js
@@ -693,6 +693,8 @@ define([
redrawRoster(common);
});
};
+
+ var getDisplayName = UI.getDisplayName;
var makeMember = function (common, data, me, roster) {
if (!data.curvePublic) { return; }
@@ -701,11 +703,12 @@ define([
return user.role === "OWNER" && user.curvePublic !== me.curvePublic && !user.pendingOwner;
});
+ var displayName = getDisplayName(data.displayName);
// Avatar
var avatar = h('span.cp-avatar.cp-team-member-avatar');
- common.displayAvatar($(avatar), data.avatar, data.displayName);
+ common.displayAvatar($(avatar), data.avatar, displayName, Util.noop, data.uid);
// Name
- var name = h('span.cp-team-member-name', data.displayName);
+ var name = h('span.cp-team-member-name', displayName);
if (data.pendingOwner) {
$(name).append(h('em', {
title: Messages.team_pendingOwnerTitle
@@ -789,7 +792,7 @@ define([
title: Messages.team_rosterKick
});
$(remove).click(function () {
- UI.confirm(Messages._getKey('team_kickConfirm', [Util.fixHTML(data.displayName)]), function (yes) {
+ UI.confirm(Messages._getKey('team_kickConfirm', [Util.fixHTML(displayName)]), function (yes) {
if (!yes) { return; }
APP.module.execCommand('REMOVE_USER', {
pending: data.pending,
@@ -1073,6 +1076,9 @@ define([
metadata: obj
}, function () {
$avatar.empty();
+ // the UI is not supposed to allow admins to remove team names
+ // so we expect that it will be there. Failing that the initials
+ // from the default name will be displayed
common.displayAvatar($avatar, data.url);
});
});
@@ -1093,8 +1099,8 @@ define([
if (!val) {
var $img = $(' ', {
src: '/customize/images/avatar.png',
- title: Messages.profile_avatar,
- alt: 'Avatar'
+ title: Messages.profile_defaultAlt,
+ alt: Messages.profile_defaultAlt,
});
var mt = h('media-tag', $img[0]);
$avatar.append(mt);
@@ -1191,10 +1197,11 @@ define([
var displayUser = function (common, data) {
var avatar = h('span.cp-teams-invite-from-avatar.cp-avatar');
- common.displayAvatar($(avatar), data.avatar, data.displayName);
+ var name = getDisplayName(data.displayName);
+ common.displayAvatar($(avatar), data.avatar, name);
return h('div.cp-teams-invite-from-author', [
avatar,
- h('span.cp-teams-invite-from-name', data.displayName)
+ h('span.cp-teams-invite-from-name', name)
]);
};
@@ -1316,23 +1323,31 @@ define([
});
};
+ var isValidInvitationLinkContent = function (json) {
+ if (!json) { return false; }
+ if (json.error || !Object.keys(json).length) { return false; }
+ if (!json.author) { return false; }
+ return true;
+ };
+
nThen(function (waitFor) {
// Get preview content.
sframeChan.query('Q_ANON_GET_PREVIEW_CONTENT', { seeds: seeds }, waitFor(function (err, json) {
- if (json && (json.error || !Object.keys(json).length)) {
+ if (!isValidInvitationLinkContent(json)) {
$(errorBlock).text(Messages.team_inviteInvalidLinkError).show();
waitFor.abort();
$div.empty();
return;
}
+ // FIXME nothing guarantees that teamName or author.displayName exist in json
$div.empty();
$div.append(h('div.cp-teams-invite-from', [
- Messages.team_inviteFrom || 'From:',
+ Messages.team_inviteFrom,
displayUser(common, json.author)
]));
$div.append(UI.setHTML(h('p.cp-teams-invite-to'),
Messages._getKey('team_inviteFromMsg',
- [Util.fixHTML(json.author.displayName),
+ [Util.fixHTML(getDisplayName(json.author.displayName)),
Util.fixHTML(json.teamName)])));
if (json.message) {
$div.append(h('div.cp-teams-invite-message', json.message));
@@ -1449,10 +1464,10 @@ define([
// Update the name in the user menu
var $displayName = $bar.find('.' + Toolbar.constants.username);
metadataMgr.onChange(function () {
- var name = metadataMgr.getUserData().name || Messages.anonymous;
+ var name = getDisplayName(metadataMgr.getUserData().name);
$displayName.text(name);
});
- $displayName.text(user.name || Messages.anonymous);
+ $displayName.text(getDisplayName(user.name));
// Load the Team module
var onEvent = function (obj) {
diff --git a/www/test/index.html b/www/test/index.html
deleted file mode 100644
index 74f510041..000000000
--- a/www/test/index.html
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
- CryptPad
-
-
-
-
-
-
-
diff --git a/www/test/inner.js b/www/test/inner.js
deleted file mode 100644
index 4b02d51a1..000000000
--- a/www/test/inner.js
+++ /dev/null
@@ -1,68 +0,0 @@
-define([
- '/common/hyperscript.js',
- '/common/inner/charts.js',
-], function (h, Charts) {
- var wrap = function (content) {
- return h('div', {
- style: 'height: 500px; width: 500px; padding: 15px; border: 1px solid #222; margin: 15px;'
- }, content);
- };
-
- var append = function (el) {
- document.body.appendChild(el);
- };
-
- var data = [
- 25, 58, 5, 96, 79,
- 23, 75, 13, 44, 29,
- 65, 80, 30, 47, 22,
- 7, 62, 64, 46, 21,
- 29, 31, 76, 65, 61,
- 78, 58, 12, 90, 98,
- 37, 75, 92, 74, 16,
- 17, 52, 42, 71, 19
- ];
-
-
- append(h('h1', 'Charts'));
- append(h('hr'));
-
- var cell = (function () {
- var i = 0;
-
- return function () {
- var val = data[i++];
- return h('td', {
- style: '--size: ' + (val / 100),
- }, val);
- };
- }());
-
- var multirow = function (n) {
- var cells = [];
- while (n--) {
- cells.push(cell());
- }
- return h('tr', {
- style: 'margin: 15px',
- }, cells);
- };
-
- append(wrap(Charts.table([
- h('tbody', [
- multirow(4),
- multirow(4),
- multirow(4),
- multirow(4),
- ]),
- ], [
- 'charts-css',
- 'bar',
- 'multiple',
- ])));
-
-
- append(h('hr'));
- append(wrap(Charts.columns([ 40, 60, 75, 90, 100])));
- append(wrap(Charts.columns(data.slice(20))));
-});
diff --git a/www/todo/inner.js b/www/todo/inner.js
index 2b69077f3..39cbbf588 100644
--- a/www/todo/inner.js
+++ b/www/todo/inner.js
@@ -1,7 +1,7 @@
define([
'jquery',
'/bower_components/chainpad-crypto/crypto.js',
- '/bower_components/chainpad-listmap/chainpad-listmap.js',
+ 'chainpad-listmap',
'/common/toolbar.js',
'/bower_components/nthen/index.js',
'/common/sframe-common.js',