diff --git a/.jshintignore b/.jshintignore
index 3dce1dfc9..9a7d8b1c7 100644
--- a/.jshintignore
+++ b/.jshintignore
@@ -19,6 +19,7 @@ www/pad/wysiwygarea-plugin.js
www/pad/mediatag-plugin.js
www/pad/mediatag-plugin-dialog.js
www/pad/disable-base64.js
+www/pad/wordcount/
www/kanban/jkanban.js
www/common/jscolor.js
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 714d02d59..12df2ec6d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,43 @@
-# Elasmotherium release notes
+# FalklandWolf release (3.5.0)
+
+## Goals
+
+This release features work that we've been planning for a long time centered around sharing collections of documents in a more granular way.
+
+This is our first release since David Benqué joined our team, so in addition to these team-centric updates we also worked on integrating some UI/UX improvements.
+
+## Update notes
+
+Updating to 3.5.0 from 3.4.0 is simple.
+
+1. stop your server
+2. pull the latest code via git
+3. run `bower update`
+4. restart your server
+
+## Features
+
+* We restyled some elements throughout the platform:
+ * our tooltips have a sleeker flat design
+ * the quota bar which appears in the drive, teams, and settings pages has also been improved
+ * we've begun improving the look and feel of various popup dialogs
+* We've added support for password-change for owned uploaded files and owned shared folders:
+ * changing passwords for encrypted files means that the original file will be removed from the server and a new file will be encrypted with a new key and uploaded to a new location on the server. References to the original file will be broken. This includes links, media-tags embedded within pads, and items in other users' drives or shared folders to which you do not have access.
+ * the process is very similar for shared folders stored in users' CryptDrives, except that users will have the opportunity to enter the new password when they visit the platform.
+* We're very happy to finally introduce the notion of _read-only shared folders_. While we've had the capacity to make shared folders read-only for some time, it was only in the same sense as pads were read-only.
+ * This is to say that while a viewer cannot modify the document, any links to encrypted documents within that document would confer their natural editing rights to viewers, making it possible to accidentally leak access when a single pad was shared.
+ * Our new read-only shared folders encrypt the editing keys for the documents they contain, such that only those with the ability to change the folder structure itself have the inherent capacity to edit the documents contained within. We think this is more intuitive than the alternative, but it took a lot of work to make it happen!
+ * Unfortunately, older shared folders created before this release will already contain the cryptographic keys which confer editing rights. Pads which are added to shared folders from this release onward will have the keys for their editing rights encrypted. We'll offer the ability for owners to migrate these shared folders in an upcoming release once we've added the ability to selectively trim document history.
+* Similarly, we've introduced the notion of _viewers_ in teams. Viewers are listed in the team roster and have the ability to view the contents of the team's drive, but not to edit them or add new documents.
+ * Unfortunately, the notion of viewers is also complicated by the fact that documents added to team drives or shared folders in team drives did not have their editing keys encrypted. The first team member to open the team drive since we've deployed this release will run a migration that will encrypt the keys saved within the team drive, however, the encryption keys will remain in the drive's history until we develop a means of selectively trimming history.
+
+## Bug fixes
+
+* We discovered and fixed some bugs in the serverside code responsible for handling some aspects of file upload related to starting a new upload after having cancelled a previous session.
+* We also identified a regression in Our _slides_ app related to the rendering of ` ` tags, such as you might create with a `****` sequence in the corresponding markdown. This was introduced with some overly broad CSS that was intended to style our notifications page. We've since made the notifications styles more specific such that they can't interfere with other applications.
+* We've become aware of some mysterious behaviour in Firefox that seems to cause some tabs or functionality to reconnect to the server after going offline while other aspects of the platform did not. Until now we've always assumed that users were connected or not, and this partial connection has revealed some bugs in our implementation. Consequently, we've begun adding some measures to detect odd behaviour if it occurs. We expect to have determined the cause of this behaviour and to have proposed a solution by our next release.
+
+# Elasmotherium release (3.4.0)
## Goals
diff --git a/customize.dist/ckeditor-config.js b/customize.dist/ckeditor-config.js
index dc138a558..5c4940c52 100644
--- a/customize.dist/ckeditor-config.js
+++ b/customize.dist/ckeditor-config.js
@@ -10,7 +10,7 @@ CKEDITOR.editorConfig = function( config ) {
// document itself and causes problems when it's sent across the wire and reflected back
config.removePlugins= 'resize,elementspath';
config.resize_enabled= false; //bottom-bar
- config.extraPlugins= 'autolink,colorbutton,colordialog,font,indentblock,justify,mediatag,print,blockbase64,mathjax';
+ config.extraPlugins= 'autolink,colorbutton,colordialog,font,indentblock,justify,mediatag,print,blockbase64,mathjax,wordcount';
config.toolbarGroups= [
// {"name":"clipboard","groups":["clipboard","undo"]},
//{"name":"editing","groups":["find","selection"]},
diff --git a/customize.dist/src/less2/include/alertify.less b/customize.dist/src/less2/include/alertify.less
index 142cc2509..9cd904c45 100644
--- a/customize.dist/src/less2/include/alertify.less
+++ b/customize.dist/src/less2/include/alertify.less
@@ -17,6 +17,7 @@
@alertify-btn-fg: @alertify-fore;
+ @alertify-light-bg: fade(@alertify-fore, 25%);
@alertify-bg: @colortheme_modal-dim;
@alertify-fg: @alertify-fore;
@@ -164,27 +165,29 @@
display: flex;
flex-flow: column;
.alertify-tabs-titles {
- height: 30px;
+ height: 40px;
display: flex;
border-bottom: 1px solid @alertify-fore;
- margin-bottom: 20px;
+ margin-bottom: 10px;
box-sizing: content-box;
span {
font-size: 20px;
- height: 30px;
- line-height: 30px;
+ height: 40px;
+ line-height: 40px;
box-sizing: border-box;
padding: 0 15px;
border-left: 1px solid lighten(@alertify-base, 10%);
border-right: 1px solid lighten(@alertify-base, 10%);
cursor: pointer;
+ &:hover {
+ background-color: @alertify-light-bg;
+ }
}
span.alertify-tabs-active {
background-color: @alertify-fore;
border-left: 1px solid @alertify-fore;
border-right: 1px solid @alertify-fore;
color: @alertify-base;
- font-weight: bold;
cursor: default;
}
}
@@ -206,24 +209,28 @@
}
::placeholder { /* Chrome, Firefox, Opera, Safari 10.1+ */
- color: darken(@alertify-input-fg, 15%);
+ color: @cryptpad_color_grey;
opacity: 1; /* Firefox */
}
:-ms-input-placeholder { /* Internet Explorer 10-11 */
- color: darken(@alertify-input-fg, 15%);
+ color: @cryptpad_color_grey;
}
::-ms-input-placeholder { /* Microsoft Edge */
- color: darken(@alertify-input-fg, 15%);
+ color: @cryptpad_color_grey;
}
input:not(.form-control), textarea {
- background-color: @alertify-input-bg;
- color: @alertify-input-fg;
- border: 0px;
-
+ background-color: @alertify-input-fg;
+ color: @cryptpad_text_col;
+ border: 1px solid @alertify-input-bg;
margin-bottom: 15px;
width: 100%;
font-size: 100%;
padding: @alertify_padding-base;
+ &[readonly] {
+ background-color: @alertify-light-bg;
+ color: @cryptpad_text_col;
+ border-color: @alertify-input-fg;
+ }
}
span.cp-password-container {
@@ -239,6 +246,7 @@
}
}
+
input[type="checkbox"], input[type="radio"] {
width: auto;
padding: 0;
@@ -274,12 +282,16 @@
border-radius: 0;
color: @alertify-btn-fg;
- border: 1px solid @colortheme_alertify-cancel-border;
+ border: 1px solid @alertify-btn-fg;
&.no-margin {
margin: 0;
}
+ &:hover, &:active {
+ background-color: @alertify-light-bg;
+ }
+
&.safe, &.danger {
color: @colortheme_old-base;
white-space: normal;
@@ -313,10 +325,16 @@
}
}
- &:hover, &:active {
- background-color: contrast(@colortheme_modal-bg, darken(@colortheme_alertify-cancel, 10%), lighten(@colortheme_alertify-cancel, 10%));
+ &.cancel {
+ border-color: @colortheme_alertify-cancel-border;
+ color: @colortheme_alertify-cancel-border;
+ &:hover, &:hover {
+ background-color: fade(@colortheme_alertify-cancel-border, 25%);
+ }
}
+
+
&:focus {
//border: 1px dotted @alertify-base;
box-shadow: 0px 0px 5px @colortheme_alertify-primary;
@@ -337,12 +355,15 @@
}
}
- button.btn {
- margin: 6px 4px;
- }
-
nav {
+ padding: @alertify_padding-base;
text-align: right;
+ button {
+ margin: 0px !important;
+ &:not(:last-child) {
+ margin-right: @alertify_padding-base !important;
+ }
+ }
}
}
}
diff --git a/customize.dist/src/less2/include/colortheme.less b/customize.dist/src/less2/include/colortheme.less
index 44719c2d6..23dca6fe8 100644
--- a/customize.dist/src/less2/include/colortheme.less
+++ b/customize.dist/src/less2/include/colortheme.less
@@ -23,7 +23,7 @@
@colortheme_form-bg: @colortheme_logo-2;
@colortheme_form-color: #ffffff;
@colortheme_form-bg-alt: #ffffff;
-@colortheme_form-color-alt: @colortheme_logo-1;
+@colortheme_form-color-alt: @colortheme_logo-2;
@colortheme_form-warning: #f49842;
@colortheme_form-warning-hov: darken(@colortheme_form-warning, 5%);
@@ -56,7 +56,7 @@
@colortheme_alertify-disabled-text: #ffffff;
@colortheme_alertify-disabled-border: #6c757d;
@colortheme_alertify-cancel: @colortheme_modal-bg;
-@colortheme_alertify-cancel-border: #ccc;
+@colortheme_alertify-cancel-border: #949494;
@colortheme_notification-log: fade(@colortheme_logo-1, 90%);
@colortheme_notification-color: #fff;;
diff --git a/customize.dist/src/less2/include/framework.less b/customize.dist/src/less2/include/framework.less
index 685bfcaf5..0eefababb 100644
--- a/customize.dist/src/less2/include/framework.less
+++ b/customize.dist/src/less2/include/framework.less
@@ -15,6 +15,7 @@
@import (reference) "./messenger.less";
@import (reference) "./cursor.less";
@import (reference) "./usergrid.less";
+@import (reference) "./modals-ui-elements.less";
.framework_main(@bg-color, @warn-color, @color) {
--LessLoader_require: LessLoader_currentFile();
@@ -32,6 +33,7 @@
@color: @color
);
.alertify_main();
+ .modals-ui-elements_main();
.corner_main();
.contextmenu_main();
.fileupload_main();
@@ -70,6 +72,7 @@
);
.fileupload_main();
.alertify_main();
+ .modals-ui-elements_main();
.corner_main();
.contextmenu_main();
.tippy_main();
diff --git a/customize.dist/src/less2/include/modal.less b/customize.dist/src/less2/include/modal.less
index 07c533b15..044763c59 100644
--- a/customize.dist/src/less2/include/modal.less
+++ b/customize.dist/src/less2/include/modal.less
@@ -66,6 +66,11 @@
padding: 8px 12px;
margin: 1em;
width: 300px;
+ &[type="text"] {
+ background-color: @colortheme_modal-input-fg;
+ color: @cryptpad_text_col;
+ border: 1px solid @colortheme_modal-input;
+ }
}
.cp-modal-close {
diff --git a/customize.dist/src/less2/include/modals-ui-elements.less b/customize.dist/src/less2/include/modals-ui-elements.less
new file mode 100644
index 000000000..57c9b0a53
--- /dev/null
+++ b/customize.dist/src/less2/include/modals-ui-elements.less
@@ -0,0 +1,26 @@
+@import (reference) "./colortheme-all.less";
+
+.modals-ui-elements_main() {
+ --LessLoader_require: LessLoader_currentFile();
+}
+& {
+ // Share modal
+ .msg.cp-inline-radio-group {
+ .radio-group {
+ display: flex;
+ flex-direction: row;
+ .cp-radio {
+ margin-right: 30px;
+ }
+ }
+ }
+
+ // Properties modal
+ .cp-app-prop {
+ margin-bottom: 10px;
+ }
+
+ .cp-app-prop-content {
+ color: @cryptpad_text_col;
+ }
+}
diff --git a/customize.dist/src/less2/include/password-input.less b/customize.dist/src/less2/include/password-input.less
index a2f2fb044..79824bac7 100644
--- a/customize.dist/src/less2/include/password-input.less
+++ b/customize.dist/src/less2/include/password-input.less
@@ -9,8 +9,27 @@
flex: 1;
min-width: 0;
}
- label, .fa {
- margin-left: 10px;
+ .fa {
+ width: 30px;
+ height: 30px;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ cursor: pointer;
+ &:hover {
+ background-color: rgba(0,0,0,0.1);
+ }
+ }
+ }
+ .cp-password-change-container {
+ display: flex;
+ align-items: center;
+ .cp-password-container {
+ margin-bottom: 0 !important;
+ flex: 1;
+ }
+ button {
+ margin: 0 !important;
}
}
}
diff --git a/customize.dist/src/less2/include/toolbar.less b/customize.dist/src/less2/include/toolbar.less
index ff588ff77..0df5823a0 100644
--- a/customize.dist/src/less2/include/toolbar.less
+++ b/customize.dist/src/less2/include/toolbar.less
@@ -507,7 +507,8 @@
}
}
.cp-toolbar-top {
- @media screen and (max-width: @browser_media-medium-screen) {
+ @media screen and (max-width: @browser_media-medium-screen),
+ screen and (max-height: 500px) {
flex-wrap: wrap;
height: @toolbar_line-height;
.cp-pad-not-pinned {
diff --git a/customize.dist/src/less2/include/usergrid.less b/customize.dist/src/less2/include/usergrid.less
index a2d2c8fc5..38202de86 100644
--- a/customize.dist/src/less2/include/usergrid.less
+++ b/customize.dist/src/less2/include/usergrid.less
@@ -24,7 +24,7 @@
min-width: 0;
margin-bottom: 0 !important;
&::placeholder { /* Chrome, Firefox, Opera, Safari 10.1+ */
- color: @colortheme_alertify-primary-text;
+ color: @cryptpad_color_grey;
opacity: 1; /* Firefox */
}
}
diff --git a/docs/cryptpad-docker.md b/docs/cryptpad-docker.md
index 12018902e..5998dc143 100644
--- a/docs/cryptpad-docker.md
+++ b/docs/cryptpad-docker.md
@@ -2,7 +2,7 @@
Cryptpad includes support for building a Docker image and running it to provide a Cryptpad instance. You can manage the container manually, or let Docker Compose manage it for you.
-A full tutorial is available [on the Cryptpad Github wiki](https://github.com/xwiki-labs/cryptpad/wiki/Docker-(with-Nginx-and-Traefik)). This document provides a brief overview.
+A full tutorial is available [on the Cryptpad Github wiki](https://github.com/xwiki-labs/cryptpad/wiki/Docker). This document provides a brief overview.
## Features
diff --git a/www/common/common-constants.js b/www/common/common-constants.js
index a083ceb90..553665574 100644
--- a/www/common/common-constants.js
+++ b/www/common/common-constants.js
@@ -18,8 +18,6 @@ define(['/customize/application_config.js'], function (AppConfig) {
deprecatedKey: 'deprecated',
MAX_TEAMS_SLOTS: AppConfig.maxTeamsSlots || 3,
MAX_TEAMS_OWNED: AppConfig.maxOwnedTeams || 1,
- // Sub
- plan: 'CryptPad_plan',
// Apps
criticalApps: ['profile', 'settings', 'debug', 'admin', 'support', 'notifications']
};
diff --git a/www/common/common-interface.js b/www/common/common-interface.js
index 72851a8cc..04acc26d8 100644
--- a/www/common/common-interface.js
+++ b/www/common/common-interface.js
@@ -146,7 +146,7 @@ define([
type: 'text',
'class': 'cp-text-input',
}, opt);
- return h('input', attrs);
+ return h('p.msg', h('input', attrs));
};
dialog.nav = function (content) {
@@ -191,6 +191,10 @@ define([
if (!tab.content || !tab.title) { return; }
var content = h('div.alertify-tabs-content', tab.content);
var title = h('span.alertify-tabs-title', tab.title);
+ if (tab.icon) {
+ var icon = h('i', {class: tab.icon});
+ $(title).prepend(' ').prepend(icon);
+ }
$(title).click(function () {
titles.forEach(function (t) { $(t).removeClass('alertify-tabs-active'); });
contents.forEach(function (c) { $(c).removeClass('alertify-tabs-content-active'); });
@@ -344,7 +348,8 @@ define([
if (!b.name || !b.onClick) { return; }
var button = h('button', { tabindex: '1', 'class': b.className || '' }, b.name);
$(button).click(function () {
- b.onClick();
+ var noClose = b.onClick();
+ if (noClose) { return; }
var $modal = $(button).parents('.alertify').first();
if ($modal.length && $modal[0].closeModal) {
$modal[0].closeModal(function () {
@@ -590,9 +595,10 @@ define([
}, opts);
var input = h('input.cp-password-input', attributes);
- var reveal = UI.createCheckbox('cp-password-reveal', Messages.password_show);
+ //var reveal = UI.createCheckbox('cp-password-reveal', Messages.password_show);
var eye = h('span.fa.fa-eye.cp-password-reveal');
+ /*
$(reveal).find('input').on('change', function () {
if($(this).is(':checked')) {
$(input).prop('type', 'text');
@@ -602,26 +608,41 @@ define([
$(input).prop('type', 'password');
$(input).focus();
});
+ */
- $(eye).mousedown(function () {
- $(input).prop('type', 'text');
- $(input).focus();
- }).mouseup(function(){
- $(input).prop('type', 'password');
- $(input).focus();
- }).mouseout(function(){
- $(input).prop('type', 'password');
- $(input).focus();
- });
if (displayEye) {
+ $(eye).mousedown(function () {
+ $(input).prop('type', 'text');
+ $(input).focus();
+ }).mouseup(function(){
+ $(input).prop('type', 'password');
+ $(input).focus();
+ }).mouseout(function(){
+ $(input).prop('type', 'password');
+ $(input).focus();
+ });
+ } else {
+ $(eye).click(function () {
+ if ($(this).hasClass('fa-eye')) {
+ $(input).prop('type', 'text');
+ $(input).focus();
+ $(this).removeClass('fa-eye').addClass('fa-eye-slash');
+ return;
+ }
+ $(input).prop('type', 'password');
+ $(input).focus();
+ $(this).removeClass('fa-eye-slash').addClass('fa-eye');
+ });
+ }
+ /*if (displayEye) {
$(reveal).hide();
} else {
$(eye).hide();
- }
+ }*/
return h('span.cp-password-container', [
input,
- reveal,
+ //reveal,
eye
]);
};
@@ -991,6 +1012,7 @@ define([
if (e.which === 32) {
e.stopPropagation();
e.preventDefault();
+ if ($(input).is(':checked')) { return; }
$(input).prop('checked', !$(input).is(':checked'));
$(input).change();
}
diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js
index 58cadb920..2b8d36e81 100644
--- a/www/common/common-ui-elements.js
+++ b/www/common/common-ui-elements.js
@@ -571,7 +571,7 @@ define([
style: 'flex: 1;'
});
var passwordOk = h('button', Messages.properties_changePasswordButton);
- var changePass = h('span.cp-password-container', [
+ var changePass = h('span.cp-password-change-container', [
newPassword,
passwordOk
]);
@@ -685,29 +685,20 @@ define([
}));
}
+ // XXX problem with the hardcoded ": " here
+ // possibly duplicate translation keys
if (data.tags && Array.isArray(data.tags)) {
- $('', {'for': 'cp-app-prop-tags'}).text(Messages.fm_prop_tagsList).appendTo($d);
- $d.append(UI.dialog.selectable(data.tags.join(', '), {
- id: 'cp-app-prop-tags',
- }));
+ $d.append(h('div.cp-app-prop', [Messages.fm_prop_tagsList, h('br'), h('span.cp-app-prop-content', data.tags.join(', '))]));
}
if (data.ctime) {
- $('', {'for': 'cp-app-prop-ctime'}).text(Messages.fm_creation)
- .appendTo($d);
- $d.append(UI.dialog.selectable(new Date(data.ctime).toLocaleString(), {
- id: 'cp-app-prop-ctime',
- }));
+ $d.append(h('div.cp-app-prop', [Messages.fm_creation, h('br'), h('span.cp-app-prop-content', new Date(data.ctime).toLocaleString())]));
}
if (data.atime) {
- $('', {'for': 'cp-app-prop-atime'}).text(Messages.fm_lastAccess)
- .appendTo($d);
- $d.append(UI.dialog.selectable(new Date(data.atime).toLocaleString(), {
- id: 'cp-app-prop-atime',
- }));
+ $d.append(h('div.cp-app-prop', [Messages.fm_lastAccess, h('br'), h('span.cp-app-prop-content', new Date(data.atime).toLocaleString())]));
}
-
+
if (common.isLoggedIn()) {
// check the size of this file...
var bytes = 0;
@@ -729,15 +720,7 @@ define([
var KB = Util.bytesToKilobytes(bytes);
var formatted = Messages._getKey('formattedKB', [KB]);
- $(' ').appendTo($d);
-
- $('', {
- 'for': 'cp-app-prop-size'
- }).text(Messages.fc_sizeInKilobytes).appendTo($d);
-
- $d.append(UI.dialog.selectable(formatted, {
- id: 'cp-app-prop-size',
- }));
+ $d.append(h('div.cp-app-prop', [Messages.upload_size, h('br'), h('span.cp-app-prop-content', formatted)]));
if (data.sharedFolder && false) {
$('', {'for': 'cp-app-prop-channel'}).text('Channel ID').appendTo($d);
@@ -866,7 +849,7 @@ define([
};
- var createShareWithFriends = function (config, onShare) {
+ var createShareWithFriends = function (config, onShare, linkGetter) {
var common = config.common;
var sframeChan = common.getSframeChannel();
var title = config.title;
@@ -879,7 +862,7 @@ define([
return friends[c].curvePublic.slice(0,8);
});
- var div = h('div.cp-share-column.contains-nav');
+ var div = h('div.contains-nav');
var $div = $(div);
// Replace "copy link" by "share with friends" if at least one friend is selected
// Also create the "share with friends" button if it doesn't exist
@@ -901,7 +884,7 @@ define([
delete friends[curve];
});
- var friendsList = UIElements.getUserGrid(Messages.share_linkFriends, {
+ var friendsList = UIElements.getUserGrid(null, {
common: common,
data: friends,
noFilter: false
@@ -934,11 +917,11 @@ define([
}, refreshButtons);
$div.append(teamsList.div);
- var shareButtons = [{
+ var shareButton = {
className: 'primary cp-share-with-friends',
name: Messages.share_withFriends,
onClick: function () {
- var href = Hash.getRelativeHref($('#cp-share-link-preview').val());
+ var href = Hash.getRelativeHref(linkGetter());
var $friends = $div.find('.cp-usergrid-user.cp-selected');
$friends.each(function (i, el) {
var curve = $(el).attr('data-curve');
@@ -994,7 +977,7 @@ define([
}
},
keys: [13]
- }];
+ };
common.getAttribute(['general', 'share-friends'], function (err, val) {
order = val || [];
@@ -1019,10 +1002,12 @@ define([
// Display them
$(friendDiv).find('.cp-usergrid-grid').detach();
$(friendDiv).append(h('div.cp-usergrid-grid', others));
- $div.append(UI.dialog.getButtons(shareButtons, config.onClose));
refreshButtons();
});
- return div;
+ return {
+ content: div,
+ button: shareButton
+ };
};
UIElements.createShareModal = function (config) {
@@ -1033,107 +1018,106 @@ define([
if (!hashes || (!hashes.editHash && !hashes.viewHash)) { return; }
- // Share link tab
- var hasFriends = Object.keys(config.friends || {}).length !== 0;
- var onFriendShare = Util.mkEvent();
- var friendsList = hasFriends ? createShareWithFriends(config, onFriendShare) : undefined;
- var friendsUIClass = hasFriends ? '.cp-share-columns' : '';
+ var parsed = Hash.parsePadUrl(pathname);
+ var canPresent = ['code', 'slide'].indexOf(parsed.type) !== -1;
- var content = [];
- var sfContent = [
- h('label', Messages.sharedFolders_share),
- h('br'),
- ];
- var shareContent = [
+ var rights = h('div.msg.cp-inline-radio-group', [
h('label', Messages.share_linkAccess),
h('br'),
- UI.createRadio('cp-share-editable', 'cp-share-editable-true',
- Messages.share_linkEdit, true, { mark: {tabindex:1} }),
- UI.createRadio('cp-share-editable', 'cp-share-editable-false',
- Messages.share_linkView, false, { mark: {tabindex:1} }),
- h('br'),
- ];
- var padContent = [
- h('label', Messages.share_linkOptions),
- h('br'),
- UI.createCheckbox('cp-share-embed', Messages.share_linkEmbed, false, { mark: {tabindex:1} }),
- UI.createCheckbox('cp-share-present', Messages.share_linkPresent, false, { mark: {tabindex:1} }),
- h('br'),
- ];
- if (config.sharedFolder) { Array.prototype.push.apply(content, sfContent); }
- Array.prototype.push.apply(content, shareContent);
- if (!config.sharedFolder) { Array.prototype.push.apply(content, padContent); }
- content.push(UI.dialog.selectable('', { id: 'cp-share-link-preview', tabindex: 1 }));
+ h('div.radio-group',[
+ UI.createRadio('accessRights', 'cp-share-editable-false',
+ Messages.share_linkView, true, { mark: {tabindex:1} }),
+ canPresent ? UI.createRadio('accessRights', 'cp-share-present',
+ Messages.share_linkPresent, false, { mark: {tabindex:1} }) : undefined,
+ UI.createRadio('accessRights', 'cp-share-editable-true',
+ Messages.share_linkEdit, false, { mark: {tabindex:1} })])
+ ]);
+
+ var $rights = $(rights);
- var mainShareColumn = h('div.cp-share-column.contains-nav', content);
- var link = h('div.cp-share-modal' + friendsUIClass);
var saveValue = function () {
- var edit = Util.isChecked($(link).find('#cp-share-editable-true'));
- var embed = Util.isChecked($(link).find('#cp-share-embed'));
- var present = Util.isChecked($(link).find('#cp-share-present'));
+ var edit = Util.isChecked($rights.find('#cp-share-editable-true'));
+ var present = Util.isChecked($rights.find('#cp-share-present'));
common.setAttribute(['general', 'share'], {
edit: edit,
- embed: embed,
present: present
});
};
- onFriendShare.reg(saveValue);
+
var getLinkValue = function (initValue) {
var val = initValue || {};
- var edit = val.edit !== undefined ? val.edit : Util.isChecked($(link).find('#cp-share-editable-true'));
- var embed = val.embed !== undefined ? val.embed : Util.isChecked($(link).find('#cp-share-embed'));
- var present = val.present !== undefined ? val.present : Util.isChecked($(link).find('#cp-share-present'));
-
+ var edit = val.edit !== undefined ? val.edit : Util.isChecked($rights.find('#cp-share-editable-true'));
+ var embed = val.embed;
+ var present = val.present !== undefined ? val.present : Util.isChecked($rights.find('#cp-share-present'));
var hash = (!hashes.viewHash || (edit && hashes.editHash)) ? hashes.editHash : hashes.viewHash;
var href = origin + pathname + '#' + hash;
var parsed = Hash.parsePadUrl(href);
return origin + parsed.getUrl({embed: embed, present: present});
};
- var linkButtons = [{
- className: 'cancel',
- name: Messages.cancel,
- onClick: function () {},
- keys: [27]
- }];
- var shareButtons = [{
- className: 'primary',
- name: Messages.share_linkCopy,
- onClick: function () {
- saveValue();
- var v = getLinkValue();
- var success = Clipboard.copy(v);
- if (success) { UI.log(Messages.shareSuccess); }
- },
- keys: [13]
- }];
- if (!config.sharedFolder) {
- shareButtons.push({
- className: 'primary',
- name: Messages.share_linkOpen,
- onClick: function () {
- saveValue();
- var v = getLinkValue();
- window.open(v);
- },
- keys: [[13, 'ctrl']]
- });
- }
+ var makeCancelButton = function() {
+ return {
+ className: 'cancel',
+ name: Messages.cancel,
+ onClick: function () {},
+ keys: [27]
+ };
+ };
+
+ // Share link tab
+ var linkContent = config.sharedFolder ? [
+ h('label', Messages.sharedFolders_share),
+ h('br'),
+ ] : [
+ UI.createCheckbox('cp-share-embed', Messages.share_linkEmbed, false, { mark: {tabindex:1} }),
+ h('br'),
+ ];
+ linkContent.push(UI.dialog.selectable('', { id: 'cp-share-link-preview', tabindex: 1 }));
+
+ var link = h('div.cp-share-modal', linkContent);
var $link = $(link);
- $(mainShareColumn).append(UI.dialog.getButtons(shareButtons, config.onClose)).appendTo($link);
- $(friendsList).appendTo($link);
- if (!hashes.editHash) {
- $(link).find('#cp-share-editable-false').attr('checked', true);
- $(link).find('#cp-share-editable-true').removeAttr('checked').attr('disabled', true);
- } else if (!hashes.viewHash) {
- $(link).find('#cp-share-editable-false').removeAttr('checked').attr('disabled', true);
- $(link).find('#cp-share-editable-true').attr('checked', true);
- }
+ var linkButtons = [
+ makeCancelButton(),
+ !config.sharedFolder && {
+ className: 'secondary', // XXX style this diferently than cancel
+ name: Messages.share_linkOpen,
+ onClick: function () {
+ saveValue();
+ var v = getLinkValue({
+ embed: Util.isChecked($link.find('#cp-share-embed'))
+ });
+ window.open(v);
+ return true;
+ },
+ keys: [[13, 'ctrl']]
+ },
+ {
+ className: 'primary',
+ name: Messages.share_linkCopy,
+ onClick: function () {
+ saveValue();
+ var v = getLinkValue({
+ embed: Util.isChecked($link.find('#cp-share-embed'))
+ });
+ var success = Clipboard.copy(v);
+ if (success) { UI.log(Messages.shareSuccess); }
+ },
+ keys: [13]
+ }
+ ];
- $(link).find('#cp-share-link-preview').val(getLinkValue());
- $(link).find('input[type="radio"], input[type="checkbox"]').on('change', function () {
- $(link).find('#cp-share-link-preview').val(getLinkValue());
+ // update values for link preview when radio btns change
+ $link.find('#cp-share-link-preview').val(getLinkValue());
+ $rights.find('input[type="radio"]').on('change', function () {
+ $link.find('#cp-share-link-preview').val(getLinkValue({
+ embed: Util.isChecked($link.find('#cp-share-embed'))
+ }));
+ });
+ $link.find('input[type="checkbox"]').on('change', function () {
+ $link.find('#cp-share-link-preview').val(getLinkValue({
+ embed: Util.isChecked($link.find('#cp-share-embed'))
+ }));
});
var frameLink = UI.dialog.customModal(link, {
@@ -1141,26 +1125,44 @@ define([
onClose: config.onClose,
});
+ // Share with contacts tab
+
+ var hasFriends = Object.keys(config.friends || {}).length !== 0;
+ var onFriendShare = Util.mkEvent();
+ var friendsObject = hasFriends ? createShareWithFriends(config, onFriendShare, getLinkValue) : {
+ content: h('p', Messages.team_noFriend),
+ button: {}
+ };
+ var friendsList = friendsObject.content;
+
+ onFriendShare.reg(saveValue);
+
+ // XXX Don't display access rights if no contacts
+ var contactsContent = h('div.cp-share-modal');
+ $(contactsContent).append(friendsList);
+
+ var contactButtons = [makeCancelButton(),
+ friendsObject.button];
+
+ var frameContacts = UI.dialog.customModal(contactsContent, {
+ buttons: contactButtons,
+ onClose: config.onClose,
+ });
+
// Embed tab
var getEmbedValue = function () {
- var hash = hashes.viewHash || hashes.editHash;
- var href = origin + pathname + '#' + hash;
- var parsed = Hash.parsePadUrl(href);
- var url = origin + parsed.getUrl({embed: true, present: true});
+ var url = getLinkValue({
+ embed: true
+ });
return '';
};
- var embed = h('div.cp-share-modal', [
- h('h3', Messages.viewEmbedTitle),
+ var embedContent = [
h('p', Messages.viewEmbedTag),
h('br'),
- UI.dialog.selectable(getEmbedValue())
- ]);
- var embedButtons = [{
- className: 'cancel',
- name: Messages.cancel,
- onClick: function () {},
- keys: [27]
- }, {
+ UI.dialog.selectable(getEmbedValue(), { id: 'cp-embed-link-preview', tabindex: 1 })
+ ];
+ var embedButtons = [
+ makeCancelButton(), {
className: 'primary',
name: Messages.share_linkCopy,
onClick: function () {
@@ -1170,6 +1172,15 @@ define([
},
keys: [13]
}];
+
+ var embed = h('div.cp-share-modal', embedContent);
+
+ // update values for link preview when radio btns change
+ $(embed).find('#cp-embed-link-preview').val(getEmbedValue());
+ $rights.find('input[type="radio"]').on('change', function () {
+ $(embed).find('#cp-embed-link-preview').val(getEmbedValue());
+ });
+
var frameEmbed = UI.dialog.customModal(embed, {
buttons: embedButtons,
onClose: config.onClose,
@@ -1178,9 +1189,15 @@ define([
// Create modal
var tabs = [{
title: Messages.share_linkCategory,
+ icon: "fa fa-link",
content: frameLink
+ }, {
+ title: Messages.share_contactCategory,
+ icon: "fa fa-address-book",
+ content: frameContacts
}, {
title: Messages.share_embedCategory,
+ icon: "fa fa-code",
content: frameEmbed
}];
if (typeof(AppConfig.customizeShareOptions) === 'function') {
@@ -1190,32 +1207,52 @@ define([
pathname: pathname
});
}
+
+ var modal = UI.dialog.tabs(tabs);
+ $(modal).find('.alertify-tabs-titles').after(rights);
+
+ // XXX
+ // disable edit share options if you don't have edit rights
+ if (!hashes.editHash) {
+ $rights.find('#cp-share-editable-false').attr('checked', true);
+ $rights.find('#cp-share-editable-true').removeAttr('checked').attr('disabled', true);
+ } else if (!hashes.viewHash) {
+ $rights.find('#cp-share-editable-false').removeAttr('checked').attr('disabled', true);
+ $rights.find('#cp-share-present').removeAttr('checked').attr('disabled', true);
+ $rights.find('#cp-share-editable-true').attr('checked', true);
+ }
+
common.getAttribute(['general', 'share'], function (err, val) {
val = val || {};
- if ((val.edit === false && hashes.viewHash) || !hashes.editHash) {
- $(link).find('#cp-share-editable-false').prop('checked', true);
- $(link).find('#cp-share-editable-true').prop('checked', false);
+ if (val.present && canPresent) {
+ $rights.find('#cp-share-editable-false').prop('checked', false);
+ $rights.find('#cp-share-editable-true').prop('checked', false);
+ $rights.find('#cp-share-present').prop('checked', true);
+ } else if ((val.edit === false && hashes.viewHash) || !hashes.editHash) {
+ $rights.find('#cp-share-editable-false').prop('checked', true);
+ $rights.find('#cp-share-editable-true').prop('checked', false);
+ $rights.find('#cp-share-present').prop('checked', false);
} else {
- $(link).find('#cp-share-editable-true').prop('checked', true);
- $(link).find('#cp-share-editable-false').prop('checked', false);
+ $rights.find('#cp-share-editable-true').prop('checked', true);
+ $rights.find('#cp-share-editable-false').prop('checked', false);
+ $rights.find('#cp-share-present').prop('checked', false);
}
- if (val.embed) { $(link).find('#cp-share-embed').prop('checked', true); }
- if (val.present) { $(link).find('#cp-share-present').prop('checked', true); }
- if (config.sharedFolder) {
- delete val.embed;
+ delete val.embed;
+ if (!canPresent) {
delete val.present;
}
- $(link).find('#cp-share-link-preview').val(getLinkValue(val));
+ $link.find('#cp-share-link-preview').val(getLinkValue(val));
});
common.getMetadataMgr().onChange(function () {
// "hashes" is only available is the secure "share" app
var _hashes = common.getMetadataMgr().getPrivateData().hashes;
if (!_hashes) { return; }
hashes = _hashes;
- $(link).find('#cp-share-link-preview').val(getLinkValue());
+ $link.find('#cp-share-link-preview').val(getLinkValue());
});
- return tabs;
+ return modal;
};
+
UIElements.createFileShareModal = function (config) {
var origin = config.origin;
var pathname = config.pathname;
@@ -1226,49 +1263,65 @@ define([
if (!hashes.fileHash) { throw new Error("You must provide a file hash"); }
var url = origin + pathname + '#' + hashes.fileHash;
-
- // Share link tab
- var hasFriends = Object.keys(config.friends || {}).length !== 0;
- var friendsList = hasFriends ? createShareWithFriends(config) : undefined;
- var friendsUIClass = hasFriends ? '.cp-share-columns' : '';
- var mainShareColumn = h('div.cp-share-column.contains-nav', [
- h('div.cp-share-column', [
- hasFriends ? h('p', Messages.share_description) : undefined,
- UI.dialog.selectable('', { id: 'cp-share-link-preview' }),
- ]),
- ]);
- var link = h('div.cp-share-modal' + friendsUIClass);
var getLinkValue = function () { return url; };
- $(mainShareColumn).find('#cp-share-link-preview').val(getLinkValue());
- var linkButtons = [{
- className: 'cancel',
+
+ var makeCancelButton = function() {
+ return {className: 'cancel',
name: Messages.cancel,
onClick: function () {},
- keys: [27]
- }];
- var shareButtons = [{
- className: 'primary',
- name: Messages.share_linkCopy,
- onClick: function () {
- var v = getLinkValue();
- var success = Clipboard.copy(v);
- if (success) { UI.log(Messages.shareSuccess); }
- },
- keys: [13]
- }];
+ keys: [27]};
+ };
- var $link = $(link);
- $(mainShareColumn).append(UI.dialog.getButtons(shareButtons, config.onClose)).appendTo($link);
- $(friendsList).appendTo($link);
+ // Share link tab
+ var linkContent = [
+ UI.dialog.selectable(getLinkValue(), { id: 'cp-share-link-preview', tabindex: 1 })
+ ];
+
+ var link = h('div.cp-share-modal', linkContent);
+
+ var linkButtons = [
+ makeCancelButton(),
+ {
+ className: 'primary',
+ name: Messages.share_linkCopy,
+ onClick: function () {
+ var v = getLinkValue();
+ var success = Clipboard.copy(v);
+ if (success) { UI.log(Messages.shareSuccess);
+ }
+ },
+ keys: [13]
+ }
+ ];
var frameLink = UI.dialog.customModal(link, {
buttons: linkButtons,
onClose: config.onClose,
});
+ // share with contacts tab
+ var hasFriends = Object.keys(config.friends || {}).length !== 0;
+
+ var friendsObject = hasFriends ? createShareWithFriends(config, null, getLinkValue) : {
+ content: h('p', Messages.share_noContacts),
+ button: {}
+ };
+ var friendsList = friendsObject.content;
+
+ var contactsContent = h('div.cp-share-modal');
+ $(contactsContent).append(friendsList);
+
+ var contactButtons = [makeCancelButton(),
+ friendsObject.button];
+
+ var frameContacts = UI.dialog.customModal(contactsContent, {
+ buttons: contactButtons,
+ onClose: config.onClose,
+ });
+
+
// Embed tab
var embed = h('div.cp-share-modal', [
- h('h3', Messages.fileEmbedTitle),
h('p', Messages.fileEmbedScript),
h('br'),
UI.dialog.selectable(common.getMediatagScript()),
@@ -1299,9 +1352,15 @@ define([
// Create modal
var tabs = [{
title: Messages.share_linkCategory,
+ icon: "fa fa-link",
content: frameLink
+ }, {
+ title: Messages.share_contactCategory,
+ icon: "fa fa-address-book",
+ content: frameContacts
}, {
title: Messages.share_embedCategory,
+ icon: "fa fa-code",
content: frameEmbed
}];
if (typeof(AppConfig.customizeShareOptions) === 'function') {
@@ -1311,9 +1370,11 @@ define([
pathname: pathname
});
}
- return tabs;
+ var modal = UI.dialog.tabs(tabs);
+ return modal;
};
+
UIElements.createInviteTeamModal = function (config) {
var common = config.common;
var hasFriends = Object.keys(config.friends || {}).length !== 0;
@@ -3465,19 +3526,24 @@ define([
(cb || function () {})();
};
- UIElements.displayPasswordPrompt = function (common, isError) {
+ UIElements.displayPasswordPrompt = function (common, cfg, isError) {
var error;
if (isError) { error = setHTML(h('p.cp-password-error'), Messages.password_error); }
var info = h('p.cp-password-info', Messages.password_info);
var password = UI.passwordInput({placeholder: Messages.password_placeholder});
var button = h('button', Messages.password_submit);
+ cfg = cfg || {};
+
+ if (cfg.value && !isError) {
+ $(password).find('.cp-password-input').val(cfg.value);
+ }
var submit = function () {
var value = $(password).find('.cp-password-input').val();
UI.addLoadingScreen();
common.getSframeChannel().query('Q_PAD_PASSWORD_VALUE', value, function (err, data) {
if (!data) {
- UIElements.displayPasswordPrompt(common, true);
+ UIElements.displayPasswordPrompt(common, cfg, true);
}
});
};
@@ -4032,6 +4098,7 @@ define([
common.mailbox.sendTo("INVITE_TO_TEAM_ANSWER", {
answer: yes,
teamChannel: msg.content.team.channel,
+ teamName: teamName,
user: {
displayName: user.name,
avatar: user.avatar,
diff --git a/www/common/drive-ui.js b/www/common/drive-ui.js
index b0add7044..4c73a95a8 100644
--- a/www/common/drive-ui.js
+++ b/www/common/drive-ui.js
@@ -2559,8 +2559,6 @@ define([
var roParsed = Hash.parsePadUrl(data.roHref) || {};
if (!parsed.hash && !roParsed.hash) { return void console.error("Invalid href: "+(data.href || data.roHref)); }
var friends = common.getFriends();
- var teams = common.getMetadataMgr().getPrivateData().teams;
- var _wide = Object.keys(friends).length || Object.keys(teams).length;
var ro = folders[id] && folders[id].version >= 2;
var modal = UIElements.createShareModal({
teamId: APP.team,
@@ -2580,11 +2578,8 @@ define([
// can't share the read-only URL and we don't have access to the edit one.
// We should hide the share button.
if (!modal) { return; }
- modal = UI.dialog.tabs(modal);
$shareBlock.click(function () {
- UI.openCustomModal(modal, {
- wide: _wide
- });
+ UI.openCustomModal(modal);
});
$container.append($shareBlock);
};
@@ -4053,8 +4048,6 @@ define([
el = manager.find(paths[0].path);
var parsed, modal;
var friends = common.getFriends();
- var teams = common.getMetadataMgr().getPrivateData().teams;
- var _wide = Object.keys(friends).length || Object.keys(teams).length;
if (manager.isFolder(el) && !manager.isSharedFolder(el)) { // Folder
// if folder is inside SF
@@ -4119,10 +4112,7 @@ define([
};
modal = padType === 'file' ? UIElements.createFileShareModal(padData)
: UIElements.createShareModal(padData);
- modal = UI.dialog.tabs(modal);
- UI.openCustomModal(modal, {
- wide: _wide
- });
+ UI.openCustomModal(modal);
}
}
else if ($this.hasClass('cp-app-drive-context-savelocal')) {
diff --git a/www/common/notifications.js b/www/common/notifications.js
index ed44c2917..192d2b4c6 100644
--- a/www/common/notifications.js
+++ b/www/common/notifications.js
@@ -294,7 +294,8 @@ define([
// Display the notification
var name = Util.fixHTML(msg.content.user.displayName) || Messages.anonymous;
- var teamName = Util.fixHTML(Util.find(msg, ['content', 'team', 'metadata', 'name']) || '');
+ var teamName = Util.fixHTML(Util.find(msg, ['content', 'team', 'metadata', 'name']) || '') ||
+ Util.fixHTML(Util.find(msg, ['content', 'teamName']));
var key = 'team_' + (msg.content.answer ? 'accept' : 'decline') + 'Invitation';
content.getFormatText = function () {
return Messages._getKey(key, [name, teamName]);
diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js
index 06d5b7d3a..15444f77b 100644
--- a/www/common/outer/async-store.js
+++ b/www/common/outer/async-store.js
@@ -575,7 +575,8 @@ define([
support: Util.find(store.proxy, ['mailboxes', 'support', 'channel']),
pendingFriends: store.proxy.friends_pending || {},
supportPrivateKey: Util.find(store.proxy, ['mailboxes', 'supportadmin', 'keys', 'curvePrivate']),
- teams: teams
+ teams: teams,
+ plan: account.plan
}
};
cb(JSON.parse(JSON.stringify(metadata)));
diff --git a/www/common/outer/profile.js b/www/common/outer/profile.js
index 0e1e1f35e..dd56db6e9 100644
--- a/www/common/outer/profile.js
+++ b/www/common/outer/profile.js
@@ -20,11 +20,11 @@ define([
}
profile.edit = Hash.getEditHashFromKeys(secret);
profile.view = Hash.getViewHashFromKeys(secret);
- cb();
+ setTimeout(cb);
});
return;
}
- cb();
+ setTimeout(cb);
};
var openChannel = function (ctx) {
diff --git a/www/common/outer/sharedfolder.js b/www/common/outer/sharedfolder.js
index e4d8d152c..907c49cd0 100644
--- a/www/common/outer/sharedfolder.js
+++ b/www/common/outer/sharedfolder.js
@@ -21,7 +21,8 @@ define([
// No version: visible edit
// Version 2: encrypted edit links
- SF.checkMigration = function (secondaryKey, proxy, uo, cb) {
+ SF.checkMigration = function (secondaryKey, proxy, uo, _cb) {
+ var cb = Util.once(Util.mkAsync(_cb));
var drive = proxy.drive || proxy;
// View access: can't migrate
if (!secondaryKey) { return void cb(); }
@@ -82,7 +83,7 @@ define([
};
SF.load = function (config, id, data, _cb) {
- var cb = Util.once(_cb);
+ var cb = Util.once(Util.mkAsync(_cb));
var network = config.network;
var store = config.store;
var isNew = config.isNew;
@@ -188,7 +189,7 @@ define([
return;
}
sf.teams.forEach(function (obj) {
- var leave = function () { SF.leave(secret.channel, teamId); };
+ var leave = function () { SF.leave(secret.channel, obj.store.id); };
/*
var uo = obj.store.manager.addProxy(obj.id, rt, leave, obj.secondaryKey);
// NOTE: Shared folder migration, disable for now
@@ -300,6 +301,7 @@ define([
*/
SF.loadSharedFolders = function (Store, network, store, userObject, waitFor) {
var shared = Util.find(store.proxy, ['drive', UserObject.SHARED_FOLDERS]) || {};
+ var w = waitFor();
nThen(function (waitFor) {
Object.keys(shared).forEach(function (id) {
var sf = shared[id];
@@ -309,7 +311,9 @@ define([
isNewChannel: Store.isNewChannel
}, id, sf, waitFor());
});
- }).nThen(waitFor());
+ }).nThen(function () {
+ setTimeout(w);
+ });
};
return SF;
diff --git a/www/common/outer/team.js b/www/common/outer/team.js
index 9c33a722a..62fc1b45b 100644
--- a/www/common/outer/team.js
+++ b/www/common/outer/team.js
@@ -25,10 +25,6 @@ define([
var Nacl = window.nacl;
- var initializeTeams = function (ctx, cb) {
- cb();
- };
-
var registerChangeEvents = function (ctx, team, proxy, fId) {
if (!team) { return; }
if (!fId) {
@@ -340,7 +336,7 @@ define([
};
var openChannel = function (ctx, teamData, id, _cb) {
- var cb = Util.once(_cb);
+ var cb = Util.once(Util.mkAsync(_cb));
var hash = teamData.hash || teamData.roHash;
var secret = Hash.getSecrets('team', hash, teamData.password);
@@ -1279,10 +1275,6 @@ define([
var teams = store.proxy.teams = store.proxy.teams || {};
- initializeTeams(ctx, waitFor(function (err) {
- if (err) { return; }
- }));
-
// Listen for changes in our access rights (if another worker receives edit access)
ctx.store.proxy.on('change', ['teams'], function (o, n, p) {
if (p[2] !== 'hash') { return; }
diff --git a/www/common/outer/userObject.js b/www/common/outer/userObject.js
index 868e623de..7182d6ab2 100644
--- a/www/common/outer/userObject.js
+++ b/www/common/outer/userObject.js
@@ -45,6 +45,8 @@ define([
var ids = id ? [id] : exp.findChannels([channel]);
ids.forEach(function (i) {
var data = exp.getFileData(i, true);
+ var oldHref = exp.getHref(data);
+ if (oldHref === href) { return; }
data.href = exp.cryptor.encrypt(href);
});
};
diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js
index dc710ef27..f397f96ea 100644
--- a/www/common/sframe-common-outer.js
+++ b/www/common/sframe-common-outer.js
@@ -206,7 +206,7 @@ define([
// 2c: 'view' pad and '/p/' and a wrong password stored --> the seed is incorrect
// 2d: 'view' pad and '/p/' and password never stored (security feature) --> password-prompt
- var askPassword = function (wrongPasswordStored) {
+ var askPassword = function (wrongPasswordStored, cfg) {
// Ask for the password and check if the pad exists
// If the pad doesn't exist, it means the password isn't correct
// or the pad has been deleted
@@ -249,11 +249,14 @@ define([
// Not a file, so we can use `isNewChannel`
Cryptpad.isNewChannel(window.location.href, password, next);
});
- sframeChan.event("EV_PAD_PASSWORD");
+ sframeChan.event("EV_PAD_PASSWORD", cfg);
};
var done = waitFor();
var stored = false;
+ var passwordCfg = {
+ value: ''
+ };
nThen(function (w) {
Cryptpad.getPadAttribute('title', w(function (err, data) {
stored = (!err && typeof (data) === "string");
@@ -263,7 +266,7 @@ define([
}), parsed.getUrl());
}).nThen(function (w) {
if (!password && !stored && sessionStorage.newPadPassword) {
- password = sessionStorage.newPadPassword;
+ passwordCfg.value = sessionStorage.newPadPassword;
delete sessionStorage.newPadPassword;
}
@@ -273,7 +276,7 @@ define([
Cryptpad.getFileSize(window.location.href, password, w(function (e, size) {
if (size !== 0) { return void todo(); }
// Wrong password or deleted file?
- askPassword(true);
+ askPassword(true, passwordCfg);
}));
return;
}
@@ -292,7 +295,7 @@ define([
return void todo();
}
// Wrong password or deleted file?
- askPassword(true);
+ askPassword(true, passwordCfg);
}));
}).nThen(done);
}
@@ -363,7 +366,6 @@ define([
donateURL: Cryptpad.donateURL,
upgradeURL: Cryptpad.upgradeURL
},
- plan: localStorage[Utils.Constants.plan],
isNewFile: isNewFile,
isDeleted: isNewFile && window.location.hash.length > 0,
forceCreationScreen: forceCreationScreen,
diff --git a/www/common/sframe-common.js b/www/common/sframe-common.js
index c73e43996..f8bbb205b 100644
--- a/www/common/sframe-common.js
+++ b/www/common/sframe-common.js
@@ -595,8 +595,8 @@ define([
UI.addTooltips();
- ctx.sframeChan.on("EV_PAD_PASSWORD", function () {
- UIElements.displayPasswordPrompt(funcs);
+ ctx.sframeChan.on("EV_PAD_PASSWORD", function (cfg) {
+ UIElements.displayPasswordPrompt(funcs, cfg);
});
ctx.sframeChan.on("EV_PAD_PASSWORD_ERROR", function () {
diff --git a/www/common/translations/messages.ca.json b/www/common/translations/messages.ca.json
index dd4c9c4ff..1b38959a6 100644
--- a/www/common/translations/messages.ca.json
+++ b/www/common/translations/messages.ca.json
@@ -170,7 +170,6 @@
"viewOpenTitle": "Obre aquest document en mode només de lectura en una pestanya nova",
"fileShare": "Copia l'enllaç",
"getEmbedCode": "Obté el codi d'incrustat",
- "viewEmbedTitle": "Inscrusta el document en una pàgina externa",
"viewEmbedTag": "Per incrustar aquest document, poseu aquest iframe allà on vulgueu de la vostra pàgina. Podeu donar-li l'estil desitjat utilitzant els atributs CSS o HTML.",
"fileEmbedTitle": "Incrusta el fitxer en una pàgina externa",
"fileEmbedScript": "Per incrustar aquest fitxer, poseu aquest script un cop a la vostra pàgina per carregar l'Etiqueta Multimèdia:",
diff --git a/www/common/translations/messages.de.json b/www/common/translations/messages.de.json
index 9c2c67ab1..de40bbfec 100644
--- a/www/common/translations/messages.de.json
+++ b/www/common/translations/messages.de.json
@@ -168,7 +168,6 @@
"viewOpenTitle": "Pad schreibgeschützt in neuem Tab öffnen",
"fileShare": "Link kopieren",
"getEmbedCode": "Einbettungscode anzeigen",
- "viewEmbedTitle": "Das Pad in eine externe Webseite einbetten",
"viewEmbedTag": "Um dieses Pad einzubetten, platziere diesen iframe an der gewünschten Stelle deiner HTML-Seite. Du kannst es mit CSS oder HTML-Attributen gestalten.",
"fileEmbedTitle": "Die Datei in einer externen Seite einbetten",
"fileEmbedScript": "Um diese Datei einzubetten, füge dieses Skript einmal in deiner Webseite ein, damit das Media-Tag geladen wird:",
@@ -955,15 +954,14 @@
"properties_passwordWarning": "Das Passwort wurde erfolgreich geändert, aber dein CryptDrive konnte nicht aktualisiert werden. Du musst möglicherweise die alte Version des Pads manuell entfernen. Klicke auf OK, um die Seite neu zu laden und die Zugriffsrechte zu aktualisieren.",
"properties_passwordSuccess": "Das Passwort wurde erfolgreich geändert. Klicke auf OK, um die Seite neu zu laden und die Zugriffsrechte zu aktualisieren.",
"properties_changePasswordButton": "Absenden",
- "share_linkCategory": "Link teilen",
+ "share_linkCategory": "Link",
"share_linkAccess": "Zugriffsrechte",
"share_linkEdit": "Bearbeiten",
"share_linkView": "Ansehen",
- "share_linkOptions": "Linkoptionen",
- "share_linkEmbed": "Einbettungsmodus (Werkzeugleiste und Benutzerliste sind verborgen)",
- "share_linkPresent": "Anzeigemodus (Bearbeitbare Abschnitte sind verborgen)",
- "share_linkOpen": "In einem neuen Tab öffnen",
- "share_linkCopy": "In die Zwischenablage kopieren",
+ "share_linkEmbed": "Einbettungsmodus (Werkzeugleiste und Benutzerliste verbergen)",
+ "share_linkPresent": "Anzeigemodus",
+ "share_linkOpen": "Vorschau",
+ "share_linkCopy": "Kopieren",
"share_embedCategory": "Einbetten",
"share_mediatagCopy": "Media-Tag in die Zwischenablage kopieren",
"loading_pad_1": "Initialisiere Pad",
@@ -977,7 +975,7 @@
"sharedFolders_create_name": "Neuer Ordner",
"sharedFolders_create_owned": "Eigener Ordner",
"sharedFolders_create_password": "Ordnerpasswort",
- "sharedFolders_share": "Teile diese URL mit anderen registrierten Benutzern, um ihnen Zugriff auf den geteilten Ordner zu geben. Sobald sie diese URL öffnen, wird der geteilte Ordner zu ihrem CryptDrive hinzugefügt.",
+ "sharedFolders_share": "Teile diesen Link mit anderen registrierten Benutzern, um ihnen Zugriff auf den geteilten Ordner zu geben. Sobald sie diesen Link öffnen, wird der geteilte Ordner zu ihrem CryptDrive hinzugefügt.",
"chrome68": "Anscheinend benutzt du Chrome oder Chromium in Version 68. Ein darin enthaltener Fehler führt dazu, dass nach ein paar Sekunden die Seite komplett weiß wird oder nicht mehr auf Klicks reagiert. Um das Problem zu beheben, wechsle den Tab und kehre zu CryptPad zurück, oder versuche zu scrollen. Dieser Fehler sollte in der nächsten Version deines Browsers behoben sein.",
"autostore_file": "Diese Datei",
"autostore_sf": "Dieser Ordner",
@@ -1242,5 +1240,7 @@
"teams_table_specificHint": "Dies sind ältere geteilte Ordner, wo Benutzer noch Bearbeitungsrechte haben. Für hier erstellte oder hierhin kopierte Pads gelten Standard-Berechtigungen.",
"teams_table_admins": "Mitglieder verwalten",
"teams_table_owners": "Team verwalten",
- "teams_table_role": "Rolle"
+ "teams_table_role": "Rolle",
+ "share_contactCategory": "Kontakte",
+ "pad_wordCount": "Wörter: {0}"
}
diff --git a/www/common/translations/messages.el.json b/www/common/translations/messages.el.json
index 593c5ff30..e5fbf232e 100644
--- a/www/common/translations/messages.el.json
+++ b/www/common/translations/messages.el.json
@@ -141,7 +141,6 @@
"viewOpenTitle": "Άνοιγμα αυτού του pad μόνο για ανάγνωση σε νέα καρτέλα",
"fileShare": "Αντιγραφή συνδέσμου",
"getEmbedCode": "Κώδικας ενσωμάτωσης",
- "viewEmbedTitle": "Ενσωματώστε αυτό το pad σε μία εξωτερική σελίδα",
"viewEmbedTag": "Για να ενσωματώσετε αυτό το pad, συμπεριλάβετε αυτό το iframe στη σελίδα σας, στο σημείο που θέλετε. Μπορείτε να το διαμορφώσετε χρησιμοποιώντας CSS η HTML παραμέτρους.",
"fileEmbedTitle": "Ενσωματώστε το αρχείο σε μια εξωτερική σελίδα",
"fileEmbedScript": "Για να ενσωματώσετε αυτό το αρχείο, συμπεριλάβετε αυτό το script στη σελίδα σας για να φορτωθεί το Media Tag:",
diff --git a/www/common/translations/messages.es.json b/www/common/translations/messages.es.json
index 37811d0c9..87ad7134e 100644
--- a/www/common/translations/messages.es.json
+++ b/www/common/translations/messages.es.json
@@ -496,7 +496,6 @@
"kanban_removeItemConfirm": "Estás seguro que quieres eliminar este ítem?",
"printBackgroundNoValue": "No se muestra fondo de pantalla ",
"getEmbedCode": "Obtener el código insertado",
- "viewEmbedTitle": "Insertar la nota en una página externa",
"viewEmbedTag": "Para insertar esta nota, incluya este iframe en su página donde usted quiera. Puede darle estilo usando CSS o atributos HTML.",
"fileEmbedTitle": "Insertar el archivo en una pagina externa",
"fileEmbedScript": "Para insertar este archivo, incluya este código una vez en su página para cargar el Etiqueta de Media:",
diff --git a/www/common/translations/messages.fr.json b/www/common/translations/messages.fr.json
index bd15572e7..b39e76785 100644
--- a/www/common/translations/messages.fr.json
+++ b/www/common/translations/messages.fr.json
@@ -170,7 +170,6 @@
"viewOpenTitle": "Ouvrir le lien en lecture seule dans un nouvel onglet",
"fileShare": "Copier le lien",
"getEmbedCode": "Obtenir le code d'intégration",
- "viewEmbedTitle": "Intégrer le pad dans une page web",
"viewEmbedTag": "Pour intégrer ce pad, veuillez inclure l'iframe suivant dans votre page là où vous souhaitez l'afficher. Vous pouvez changer sa taille en utilisant du code CSS ou des attributs HTML.",
"fileEmbedTitle": "Intégrer le fichier dans une page web",
"fileEmbedScript": "Pour intégrer un fichier, veuillez inclure le script suivant une fois dans votre page afin de pouvoir charger le Media Tag :",
@@ -962,15 +961,14 @@
"properties_passwordWarning": "Le mot de passe a été modifié avec succès mais nous n'avons pas réussi à mettre à jour votre CryptDrive avec les nouvelles informations. Vous devrez peut-être supprimer manuellement l'ancienne version de ce pad. Appuyez sur OK pour recharger le pad et mettre à jour vos droits d'accès.",
"properties_passwordSuccess": "Le mot de passe a été modifié avec succès. Appuyez sur OK pour mettre à jour vos droits d'accès.",
"properties_changePasswordButton": "Valider",
- "share_linkCategory": "Partage",
+ "share_linkCategory": "Lien",
"share_linkAccess": "Droits d'accès",
"share_linkEdit": "Édition",
"share_linkView": "Lecture-seule",
- "share_linkOptions": "Options du lien",
- "share_linkEmbed": "Mode intégration (barre d'outils cachée)",
- "share_linkPresent": "Mode présentation (sections d'édition cachées)",
- "share_linkOpen": "Ouvrir le lien",
- "share_linkCopy": "Copier le lien",
+ "share_linkEmbed": "Mode intégration (cache la barre d'outils)",
+ "share_linkPresent": "Présenter",
+ "share_linkOpen": "Apperçu",
+ "share_linkCopy": "Copier",
"share_embedCategory": "Intégration",
"share_mediatagCopy": "Copier le mediatag",
"loading_pad_1": "Initialisation du pad",
@@ -984,7 +982,7 @@
"sharedFolders_create_name": "Nom du dossier",
"sharedFolders_create_owned": "Être propriétaire du dossier",
"sharedFolders_create_password": "Mot de passe du dossier",
- "sharedFolders_share": "Partager cette URL avec d'autres utilisateurs enregistrés leur donne accès au dossier partagé. Une fois l'URL ouverte, le dossier partagé sera ajouté au répertoire racine de leur CryptDrive.",
+ "sharedFolders_share": "Partager ce lien avec d'autres utilisateurs enregistrés leur donne accès au dossier partagé. Une fois le lien ouvert, le dossier partagé sera ajouté à leur CryptDrive.",
"chrome68": "Il semblerait que vous utilisiez le navigateur Chrome version 68. Ce navigateur contient un bug rendant certaines pages entièrement blanches après quelques secondes ou bloquant les clics. Pour corriger ce problème, vous pouvez vous déplacer vers un nouvel onglet et revenir ou vous pouvez essayer de faire défiler la page. Ce bug devrait être corrigé dans la prochaine version du navigateur.",
"autostore_file": "fichier",
"autostore_sf": "dossier",
@@ -1242,5 +1240,7 @@
"teams_table_specificHint": "Dans ces dossiers partagés qui sont d'une version antérieure, les lecteurs peuvent modifier les pads existants. Les pads créés ou copiés dans ces dossiers auront les permissions standard.",
"teams_table_admins": "Gérer les membres",
"teams_table_owners": "Gérer l'équipe",
- "teams_table_role": "Rôle"
+ "teams_table_role": "Rôle",
+ "share_contactCategory": "Contacts",
+ "pad_wordCount": "Mots : {0}"
}
diff --git a/www/common/translations/messages.it.json b/www/common/translations/messages.it.json
index 673c40fd1..64451d416 100644
--- a/www/common/translations/messages.it.json
+++ b/www/common/translations/messages.it.json
@@ -169,7 +169,6 @@
"viewOpenTitle": "Apri questo pad in modalità solo lettura in una nuova finestra",
"fileShare": "Copia il link",
"getEmbedCode": "Mostra il codice per embedding",
- "viewEmbedTitle": "Fai l'embed di questo pad in una pagina esterna",
"viewEmbedTag": "Per fare l'embed di questo pad, includi questo iframe nella tua pagina dovunque tu voglia. Puoi modificarne lo stile con gli attributi HTML o CSS.",
"fileEmbedTitle": "Fai l'embed di questo file in una pagina esterna",
"fileEmbedScript": "Per fare l'embed di questo file, includi questo script una volta nella tua pagina per caricare il Media Tag:",
diff --git a/www/common/translations/messages.json b/www/common/translations/messages.json
index 769f5a52d..3c2e39e5b 100644
--- a/www/common/translations/messages.json
+++ b/www/common/translations/messages.json
@@ -173,7 +173,6 @@
"viewOpenTitle": "Open this pad in read-only mode in a new tab",
"fileShare": "Copy link",
"getEmbedCode": "Get embed code",
- "viewEmbedTitle": "Embed the pad in an external page",
"viewEmbedTag": "To embed this pad, include this iframe in your page wherever you want. You can style it using CSS or HTML attributes.",
"fileEmbedTitle": "Embed the file in an external page",
"fileEmbedScript": "To embed this file, include this script once in your page to load the Media Tag:",
@@ -980,15 +979,15 @@
"properties_passwordWarning": "The password was successfully changed but we were unable to update your CryptDrive with the new data. You may have to remove the old version of the pad manually. Press OK to reload and update your access rights.",
"properties_passwordSuccess": "The password was successfully changed. Press OK to reload and update your access rights.",
"properties_changePasswordButton": "Submit",
- "share_linkCategory": "Share link",
+ "share_linkCategory": "Link",
"share_linkAccess": "Access rights",
"share_linkEdit": "Edit",
"share_linkView": "View",
- "share_linkOptions": "Link options",
- "share_linkEmbed": "Embed mode (toolbar and userlist hidden)",
- "share_linkPresent": "Present mode (editable sections hidden)",
- "share_linkOpen": "Open in new tab",
- "share_linkCopy": "Copy to clipboard",
+ "share_linkEmbed": "Embed mode (hide toolbar and user list)",
+ "share_linkPresent": "Present",
+ "share_linkOpen": "Preview",
+ "share_linkCopy": "Copy",
+ "share_contactCategory": "Contacts",
"share_embedCategory": "Embed",
"share_mediatagCopy": "Copy mediatag to clipboard",
"loading_pad_1": "Initializing pad",
@@ -1002,7 +1001,7 @@
"sharedFolders_create_name": "Folder name",
"sharedFolders_create_owned": "Owned folder",
"sharedFolders_create_password": "Folder password",
- "sharedFolders_share": "Share this URL with other registered users to give them access to the shared folder. Once they open this URL, the shared folder will be added to the root directory of their CryptDrive.",
+ "sharedFolders_share": "Share this link with other registered users to give them access to the shared folder. Once they open this link, the shared folder will be added to their CryptDrive.",
"convertFolderToSF_SFParent": "This folder cannot be converted to a shared folder in its current location. Move it outside of the containing shared folder to continue.",
"convertFolderToSF_SFChildren": "This folder cannot be converted to a shared folder because it already contains shared folders. Move those Shared folders elsewhere to continue.",
"convertFolderToSF_confirm": "This folder must be converted to a Shared folder for others to view it. Continue?",
@@ -1242,5 +1241,6 @@
"teams_table_specificHint": "These are older shared folders where viewers still have permission to edit existing pads. Pads created or copied into these folders will have standard permissions.",
"teams_table_admins": "Manage members",
"teams_table_owners": "Manage team",
- "teams_table_role": "Role"
+ "teams_table_role": "Role",
+ "pad_wordCount": "Words: {0}"
}
diff --git a/www/common/translations/messages.nb.json b/www/common/translations/messages.nb.json
index 14790aee9..9d5cd285f 100644
--- a/www/common/translations/messages.nb.json
+++ b/www/common/translations/messages.nb.json
@@ -161,7 +161,6 @@
"viewOpenTitle": "Åpne denne paden i lesemodus i en ny fane",
"fileShare": "Kopier linken",
"getEmbedCode": "Hent innlagt kode",
- "viewEmbedTitle": "Legg inn paden i en ekstern side",
"canvas_width": "Bredde",
"canvas_opacity": "Gjennomsiktighet",
"canvas_opacityLabel": "Gjennomsiktighet:{0}",
diff --git a/www/common/translations/messages.pt-br.json b/www/common/translations/messages.pt-br.json
index 5764745d9..59b70b275 100644
--- a/www/common/translations/messages.pt-br.json
+++ b/www/common/translations/messages.pt-br.json
@@ -404,7 +404,6 @@
"viewOpen": "",
"viewOpenTitle": "",
"getEmbedCode": "",
- "viewEmbedTitle": "",
"viewEmbedTag": "",
"fileEmbedTitle": "",
"fileEmbedScript": "",
diff --git a/www/common/translations/messages.ro.json b/www/common/translations/messages.ro.json
index 9b8ad7c57..56eab943a 100644
--- a/www/common/translations/messages.ro.json
+++ b/www/common/translations/messages.ro.json
@@ -392,7 +392,6 @@
"themeButton": "Temă",
"themeButtonTitle": "Alege tema de culori de folosit pentru cod si editorul slide-urilor",
"fileShare": "Copiază linkul",
- "viewEmbedTitle": "Include pad-ul într-o pagină externă",
"fileEmbedTitle": "Include fișierul într-o pagină externă",
"fileEmbedTag": "După care plasează această etichetă Media oriunde pe pagina unde vrei sa o plasezi",
"ok": "Ok",
diff --git a/www/common/translations/messages.ru.json b/www/common/translations/messages.ru.json
index 62914d82a..66cce1d63 100644
--- a/www/common/translations/messages.ru.json
+++ b/www/common/translations/messages.ru.json
@@ -168,7 +168,6 @@
"viewOpenTitle": "Открыть данный документ для чтения в новой вкладке",
"fileShare": "Скопировать ссылку",
"getEmbedCode": "Получить код для встраивания",
- "viewEmbedTitle": "Встроить документ во внешнюю страницу",
"notifyJoined": "{0} присоединился к совместной сессии",
"notifyRenamed": "{0} теперь известен как {1}",
"notifyLeft": "{0} покинул совместную сессию",
diff --git a/www/debug/inner.js b/www/debug/inner.js
index 3373b4803..3a98b883e 100644
--- a/www/debug/inner.js
+++ b/www/debug/inner.js
@@ -439,7 +439,12 @@ define([
console.log(doc);
};
- config.onLocal = function () { };
+ var toRestore;
+
+ config.onLocal = function (a, restore) {
+ if (!toRestore || !restore) { return; }
+ cpNfInner.chainpad.contentUpdate(toRestore);
+ };
config.onInit = function (info) {
Title = common.createTitle({});
@@ -459,10 +464,13 @@ define([
/* add a history button */
var histConfig = {
- onLocal: config.onLocal,
+ onLocal: function () {
+ config.onLocal(null, true);
+ },
onRemote: config.onRemote,
setHistory: setHistory,
applyVal: function (val) {
+ toRestore = val;
displayDoc(JSON.parse(val) || {});
},
$toolbar: $bar,
diff --git a/www/kanban/inner.js b/www/kanban/inner.js
index 2b469cb3f..c2d845557 100644
--- a/www/kanban/inner.js
+++ b/www/kanban/inner.js
@@ -399,18 +399,24 @@ define([
try {
var el = getSelectedElement();
var input = $(el).is('input') ? el : $(el).find('input')[0];
- var $item = $(el).closest('.kanban-item');
+ if (!input) { return; }
+ var $input = $(input);
- var pos = kanban.findElementPosition($item[0]);
- var board = $item.closest('.kanban-board').attr('data-id');
- var val = ($(input).val && $(input).val()) || '';
+ var pos;
+ var $item = $(el).closest('.kanban-item');
+ if ($item.length) {
+ pos = kanban.findElementPosition($item[0]);
+ }
+ var board = $input.closest('.kanban-board').attr('data-id');
+ var val = ($input.val && $input.val()) || '';
var start = input.selectionStart;
var end = input.selectionEnd;
+
var boardEl = kanban.options.boards.find(function (b) {
return b.id === board;
});
- var oldVal = boardEl.item[pos] || {};
+ var oldVal = ((pos ? boardEl.item[pos] : boardEl) || {}).title;
return {
board: board,
@@ -418,7 +424,7 @@ define([
value: val,
start: start,
end: end,
- oldValue: oldVal.title
+ oldValue: oldVal
};
} catch (e) {
return {};
@@ -431,9 +437,25 @@ define([
});
if (!boardEl) { return; }
+ var $board = $('.kanban-board[data-id="'+data.board+'"');
+
+ // Editing a board title...
+ if (!data.pos && $board.length) {
+ if (boardEl.title !== data.oldValue) { return; }
+ $board.find('.kanban-title-board').click();
+ var $boardInput = $board.find('.kanban-title-board input');
+ $boardInput.val(data.value);
+ $boardInput[0].selectionStart = data.start;
+ $boardInput[0].selectionEnd = data.end;
+ return;
+ }
+ // Editing a deleted board title: abort
+ if (!data.pos) {
+ return;
+ }
+
// An item was added: add a new item
if (!data.oldValue) {
- var $board = $('.kanban-board[data-id="'+data.board+'"');
$board.find('.kanban-title-button.fa-plus').click();
var $newInput = $board.find('.kanban-item:last-child input');
$newInput.val(data.value);
diff --git a/www/notifications/inner.js b/www/notifications/inner.js
index 6fc8bf1ca..2e89c5078 100644
--- a/www/notifications/inner.js
+++ b/www/notifications/inner.js
@@ -93,6 +93,10 @@ define([
return ud.content.hash === data.content.hash;
});
notifsData.push(data);
+ if (data.content.msg.type === 'REQUEST_PAD_ACCESS') { return; } // FIXME find a way to display this notifications wihtout knowing the title
+ if (data.content.msg.type === 'INVITE_TO_TEAM_ANSWER') { console.log(data); }
+ if (data.content.msg.type === 'INVITE_TO_TEAM_ANSWER'
+ && !data.content.msg.content.teamName) { return; } // FIXME find a way to display this notifications wihtout knowing the team name
var el = common.mailbox.createElement(data);
var time = new Date(data.content.time);
$(el).find(".cp-notification-content").append(h("span.notification-time", time.toLocaleString()));
diff --git a/www/pad/app-pad.less b/www/pad/app-pad.less
index 51b8f7d0b..ca8b10d18 100644
--- a/www/pad/app-pad.less
+++ b/www/pad/app-pad.less
@@ -17,6 +17,13 @@ body.cp-app-pad {
height: 28px;
padding: 2px 0;
}
+ .cp-app-pad-wordCount {
+ float: right;
+ display: inline-flex;
+ height: 24px;
+ align-items: center;
+ padding: 4px;
+ }
}
.cke_wysiwyg_frame {
width: 100%;
diff --git a/www/pad/inner.js b/www/pad/inner.js
index b3e687228..5db93837c 100644
--- a/www/pad/inner.js
+++ b/www/pad/inner.js
@@ -616,6 +616,8 @@ define([
var patch = (DD).diff(inner, userDocStateDom);
(DD).apply(inner, patch);
+ editor.fire('cp-wc'); // Update word count
+
// Restore cursor position
var newText = inner.outerHTML;
var ops = ChainPad.Diff.diff(oldText, newText);
@@ -835,9 +837,20 @@ define([
inner.addEventListener('input', function () {
framework.localChange();
updateCursor();
+ editor.fire('cp-wc'); // Update word count
});
editor.on('change', framework.localChange);
+ var wordCount = h('span.cp-app-pad-wordCount');
+ $('.cke_toolbox_main').append(wordCount);
+ editor.on('cp-wc-update', function () {
+ if (!editor.wordCount || typeof (editor.wordCount.wordCount) === "undefined") {
+ wordCount.innerText = '';
+ return;
+ }
+ wordCount.innerText = Messages._getKey('pad_wordCount', [editor.wordCount.wordCount]);
+ });
+
// export the typing tests to the window.
// call like `test = easyTest()`
// terminate the test like `test.cancel()`
@@ -949,6 +962,7 @@ define([
};
Ckeditor.plugins.addExternal('mediatag','/pad/', 'mediatag-plugin.js');
Ckeditor.plugins.addExternal('blockbase64','/pad/', 'disable-base64.js');
+ Ckeditor.plugins.addExternal('wordcount','/pad/wordcount/', 'plugin.js');
module.ckeditor = editor = Ckeditor.replace('editor1', {
customConfig: '/customize/ckeditor-config.js',
});
diff --git a/www/pad/wordcount/LICENSE.md b/www/pad/wordcount/LICENSE.md
new file mode 100644
index 000000000..be0064ffb
--- /dev/null
+++ b/www/pad/wordcount/LICENSE.md
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) Ingo Herbote
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/www/pad/wordcount/README.md b/www/pad/wordcount/README.md
new file mode 100644
index 000000000..7605bb622
--- /dev/null
+++ b/www/pad/wordcount/README.md
@@ -0,0 +1,106 @@
+CKEditor-WordCount-Plugin
+=========================
+
+WordCount Plugin for CKEditor v4 (or above) that counts the words/characters an shows the word count and/or char count in the footer of the editor.
+
+![Screenshot](http://www.watchersnet.de/Portals/0/screenshots/dnn/CKEditorWordCountPlugin.png)
+
+#### Demo
+
+http://w8tcha.github.com/CKEditor-WordCount-Plugin/
+
+DISCLAIMER: This is a forked Version, i can not find the original Author anymore if anyone knows the original Author please contact me and i can include the Author in the Copyright Notices.
+
+#### License
+
+Licensed under the terms of the MIT License.
+
+#### Installation
+
+ If building a new editor using the CKBuilder from http://ckeditor.com/, there is no need to follow numbers steps below. If adding the Word Count & Char Count plugin to an already established CKEditor, follow the numbered steps below.
+
+1. Download the Word Count & Char Count plugin from http://ckeditor.com/addon/wordcount or https://github.com/w8tcha/CKEditor-WordCount-Plugin. This will download a folder named **wordcount_*version*.zip** or **CKEditor-WordCount-Plugin-master.zip** to your Downloads folder.
+2. Download the Notification plugin from http://ckeditor.com/addon/notification. This will download a folder named **notification_*version*.zip** to your Downloads folder.
+3. Extract the .zip folders for both the Word Count & Char Count and Notification plugin. After extraction, you should have a folder named **wordcount** and a folder named **notification**.
+4. Move the wordcount folder to /web/server/root/ckeditor/plugins/. Move the notification folder to /web/server/root/ckeditor/plugins/.
+5. Add the following line of text to the config.js file, which is located at /web/server/root/ckeditor/.
+
+```javascript
+config.extraPlugins = 'wordcount,notification';
+```
+
+Below is an example of what your config.js file might look like after adding config.extraPlugins = 'wordcount,notification';
+
+```javascript
+CKEDITOR.editorConfig = function( config ) {
+ config.extraPlugins = 'wordcount,notification';
+ config.toolbar [
+ et cetera . . .
+ ];
+};
+```
+
+There now should be text in the bottom right-hand corner of your CKEditor which counts the number of Paragraphs and number of Words in your CKEditor.
+
+To modify the behavior of the Word Count & Char Count text at the bottom right-hand corner of your CKEditor, add the following text to your config.js file located at /web/server/root/ckeditor/config.js.
+
+````js
+config.wordcount = {
+
+ // Whether or not you want to show the Paragraphs Count
+ showParagraphs: true,
+
+ // Whether or not you want to show the Word Count
+ showWordCount: true,
+
+ // Whether or not you want to show the Char Count
+ showCharCount: false,
+
+ // Whether or not you want to count Spaces as Chars
+ countSpacesAsChars: false,
+
+ // Whether or not to include Html chars in the Char Count
+ countHTML: false,
+
+ // Whether or not to include Line Breaks in the Char Count
+ countLineBreaks: false,
+
+ // Maximum allowed Word Count, -1 is default for unlimited
+ maxWordCount: -1,
+
+ // Maximum allowed Char Count, -1 is default for unlimited
+ maxCharCount: -1,
+
+ // Maximum allowed Paragraphs Count, -1 is default for unlimited
+ maxParagraphs: -1,
+
+ // How long to show the 'paste' warning, 0 is default for not auto-closing the notification
+ pasteWarningDuration: 0,
+
+
+ // Add filter to add or remove element before counting (see CKEDITOR.htmlParser.filter), Default value : null (no filter)
+ filter: new CKEDITOR.htmlParser.filter({
+ elements: {
+ div: function( element ) {
+ if(element.attributes.class == 'mediaembed') {
+ return false;
+ }
+ }
+ }
+ })
+};
+````
+
+**Note:** If you plan to change some of the JavaScript, you probably will not want to use the CKBuilder, because this will place the JavaScript of the Word Count & Char Count plugin in the ckeditor.js file located at /web/server/root/ckeditor/ckeditor.js. The JavaScript for the Word Count & Char Count plugin in the ckeditor.js file is different than the JavaScript used when manually adding the Word Count & Char Count plugin. When manually adding the Word Count & Char Count plugin, the JavaScript will be in the plugin.js file located at
+
+---
+
+If you want to query the current wordcount you can do it via
+
+```javascript
+// get the word count
+CKEDITOR.instances.editor1.wordCount.wordCount
+
+// get the char count
+CKEDITOR.instances.editor1.wordCount.charCount
+```
diff --git a/www/pad/wordcount/css/wordcount.css b/www/pad/wordcount/css/wordcount.css
new file mode 100644
index 000000000..36f86d41d
--- /dev/null
+++ b/www/pad/wordcount/css/wordcount.css
@@ -0,0 +1,3 @@
+.cke_wordcount {display:block;float:right;margin-top:-2px;margin-right:3px;color:black;}
+
+.cke_wordcountLimitReached {color:red! important}
\ No newline at end of file
diff --git a/www/pad/wordcount/lang/ar.js b/www/pad/wordcount/lang/ar.js
new file mode 100644
index 000000000..fd9125c46
--- /dev/null
+++ b/www/pad/wordcount/lang/ar.js
@@ -0,0 +1,12 @@
+// Arabic Translation by Amine BENHAMIDA
+
+CKEDITOR.plugins.setLang('wordcount', 'ar', {
+ WordCount: 'كلمات:',
+ CharCount: 'حروف:',
+ CharCountWithHTML: 'حروف مع إتش تي إم إل',
+ Paragraphs: 'فقرات',
+ ParagraphsRemaining: 'Paragraphs remaining',
+ pasteWarning: 'لا يمكن اضافة هذا المحتوى لانه تجاوز الحد الاقصى',
+ Selected: 'محدد: ',
+ title: 'احصائيات'
+});
diff --git a/www/pad/wordcount/lang/bg.js b/www/pad/wordcount/lang/bg.js
new file mode 100644
index 000000000..69e1e3f77
--- /dev/null
+++ b/www/pad/wordcount/lang/bg.js
@@ -0,0 +1,17 @@
+/*
+Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang('wordcount', 'bg', {
+ WordCount: 'Думи:',
+ WordCountRemaining: 'Оставащи думи',
+ CharCount: 'Знаци:',
+ CharCountRemaining: 'Знаци',
+ CharCountWithHTML: 'Знаци (с HTML):',
+ CharCountWithHTMLRemaining: 'Оставащи знаци (с HTML)',
+ Paragraphs: 'Параграфи:',
+ ParagraphsRemaining: 'Paragraphs remaining',
+ pasteWarning: 'Съдържанието не може да бъде поставено, защото е над разрешения лимит',
+ Selected: 'Избрани: ',
+ title: 'Статистика'
+});
diff --git a/www/pad/wordcount/lang/ca.js b/www/pad/wordcount/lang/ca.js
new file mode 100644
index 000000000..2c8f4948a
--- /dev/null
+++ b/www/pad/wordcount/lang/ca.js
@@ -0,0 +1,14 @@
+/*
+Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang('wordcount', 'ca', {
+ WordCount: 'Paraules:',
+ CharCount: 'Caràcters:',
+ CharCountWithHTML: 'Caràcters (including HTML):',
+ Paragraphs: 'Paragraphs:',
+ ParagraphsRemaining: 'Paragraphs remaining',
+ pasteWarning: 'Content can not be pasted because it is above the allowed limit',
+ Selected: 'Selected: ',
+ title: 'Estadístiques'
+});
diff --git a/www/pad/wordcount/lang/cs.js b/www/pad/wordcount/lang/cs.js
new file mode 100644
index 000000000..616c64365
--- /dev/null
+++ b/www/pad/wordcount/lang/cs.js
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang('wordcount', 'cs',
+ {
+ WordCount: 'Slov: ',
+ CharCount: 'Znaků: ',
+ CharCountWithHTML: 'Znaků (s HTML): ',
+ Paragraphs: 'Odstavců: ',
+ ParagraphsRemaining: 'Paragraphs remaining',
+ pasteWarning: 'Obsah nelze vložit',
+ Selected: 'Výběr: ',
+ title: 'Statistika'
+ });
\ No newline at end of file
diff --git a/www/pad/wordcount/lang/da.js b/www/pad/wordcount/lang/da.js
new file mode 100644
index 000000000..ada03a553
--- /dev/null
+++ b/www/pad/wordcount/lang/da.js
@@ -0,0 +1,14 @@
+/*
+Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang('wordcount', 'da', {
+ WordCount: 'Ord:',
+ CharCount: 'Karakterer:',
+ CharCountWithHTML: 'Karakterer (med HTML):',
+ Paragraphs: 'Afsnit:',
+ ParagraphsRemaining: 'Paragraphs remaining',
+ pasteWarning: 'Indholdet kan ikke indsættes da det er længere end den tilladte grænse.',
+ Selected: 'Markeret: ',
+ title: 'Statistik'
+});
diff --git a/www/pad/wordcount/lang/de.js b/www/pad/wordcount/lang/de.js
new file mode 100644
index 000000000..47501ab40
--- /dev/null
+++ b/www/pad/wordcount/lang/de.js
@@ -0,0 +1,14 @@
+/*
+Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang('wordcount', 'de', {
+ WordCount: 'Wörter:',
+ CharCount: 'Zeichen:',
+ CharCountWithHTML: 'Zeichen (inkl. HTML):',
+ Paragraphs: 'Absätze:',
+ ParagraphsRemaining: 'Paragraphs remaining',
+ pasteWarning: 'Content can not be pasted because it is above the allowed limit',
+ Selected: 'Selected: ',
+ title: 'Statistik'
+});
diff --git a/www/pad/wordcount/lang/el.js b/www/pad/wordcount/lang/el.js
new file mode 100644
index 000000000..76d0cc421
--- /dev/null
+++ b/www/pad/wordcount/lang/el.js
@@ -0,0 +1,14 @@
+/*
+Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang('wordcount', 'el', {
+ WordCount: 'Λέξεις:',
+ CharCount: 'Χαρακτήρες:',
+ CharCountWithHTML: 'Χαρακτήρες (μαζί με HTML):',
+ Paragraphs: 'Paragraphs:',
+ ParagraphsRemaining: 'Paragraphs remaining',
+ pasteWarning: 'Content can not be pasted because it is above the allowed limit',
+ Selected: 'Selected: ',
+ title: 'Στατιστικά'
+});
diff --git a/www/pad/wordcount/lang/en.js b/www/pad/wordcount/lang/en.js
new file mode 100644
index 000000000..bb566ee47
--- /dev/null
+++ b/www/pad/wordcount/lang/en.js
@@ -0,0 +1,17 @@
+/*
+Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang('wordcount', 'en', {
+ WordCount: 'Words:',
+ WordCountRemaining: 'Words remaining',
+ CharCount: 'Characters:',
+ CharCountRemaining: 'Characters remaining',
+ CharCountWithHTML: 'Characters (with HTML):',
+ CharCountWithHTMLRemaining: 'Characters (with HTML) remaining',
+ Paragraphs: 'Paragraphs:',
+ ParagraphsRemaining: 'Paragraphs remaining',
+ pasteWarning: 'Content cannot be pasted because it is above the allowed limit',
+ Selected: 'Selected: ',
+ title: 'Statistics'
+});
diff --git a/www/pad/wordcount/lang/es.js b/www/pad/wordcount/lang/es.js
new file mode 100644
index 000000000..03abaa7ce
--- /dev/null
+++ b/www/pad/wordcount/lang/es.js
@@ -0,0 +1,14 @@
+/*
+Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang('wordcount', 'es', {
+ WordCount: 'Palabras:',
+ CharCount: 'Carácteres:',
+ CharCountWithHTML: 'Carácteres (con HTML):',
+ Paragraphs: 'Párrafos:',
+ ParagraphsRemaining: 'Paragraphs remaining',
+ pasteWarning: 'El contenido no se puede pegar, ya que se encuentra fuera del límite permitido',
+ Selected: 'Seleccionado: ',
+ title: 'Estadísticas'
+});
diff --git a/www/pad/wordcount/lang/eu.js b/www/pad/wordcount/lang/eu.js
new file mode 100644
index 000000000..a8b61e66d
--- /dev/null
+++ b/www/pad/wordcount/lang/eu.js
@@ -0,0 +1,17 @@
+/*
+Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang('wordcount', 'eu', {
+ WordCount: 'Hitzak:',
+ WordCountRemaining: 'Gelditzen diren hitzak',
+ CharCount: 'Karaktereak:',
+ CharCountRemaining: 'Gelditzen diren karaktereak',
+ CharCountWithHTML: 'Karaktereak (HTMLarekin):',
+ CharCountWithHTMLRemaining: 'Gelditzen diren karaktereak (HTMLarekin)',
+ Paragraphs: 'Paragrafoak:',
+ ParagraphsRemaining: 'Gelditzen diren paragrafoak',
+ pasteWarning: 'Ezin da edukia itsatsi, onartutako muga gainditu duelako',
+ Selected: 'Hautatuta: ',
+ title: 'Estatistikak'
+});
diff --git a/www/pad/wordcount/lang/fa.js b/www/pad/wordcount/lang/fa.js
new file mode 100644
index 000000000..46060bcdb
--- /dev/null
+++ b/www/pad/wordcount/lang/fa.js
@@ -0,0 +1,13 @@
+/*
+Its The Persian (Farsi) Language Translate For Iranian By "Mohsen Esmaili"
+*/
+CKEDITOR.plugins.setLang('wordcount', 'fa', {
+ WordCount: 'لغت:',
+ CharCount: 'کاراکتر:',
+ CharCountWithHTML: 'کاراکترها (با HTML):',
+ Paragraphs: 'پاراگراف:',
+ ParagraphsRemaining: 'Paragraphs remaining',
+ pasteWarning: 'محتوای مورد نظر را نمی توان چسباند. زیرا این بیشتر از حد مجاز است.',
+ Selected: 'انتخاب شده: ',
+ title: 'آمار'
+});
\ No newline at end of file
diff --git a/www/pad/wordcount/lang/fi.js b/www/pad/wordcount/lang/fi.js
new file mode 100644
index 000000000..ef0f1fa4b
--- /dev/null
+++ b/www/pad/wordcount/lang/fi.js
@@ -0,0 +1,15 @@
+/**
+ * Finnish localisation.
+ *
+ * @author Joel Posti / Response200.pro
+ */
+CKEDITOR.plugins.setLang('wordcount', 'fi', {
+ WordCount: 'Sanoja:',
+ CharCount: 'Merkkejä:',
+ CharCountWithHTML: 'Merkkejä (ml. HTML):',
+ Paragraphs: 'Kappaleita:',
+ ParagraphsRemaining: 'Paragraphs remaining',
+ pasteWarning: 'Sisältöä ei voida liittää, koska se ylittää sallitun rajan.',
+ Selected: 'Valittuna: ',
+ title: 'Statistiikkaa'
+});
diff --git a/www/pad/wordcount/lang/fr.js b/www/pad/wordcount/lang/fr.js
new file mode 100644
index 000000000..45c56644d
--- /dev/null
+++ b/www/pad/wordcount/lang/fr.js
@@ -0,0 +1,12 @@
+// French Translation by Nicolas M. et Pierre-Luc Auclair
+
+CKEDITOR.plugins.setLang('wordcount', 'fr', {
+ WordCount: 'Mots :',
+ CharCount: 'Caractères :',
+ CharCountWithHTML: 'Caractères (incluant HTML) :',
+ Paragraphs: 'Paragraphes :',
+ ParagraphsRemaining: 'Paragraphs remaining',
+ pasteWarning: 'Le contenu ne peut pas être collé car il dépasse la limite autorisée',
+ Selected: 'Sélectionné :',
+ title: 'Statistiques'
+});
diff --git a/www/pad/wordcount/lang/he.js b/www/pad/wordcount/lang/he.js
new file mode 100644
index 000000000..4da45ae02
--- /dev/null
+++ b/www/pad/wordcount/lang/he.js
@@ -0,0 +1,14 @@
+/*
+Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang('wordcount', 'he', {
+ WordCount: 'מילים:',
+ CharCount: 'תווים:',
+ CharCountWithHTML: 'תווים (כולל HTML):',
+ Paragraphs: 'פסקאות:',
+ ParagraphsRemaining: 'Paragraphs remaining',
+ pasteWarning: 'לא ניתן להדביק תוכן בשל עודף תווים',
+ Selected: 'נבחר: ',
+ title: 'סטטיסטיקות'
+});
\ No newline at end of file
diff --git a/www/pad/wordcount/lang/hr.js b/www/pad/wordcount/lang/hr.js
new file mode 100644
index 000000000..01020b79a
--- /dev/null
+++ b/www/pad/wordcount/lang/hr.js
@@ -0,0 +1,14 @@
+/*
+Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang('wordcount', 'hr', {
+ WordCount: 'Riječi:',
+ CharCount: 'Znakova:',
+ CharCountWithHTML: 'Znakova (uključujući HTML):',
+ Paragraphs: 'Paragraphs:',
+ ParagraphsRemaining: 'Paragraphs remaining',
+ pasteWarning: 'Content can not be pasted because it is above the allowed limit',
+ Selected: 'Selected: ',
+ title: 'Statistika'
+});
diff --git a/www/pad/wordcount/lang/hu.js b/www/pad/wordcount/lang/hu.js
new file mode 100644
index 000000000..11c251e01
--- /dev/null
+++ b/www/pad/wordcount/lang/hu.js
@@ -0,0 +1,14 @@
+/*
+Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang('wordcount', 'hu', {
+ WordCount: 'Szavak:',
+ CharCount: 'Karakaterek:',
+ CharCountWithHTML: 'Karakterek (HTML tagekkel):',
+ Paragraphs: 'Bekezdések:',
+ ParagraphsRemaining: 'Paragraphs remaining',
+ pasteWarning: 'A szöveget nem lehet beilleszteni, mert a megadott limit felett van',
+ Selected: 'Kiválasztva: ',
+ title: 'Statisztika'
+});
diff --git a/www/pad/wordcount/lang/it.js b/www/pad/wordcount/lang/it.js
new file mode 100644
index 000000000..a8b451df9
--- /dev/null
+++ b/www/pad/wordcount/lang/it.js
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+@author translation: Davide Montorio
+*/
+CKEDITOR.plugins.setLang('wordcount', 'it', {
+ WordCount: 'Parole:',
+ CharCount: 'Caratteri:',
+ CharCountWithHTML: 'Caratteri (HTML incluso):',
+ Paragraphs: 'Paragrafi:',
+ ParagraphsRemaining: 'Paragraphs remaining',
+ pasteWarning: 'Il contenuto non può essere incollato poiché supera il limite massimo di caratteri disponibili',
+ Selected: 'Selezionato: ',
+ title: 'Statistiche'
+});
diff --git a/www/pad/wordcount/lang/ja.js b/www/pad/wordcount/lang/ja.js
new file mode 100644
index 000000000..c12f1e19a
--- /dev/null
+++ b/www/pad/wordcount/lang/ja.js
@@ -0,0 +1,14 @@
+/*
+Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang('wordcount', 'ja', {
+ WordCount: '単語数:',
+ CharCount: '文字数:',
+ CharCountWithHTML: '文字数 (HTMLタグを含む):',
+ Paragraphs: '段落数:',
+ ParagraphsRemaining: 'Paragraphs remaining',
+ pasteWarning: '文字数/単語数の上限を超えるため、貼り付けできません。',
+ Selected: '選択中の字数:',
+ title: 'ワードカウント'
+});
diff --git a/www/pad/wordcount/lang/ko.js b/www/pad/wordcount/lang/ko.js
new file mode 100644
index 000000000..9cff8e1fa
--- /dev/null
+++ b/www/pad/wordcount/lang/ko.js
@@ -0,0 +1,16 @@
+/*
+Korean translation by Maxime Houdais
+*/
+CKEDITOR.plugins.setLang('wordcount', 'ko', {
+ WordCount: '단어:',
+ WordCountRemaining: '남은 단어',
+ CharCount: '글자:',
+ CharCountRemaining: '남은 글자',
+ CharCountWithHTML: '글자 와 HTML:',
+ CharCountWithHTMLRemaining: '남은 글자 와 HTML',
+ Paragraphs: '단락:',
+ ParagraphsRemaining: 'Paragraphs remaining',
+ pasteWarning: '허용 된 한도를 초과하여 콘텐츠를 붙여 넣을 수 없습니다.',
+ Selected: '선택:',
+ title: '통계'
+});
diff --git a/www/pad/wordcount/lang/nl.js b/www/pad/wordcount/lang/nl.js
new file mode 100644
index 000000000..9bcad987a
--- /dev/null
+++ b/www/pad/wordcount/lang/nl.js
@@ -0,0 +1,14 @@
+/*
+Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang('wordcount', 'nl', {
+ WordCount: 'Woorden:',
+ CharCount: 'Tekens:',
+ CharCountWithHTML: 'Tekens (inclusief HTML):',
+ Paragraphs: 'Paragrafen:',
+ ParagraphsRemaining: 'Paragraphs remaining',
+ pasteWarning: 'De tekst kan niet worden geplakt omdat de limiet is overschreden',
+ Selected: 'Geselecteerd: ',
+ title: 'Statistieken'
+});
diff --git a/www/pad/wordcount/lang/no.js b/www/pad/wordcount/lang/no.js
new file mode 100644
index 000000000..2c33fe528
--- /dev/null
+++ b/www/pad/wordcount/lang/no.js
@@ -0,0 +1,11 @@
+// Norwegian translation by Vegard S.
+CKEDITOR.plugins.setLang('wordcount', 'no', {
+ WordCount: 'Ord:',
+ CharCount: 'Tegn:',
+ CharCountWithHTML: 'Tegn (including HTML):',
+ Paragraphs: 'Paragraphs:',
+ ParagraphsRemaining: 'Paragraphs remaining',
+ pasteWarning: 'Content can not be pasted because it is above the allowed limit',
+ Selected: 'Selected: ',
+ title: 'Statistikk'
+});
diff --git a/www/pad/wordcount/lang/pl.js b/www/pad/wordcount/lang/pl.js
new file mode 100644
index 000000000..e6a3d2e07
--- /dev/null
+++ b/www/pad/wordcount/lang/pl.js
@@ -0,0 +1,14 @@
+/*
+Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang('wordcount', 'pl', {
+ WordCount: 'Słów:',
+ CharCount: 'Znaków:',
+ CharCountWithHTML: 'Znaków (wraz z kodem HTML):',
+ Paragraphs: 'Paragrafy:',
+ ParagraphsRemaining: 'Paragraphs remaining',
+ pasteWarning: 'Zawartość nie może zostać wklejona, ponieważ przekracza dozwolony limit',
+ Selected: 'Zaznaczono: ',
+ title: 'Statystyka'
+});
diff --git a/www/pad/wordcount/lang/pt-br.js b/www/pad/wordcount/lang/pt-br.js
new file mode 100644
index 000000000..393ac5eca
--- /dev/null
+++ b/www/pad/wordcount/lang/pt-br.js
@@ -0,0 +1,14 @@
+/*
+Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang('wordcount', 'pt-br', {
+ WordCount: 'Contagem de palavras:',
+ CharCount: 'Contagem de carateres:',
+ CharCountWithHTML: 'Carateres (incluindo HTML):',
+ Paragraphs: 'Parágrafos:',
+ ParagraphsRemaining: 'Paragraphs remaining',
+ pasteWarning: 'Conteúdo não pode ser colado porque ultrapassa o limite permitido',
+ Selected: 'Selecionado: ',
+ title: 'Estatísticas'
+});
diff --git a/www/pad/wordcount/lang/pt.js b/www/pad/wordcount/lang/pt.js
new file mode 100644
index 000000000..8d28496e2
--- /dev/null
+++ b/www/pad/wordcount/lang/pt.js
@@ -0,0 +1,10 @@
+CKEDITOR.plugins.setLang('wordcount', 'pt', {
+ WordCount: 'Palavras:',
+ CharCount: 'Caracteres:',
+ CharCountWithHTML: 'Carateres (incluindo HTML):',
+ Paragraphs: 'Parágrafos:',
+ ParagraphsRemaining: 'Paragraphs remaining',
+ pasteWarning: 'O conteúdo não pode ser colado porque ultrapassa o limite permitido',
+ Selected: 'Selecionado: ',
+ title: 'Estatísticas'
+});
diff --git a/www/pad/wordcount/lang/ro.js b/www/pad/wordcount/lang/ro.js
new file mode 100644
index 000000000..4f214065a
--- /dev/null
+++ b/www/pad/wordcount/lang/ro.js
@@ -0,0 +1,15 @@
+// Romanian Translation by Bogdanov Mihail
+
+CKEDITOR.plugins.setLang('wordcount', 'ro', {
+ WordCount: 'Numar cuvinte',
+ WordCountRemaining: 'Cuvinte ramase',
+ CharCount: 'Numar caracter:',
+ CharCountRemaining: 'Caractere ramase:',
+ CharCountWithHTML: 'Numar caractere (cu HTML):',
+ CharCountWithHTMLRemaining: 'Caractere (cu HTML) ramase',
+ Paragraphs: 'Paragrafe:',
+ ParagraphsRemaining: 'Paragrafe ramase',
+ pasteWarning: 'Continutul nu poate fi adaugat deoarece este mai mare decat limita setata',
+ Selected: 'Selectat:',
+ title: 'Statistici'
+});
\ No newline at end of file
diff --git a/www/pad/wordcount/lang/ru.js b/www/pad/wordcount/lang/ru.js
new file mode 100644
index 000000000..d5dcb42a9
--- /dev/null
+++ b/www/pad/wordcount/lang/ru.js
@@ -0,0 +1,14 @@
+/*
+Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang('wordcount', 'ru', {
+ WordCount: 'Слов:',
+ CharCount: 'Символов:',
+ CharCountWithHTML: ' (включая HTML-разметку):',
+ Paragraphs: 'Параграфов:',
+ ParagraphsRemaining: 'Параграфов осталось',
+ pasteWarning: 'Контент не может быть вставлен, т.к. привышает допустимый лимит',
+ Selected: 'Выделено: ',
+ title: 'Статистика'
+});
diff --git a/www/pad/wordcount/lang/sk.js b/www/pad/wordcount/lang/sk.js
new file mode 100644
index 000000000..87388ad78
--- /dev/null
+++ b/www/pad/wordcount/lang/sk.js
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang('wordcount', 'sk', {
+ WordCount: 'Slov:',
+ CharCount: 'Znakov:',
+ CharCountWithHTML: 'Znakov (vrátane HTML):',
+ Paragraphs: 'Odstavcov:',
+ ParagraphsRemaining: 'Paragraphs remaining',
+ pasteWarning: 'Obsah sa nedá prilepiť.',
+ Selected: 'Výber: ',
+ title: 'Štatistika'
+});
+
diff --git a/www/pad/wordcount/lang/sv.js b/www/pad/wordcount/lang/sv.js
new file mode 100644
index 000000000..8d4b12ee3
--- /dev/null
+++ b/www/pad/wordcount/lang/sv.js
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang('wordcount', 'sv', {
+ WordCount: 'Ord:',
+ CharCount: 'Tecken:',
+ CharCountRemaining: 'tecken återstår',
+ CharCountWithHTML: 'Tecken (inklusive HTML):',
+ Paragraphs: 'Paragraf:',
+ ParagraphsRemaining: 'Paragraphs remaining',
+ pasteWarning: 'Innehåll kan inte klistras in eftersom det överskrider den tillåtna gränsen',
+ Selected: 'Valt: ',
+ title: 'Statistik'
+});
diff --git a/www/pad/wordcount/lang/tr.js b/www/pad/wordcount/lang/tr.js
new file mode 100644
index 000000000..33953f037
--- /dev/null
+++ b/www/pad/wordcount/lang/tr.js
@@ -0,0 +1,14 @@
+/*
+Mesut ÇAKIR
+mesut.cakir@hotmail.com.tr
+*/
+CKEDITOR.plugins.setLang('wordcount', 'tr', {
+ WordCount: 'Kelime:',
+ CharCount: 'Karakter:',
+ CharCountWithHTML: 'Karakter (HTML dahil):',
+ Paragraphs: 'Paragraf:',
+ ParagraphsRemaining: 'Paragraphs remaining',
+ pasteWarning: 'Content can not be pasted because it is above the allowed limit',
+ Selected: 'Selected: ',
+ title: 'İstatistik'
+});
diff --git a/www/pad/wordcount/lang/uk.js b/www/pad/wordcount/lang/uk.js
new file mode 100644
index 000000000..d5914be3b
--- /dev/null
+++ b/www/pad/wordcount/lang/uk.js
@@ -0,0 +1,17 @@
+/*
+ Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved.
+ For licensing, see LICENSE.html or http://ckeditor.com/license
+ */
+CKEDITOR.plugins.setLang('wordcount', 'uk', {
+ WordCount: 'Слів:',
+ WordCountRemaining: 'Слів залишилося',
+ CharCount: 'Символів:',
+ CharCountRemaining: 'Символів залишилося',
+ CharCountWithHTML: 'Символів (включаючи HTML-розмітку):',
+ CharCountWithHTMLRemaining: 'Символів (включаючи HTML-розмітку) залишилося',
+ Paragraphs: 'Параграфів:',
+ ParagraphsRemaining: 'Параграфів залишилося',
+ pasteWarning: 'Контент не може бути вставлено, оскільки перевищує допустимий ліміт',
+ Selected: 'Виділено: ',
+ title: 'Статистика'
+});
diff --git a/www/pad/wordcount/lang/zh-cn.js b/www/pad/wordcount/lang/zh-cn.js
new file mode 100644
index 000000000..288a7f34a
--- /dev/null
+++ b/www/pad/wordcount/lang/zh-cn.js
@@ -0,0 +1,14 @@
+/*
+Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang('wordcount', 'zh-cn', {
+ WordCount: '词数:',
+ CharCount: '字符:',
+ CharCountWithHTML: '字符 (含HTML)',
+ Paragraphs: '段落:',
+ ParagraphsRemaining: 'Paragraphs remaining',
+ pasteWarning: '由于上限允许,内容不能粘贴',
+ Selected: '已选择: ',
+ title: '统计'
+});
diff --git a/www/pad/wordcount/lang/zh.js b/www/pad/wordcount/lang/zh.js
new file mode 100644
index 000000000..8d0df17b6
--- /dev/null
+++ b/www/pad/wordcount/lang/zh.js
@@ -0,0 +1,14 @@
+/*
+Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang('wordcount', 'zh', {
+ WordCount: '詞數:',
+ CharCount: '字數:',
+ CharCountWithHTML: '字數 (含HTML)',
+ Paragraphs: '段落:',
+ ParagraphsRemaining: 'Paragraphs remaining',
+ pasteWarning: '由於字數達到上限,內容不能粘貼',
+ Selected: '已選擇: ',
+ title: '統計'
+});
\ No newline at end of file
diff --git a/www/pad/wordcount/plugin.js b/www/pad/wordcount/plugin.js
new file mode 100644
index 000000000..c544ea9f5
--- /dev/null
+++ b/www/pad/wordcount/plugin.js
@@ -0,0 +1,330 @@
+/**
+ * @license Copyright (c) CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.html or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.add("wordcount",
+ {
+ lang: "ar,bg,ca,cs,da,de,el,en,es,eu,fa,fi,fr,he,hr,hu,it,ko,ja,nl,no,pl,pt,pt-br,ru,sk,sv,tr,uk,zh-cn,zh,ro", // %REMOVE_LINE_CORE%
+ version: "1.17.6",
+ requires: 'htmlwriter,notification,undo',
+ bbcodePluginLoaded: false,
+ onLoad: function() {
+ CKEDITOR.document.appendStyleSheet(this.path + "css/wordcount.css");
+ },
+ init: function(editor) {
+ var defaultFormat = "",
+ lastWordCount = -1,
+ lastCharCount = -1,
+ lastParagraphs = -1,
+ timeoutId = 0,
+ notification = null;
+
+ // Default Config
+ var defaultConfig = {
+ showRemaining: false,
+ showParagraphs: true,
+ showWordCount: true,
+ showCharCount: false,
+ countBytesAsChars: false,
+ countSpacesAsChars: false,
+ countHTML: false,
+ countLineBreaks: false,
+ hardLimit: true,
+ warnOnLimitOnly: false,
+
+ //MAXLENGTH Properties
+ maxWordCount: -1,
+ maxCharCount: -1,
+ maxParagraphs: -1,
+
+ // Filter
+ filter: null,
+ };
+
+ // Get Config & Lang
+ var config = CKEDITOR.tools.extend(defaultConfig, editor.config.wordcount || {}, true);
+
+ if (config.showParagraphs) {
+ if (config.maxParagraphs > -1) {
+ if (config.showRemaining) {
+ defaultFormat += "%paragraphsCount% " + editor.lang.wordcount.ParagraphsRemaining;
+ } else {
+ defaultFormat += editor.lang.wordcount.Paragraphs + " %paragraphsCount%";
+
+ defaultFormat += "/" + config.maxParagraphs;
+ }
+ } else {
+ defaultFormat += editor.lang.wordcount.Paragraphs + " %paragraphsCount%";
+ }
+ }
+
+ if (config.showParagraphs && (config.showWordCount || config.showCharCount)) {
+ defaultFormat += ", ";
+ }
+
+ if (config.showWordCount) {
+ if (config.maxWordCount > -1) {
+ if (config.showRemaining) {
+ defaultFormat += "%wordCount% " + editor.lang.wordcount.WordCountRemaining;
+ } else {
+ defaultFormat += editor.lang.wordcount.WordCount + " %wordCount%";
+
+ defaultFormat += "/" + config.maxWordCount;
+ }
+ } else {
+ defaultFormat += editor.lang.wordcount.WordCount + " %wordCount%";
+ }
+ }
+
+ if (config.showCharCount && config.showWordCount) {
+ defaultFormat += ", ";
+ }
+
+ if (config.showCharCount) {
+ if (config.maxCharCount > -1) {
+ if (config.showRemaining) {
+ defaultFormat += "%charCount% " +
+ editor.lang.wordcount[config.countHTML
+ ? "CharCountWithHTMLRemaining"
+ : "CharCountRemaining"];
+ } else {
+ defaultFormat += editor.lang.wordcount[config.countHTML
+ ? "CharCountWithHTML"
+ : "CharCount"] +
+ " %charCount%";
+
+ defaultFormat += "/" + config.maxCharCount;
+ }
+ } else {
+ defaultFormat += editor.lang.wordcount[config.countHTML ? "CharCountWithHTML" : "CharCount"] +
+ " %charCount%";
+ }
+ }
+
+ var format = defaultFormat;
+
+ bbcodePluginLoaded = typeof editor.plugins.bbcode != 'undefined';
+
+ function strip(html) {
+ if (bbcodePluginLoaded) {
+ // stripping out BBCode tags [...][/...]
+ return html.replace(/\[.*?\]/gi, '');
+ }
+
+ var tmp = document.createElement("div");
+
+ // Add filter before strip
+ html = filter(html);
+
+ tmp.innerHTML = html;
+
+ if (tmp.textContent == "" && typeof tmp.innerText == "undefined") {
+ return "";
+ }
+
+ return tmp.textContent || tmp.innerText;
+ }
+
+ /**
+ * Implement filter to add or remove before counting
+ * @param html
+ * @returns string
+ */
+ function filter(html) {
+ if (config.filter instanceof CKEDITOR.htmlParser.filter) {
+ var fragment = CKEDITOR.htmlParser.fragment.fromHtml(html),
+ writer = new CKEDITOR.htmlParser.basicWriter();
+ config.filter.applyTo(fragment);
+ fragment.writeHtml(writer);
+ return writer.getHtml();
+ }
+ return html;
+ }
+
+ function countCharacters(text) {
+ if (config.countHTML) {
+ return config.countBytesAsChars ? countBytes(filter(text)) : filter(text).length;
+ }
+
+ var normalizedText;
+
+ // strip body tags
+ if (editor.config.fullPage) {
+ var i = text.search(new RegExp("", "i"));
+ if (i != -1) {
+ var j = text.search(new RegExp("", "i"));
+ text = text.substring(i + 6, j);
+ }
+
+ }
+
+ normalizedText = text;
+
+ if (!config.countSpacesAsChars) {
+ normalizedText = text.replace(/\s/g, "").replace(/ /g, "");
+ }
+
+ if (config.countLineBreaks) {
+ normalizedText = normalizedText.replace(/(\r\n|\n|\r)/gm, " ");
+ } else {
+ normalizedText = normalizedText.replace(/(\r\n|\n|\r)/gm, "").replace(/ /gi, " ");
+ }
+
+ normalizedText = strip(normalizedText).replace(/^([\t\r\n]*)$/, "");
+
+ return config.countBytesAsChars ? countBytes(normalizedText) : normalizedText.length;
+ }
+
+ function countBytes(text) {
+ var count = 0, stringLength = text.length, i;
+ text = String(text || "");
+ for (i = 0; i < stringLength; i++) {
+ var partCount = encodeURI(text[i]).split("%").length;
+ count += partCount == 1 ? 1 : partCount - 1;
+ }
+ return count;
+ }
+
+ function countParagraphs(text) {
+ return (text.replace(/ /g, " ").replace(/(<([^>]+)>)/ig, "").replace(/^\s*$[\n\r]{1,}/gm, "++")
+ .split("++").length);
+ }
+
+ function countWords(text) {
+ var normalizedText = text.replace(/(\r\n|\n|\r)/gm, " ").replace(/^\s+|\s+$/g, "")
+ .replace(" ", " ");
+
+ normalizedText = strip(normalizedText);
+
+ var words = normalizedText.split(/\s+/);
+
+ for (var wordIndex = words.length - 1; wordIndex >= 0; wordIndex--) {
+ if (words[wordIndex].match(/^([\s\t\r\n]*)$/)) {
+ words.splice(wordIndex, 1);
+ }
+ }
+
+ return (words.length);
+ }
+
+ function updateCounter(editorInstance) {
+ var paragraphs = 0,
+ wordCount = 0,
+ charCount = 0,
+ text;
+
+ // BeforeGetData and getData events are fired when calling
+ // getData(). We can prevent this by passing true as an
+ // argument to getData(). This allows us to fire the events
+ // manually with additional event data: firedBy. This additional
+ // data helps differentiate calls to getData() made by
+ // wordCount plugin from calls made by other plugins/code.
+ editorInstance.fire("beforeGetData", { firedBy: "wordCount.updateCounter" }, editor);
+ text = editorInstance.getData(true);
+ editorInstance.fire("getData", { dataValue: text, firedBy: "wordCount.updateCounter" }, editor);
+
+ if (text) {
+ if (config.showCharCount) {
+ charCount = countCharacters(text);
+ }
+
+ if (config.showParagraphs) {
+ paragraphs = countParagraphs(text);
+ }
+
+ if (config.showWordCount) {
+ wordCount = countWords(text);
+ }
+ }
+
+ var html = format;
+ if (config.showRemaining) {
+ if (config.maxCharCount >= 0) {
+ html = html.replace("%charCount%", config.maxCharCount - charCount);
+ } else {
+ html = html.replace("%charCount%", charCount);
+ }
+
+ if (config.maxWordCount >= 0) {
+ html = html.replace("%wordCount%", config.maxWordCount - wordCount);
+ } else {
+ html = html.replace("%wordCount%", wordCount);
+ }
+
+ if (config.maxParagraphs >= 0) {
+ html = html.replace("%paragraphsCount%", config.maxParagraphs - paragraphs);
+ } else {
+ html = html.replace("%paragraphsCount%", paragraphs);
+ }
+ } else {
+ html = html.replace("%wordCount%", wordCount).replace("%charCount%", charCount).replace("%paragraphsCount%", paragraphs);
+ }
+
+ (editorInstance.config.wordcount || (editorInstance.config.wordcount = {})).wordCount = wordCount;
+ (editorInstance.config.wordcount || (editorInstance.config.wordcount = {})).charCount = charCount;
+
+ if (charCount == lastCharCount && wordCount == lastWordCount && paragraphs == lastParagraphs) {
+ if (charCount == config.maxCharCount || wordCount == config.maxWordCount || paragraphs > config.maxParagraphs) {
+ editorInstance.fire('saveSnapshot');
+ }
+ return true;
+ }
+
+ //If the limit is already over, allow the deletion of characters/words. Otherwise,
+ //the user would have to delete at one go the number of offending characters
+ var deltaWord = wordCount - lastWordCount;
+ var deltaChar = charCount - lastCharCount;
+ var deltaParagraphs = paragraphs - lastParagraphs;
+
+ lastWordCount = wordCount;
+ lastCharCount = charCount;
+ lastParagraphs = paragraphs;
+
+ if (lastWordCount == -1) {
+ lastWordCount = wordCount;
+ }
+ if (lastCharCount == -1) {
+ lastCharCount = charCount;
+ }
+ if (lastParagraphs == -1) {
+ lastParagraphs = paragraphs;
+ }
+
+ // update instance
+ editorInstance.wordCount =
+ {
+ paragraphs: paragraphs,
+ wordCount: wordCount,
+ charCount: charCount
+ };
+ editor.fire('cp-wc-update');
+
+ return true;
+ }
+
+ function isCloseToLimits() {
+ if (config.maxWordCount > -1 && config.maxWordCount - lastWordCount < 5) {
+ return true;
+ }
+
+ if (config.maxCharCount > -1 && config.maxCharCount - lastCharCount < 20) {
+ return true;
+ }
+
+ if (config.maxParagraphs > -1 && config.maxParagraphs - lastParagraphs < 1) {
+ return true;
+ }
+
+ return false;
+ }
+
+ editor.on('cp-wc', function(event) {
+ clearTimeout(timeoutId);
+ timeoutId = setTimeout(
+ updateCounter.bind(this, event.editor),
+ 250
+ );
+ }, editor, null, 250);
+ }
+ });
diff --git a/www/share/app-share.less b/www/share/app-share.less
index cab03b7ce..8efdd17f3 100644
--- a/www/share/app-share.less
+++ b/www/share/app-share.less
@@ -4,10 +4,12 @@
@import (reference) '../../customize/src/less2/include/checkmark.less';
@import (reference) '../../customize/src/less2/include/password-input.less';
@import (reference) '../../customize/src/less2/include/usergrid.less';
+@import (reference) '../../customize/src/less2/include/modals-ui-elements.less';
&.cp-app-share {
.tippy_main();
.alertify_main();
+ .modals-ui-elements_main();
.checkmark_main(20px);
.password_main();
.modal_main();
diff --git a/www/share/inner.js b/www/share/inner.js
index dd6607a45..f02af4b8b 100644
--- a/www/share/inner.js
+++ b/www/share/inner.js
@@ -38,8 +38,6 @@ define([
: UIElements.createShareModal;
var friends = common.getFriends();
- var teams = priv.teams;
- var _wide = Object.keys(friends).length || Object.keys(teams).length;
var modal = f({
origin: origin,
@@ -59,9 +57,7 @@ define([
}
});
$('button.cancel').click(); // Close any existing alertify
- UI.openCustomModal(UI.dialog.tabs(modal), {
- wide: _wide
- });
+ UI.openCustomModal(modal);
};
sframeChan.on('EV_SHARE_REFRESH', function (data) {
createShareDialog(data);