diff --git a/customize.dist/src/less/toolbar.less b/customize.dist/src/less/toolbar.less index 5e4f74dcf..f67e2ee96 100644 --- a/customize.dist/src/less/toolbar.less +++ b/customize.dist/src/less/toolbar.less @@ -79,6 +79,22 @@ } } + .cryptpad-limit { + color: red; + box-sizing: content-box; + height: 16px; + width: 16px; + display: inline-block; + padding: 3px; + margin: 3px; + margin-right: 6px; + font-size: 20px; + span { + cursor: pointer; + margin: auto; + } + } + .cryptpad-lag { box-sizing: content-box; height: 16px; diff --git a/customize.dist/toolbar.css b/customize.dist/toolbar.css index 1165c6df4..db8ba7776 100644 --- a/customize.dist/toolbar.css +++ b/customize.dist/toolbar.css @@ -150,6 +150,20 @@ .cryptpad-toolbar button.hidden { display: none; } +.cryptpad-toolbar .cryptpad-limit { + color: red; + box-sizing: content-box; + height: 16px; + width: 16px; + display: inline-block; + padding: 3px; + margin: 3px; + margin-right: 6px; + font-size: 20px; +} +.cryptpad-toolbar .cryptpad-limit span { + margin: auto; +} .cryptpad-toolbar .cryptpad-lag { box-sizing: content-box; height: 16px; diff --git a/customize.dist/translations/messages.fr.js b/customize.dist/translations/messages.fr.js index 2b50a088d..a826659ca 100644 --- a/customize.dist/translations/messages.fr.js +++ b/customize.dist/translations/messages.fr.js @@ -55,6 +55,10 @@ define(function () { out.orangeLight = "Votre connexion est lente, ce qui réduit la qualité de l'éditeur"; out.redLight = "Vous êtes déconnectés de la session"; + out.pinLimitReached = "Vous avez atteint votre limite de stockage"; + out.pinLimitReachedAlert = "Vous avez atteint votre limite de stockage. Ce pad ne sera pas enregistré dans votre CrypDrive.
" + + "Pour résoudre ce problème, vous pouvez soit supprimer des pads de votre CryptDrive (y compris la corbeille), soit vous abonner à une offre premium pour augmenter la limite maximale."; + out.importButtonTitle = 'Importer un pad depuis un fichier local'; out.exportButtonTitle = 'Exporter ce pad vers un fichier local'; diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js index 6c3ec7c4d..5e37ffdc6 100644 --- a/customize.dist/translations/messages.js +++ b/customize.dist/translations/messages.js @@ -57,6 +57,10 @@ define(function () { out.orangeLight = "Your slow connection may impact your experience"; out.redLight = "You are disconnected from the session"; + out.pinLimitReached = "You've reached your storage limit"; + out.pinLimitReachedAlert = "You've reached your storage limit. This pad won't be stored in your CryptDrive.
" + + "To fix this problem, you can either remove pads from your CryptDrive (including the trash) or subscribe to a premium offer to increase your limit."; + out.importButtonTitle = 'Import a pad from a local file'; out.exportButtonTitle = 'Export this pad to a local file'; diff --git a/www/code/main.js b/www/code/main.js index 4f12d0926..35bcd90d4 100644 --- a/www/code/main.js +++ b/www/code/main.js @@ -382,7 +382,7 @@ define([ userList = info.userList; var configTb = { - displayed: ['useradmin', 'spinner', 'lag', 'state', 'share', 'userlist', 'newpad'], + displayed: ['useradmin', 'spinner', 'lag', 'state', 'share', 'userlist', 'newpad', 'limit'], userData: userData, readOnly: readOnly, ifrw: ifrw, diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 75ec129b8..24868f817 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -709,6 +709,10 @@ define([ }); }; + var getPinLimit = common.getPinLimit = function (cb) { + cb(void 0, 10); + }; + var createButton = common.createButton = function (type, rightside, data, callback) { var button; var size = "17px"; diff --git a/www/common/toolbar.js b/www/common/toolbar.js index 7ff4f2b51..ed7b88459 100644 --- a/www/common/toolbar.js +++ b/www/common/toolbar.js @@ -16,6 +16,8 @@ define([ /** Id of the div containing the lag info. */ var LAG_ELEM_CLS = Bar.constants.lag = 'cryptpad-lag'; + var LIMIT_ELEM_CLS = Bar.constants.lag = 'cryptpad-limit'; + /** The toolbar class which contains the user list, debug link and lag. */ var TOOLBAR_CLS = Bar.constants.toolbar = 'cryptpad-toolbar'; @@ -488,6 +490,28 @@ define([ $userContainer.append($lag); } + if (config.displayed.indexOf('limit') !== -1 && Config.enablePinning) { + var usage; + var $limitIcon = $('', {'class': 'fa fa-exclamation-triangle'}); + var $limit = $('', { + 'class': LIMIT_ELEM_CLS, + 'title': Messages.pinLimitReached + }).append($limitIcon).hide().appendTo($userContainer); + var andThen = function (e, limit) { + if (usage > limit) { + $limit.show().click(function () { + Cryptpad.alert(Messages.pinLimitReachedAlert, null, true); + }); + } + }; + var todo = function (e, used) { + usage = Cryptpad.bytesToMegabytes(used); + if (e) { console.error("Unable tog et the pinned usage"); return; } + Cryptpad.getPinLimit(andThen); + }; + Cryptpad.getPinnedUsage(todo); + } + if (config.displayed.indexOf('newpad') !== -1) { var pads_options = []; Config.availablePadTypes.forEach(function (p) { diff --git a/www/drive/file.css b/www/drive/file.css index a68b8e7bc..38b314d56 100644 --- a/www/drive/file.css +++ b/www/drive/file.css @@ -89,6 +89,16 @@ li { .selected .fa-plus-square-o { color: #000; } +.selectedTmp { + border: 1px dotted #bbb; + background: #AAA; + color: #ddd; + margin: -1px; +} +.selectedTmp .fa-minus-square-o, +.selectedTmp .fa-plus-square-o { + color: #000; +} span.fa-folder, span.fa-folder-open { color: #FEDE8B; @@ -215,6 +225,12 @@ span.fa-folder-open { flex: 1; display: flex; flex-flow: column; + position: relative; +} +#content .selectBox { + display: none; + background-color: rgba(100, 100, 100, 0.7); + position: absolute; } #content.readonly { background: #e6e6e6; @@ -242,7 +258,7 @@ span.fa-folder-open { #content li:not(.header) *:not(input) { /*pointer-events: none;*/ } -#content li:not(.header):hover:not(.selected) { +#content li:not(.header):hover:not(.selected, .selectedTmp) { background-color: #eee; } #content li:not(.header):hover .name { @@ -304,8 +320,8 @@ span.fa-folder-open { padding-bottom: 5px; max-height: 145px; } -#content div.grid li:not(.selected) { - border: transparent 1px; +#content div.grid li:not(.selected):not(.selectedTmp) { + border: 1px solid transparent; } #content div.grid li .name { width: 100%; @@ -326,6 +342,9 @@ span.fa-folder-open { #content div.grid .listElement { display: none; } +#content .list { + padding-left: 20px; +} #content .list ul { display: table; width: 100%; diff --git a/www/drive/file.less b/www/drive/file.less index 82c6a8657..03bc4750f 100644 --- a/www/drive/file.less +++ b/www/drive/file.less @@ -121,6 +121,16 @@ li { } } +.selectedTmp { + border: 1px dotted #bbb; + background: #AAA; + color: #ddd; + margin: -1px; + .fa-minus-square-o, .fa-plus-square-o { + color: @tree-fg; + } +} + span { &.fa-folder, &.fa-folder-open { color: #FEDE8B; @@ -260,6 +270,12 @@ span { flex: 1; display: flex; flex-flow: column; + position: relative; + .selectBox { + display: none; + background-color: rgba(100, 100, 100, 0.7); + position: absolute; + } &.readonly { background: @content-bg-ro; } @@ -287,7 +303,7 @@ span { /*pointer-events: none;*/ } &:hover { - &:not(.selected) { + &:not(.selected, .selectedTmp) { background-color: @drive-hover; } .name { @@ -357,8 +373,8 @@ span { padding-bottom: 5px; max-height: 145px; - &:not(.selected) { - border: transparent 1px; + &:not(.selected):not(.selectedTmp) { + border: 1px solid transparent; } .name { width: 100%; @@ -384,6 +400,7 @@ span { .list { // Make it act as a table! + padding-left: 20px; ul { display: table; width: 100%; diff --git a/www/drive/main.js b/www/drive/main.js index 038f9402e..057a0a8ee 100644 --- a/www/drive/main.js +++ b/www/drive/main.js @@ -199,6 +199,7 @@ define([ var $trashTreeContextMenu = $iframe.find("#trashTreeContextMenu"); var $trashContextMenu = $iframe.find("#trashContextMenu"); + // TOOLBAR /* add a "change username" button */ @@ -252,12 +253,113 @@ define([ return $el.is('.element-row') ? $el : $el.closest('.element-row'); }; + + // Selection var removeSelected = function () { $iframe.find('.selected').removeClass("selected"); var $container = $driveToolbar.find('#contextButtonsContainer'); if (!$container.length) { return; } $container.html(''); }; + + var sel = {}; + sel.refresh = 200; + sel.$selectBox = $('
', {'class': 'selectBox'}).appendTo($content); + var checkSelected = function () { + if (!sel.down) { return; } + var pos = sel.pos; + var l = $content[0].querySelectorAll('.element:not(.selected):not(.header)'); + var p, el; + for (var i = 0; i < l.length; i++) { + el = l[i]; + p = $(el).position(); + p.top += 10 + $content.scrollTop(); + p.left += 10; + p.bottom = p.top + $(el).outerHeight(); + p.right = p.left + $(el).outerWidth(); + if (p.right < pos.left || p.left > pos.right + || p.top > pos.bottom || p.bottom < pos.top) { + $(el).removeClass('selectedTmp'); + } else { + $(el).addClass('selectedTmp'); + } + } + }; + $content.on('mousedown', function (e) { + console.log('down'); + sel.down = true; + if (!e.ctrlKey) { removeSelected(); } + var rect = e.currentTarget.getBoundingClientRect(); + sel.startX = e.clientX - rect.left, + sel.startY = e.clientY - rect.top + $content.scrollTop(); + sel.$selectBox.show().css({ + left: sel.startX + 'px', + top: sel.startY + 'px', + width: '0px', + height: '0px' + }); + if (sel.move) { console.log('ret'); return; } + sel.move = function (ev) { + var rectMove = ev.currentTarget.getBoundingClientRect(), + offX = ev.clientX - rectMove.left, + offY = ev.clientY - rectMove.top + $content.scrollTop(); + + + var left = sel.startX, + top = sel.startY; + var width = offX - sel.startX; + if (width < 0) { + left = Math.max(0, offX); + var diffX = left-offX; + width = Math.abs(width) - diffX; + } + var height = offY - sel.startY; + if (height < 0) { + top = Math.max(0, offY); + var diffY = top-offY; + height = Math.abs(height) - diffY; + } + sel.$selectBox.css({ + width: width + 'px', + left: left + 'px', + height: height + 'px', + top: top + 'px' + }); + + + sel.pos = { + top: top, + left: left, + bottom: top + height, + right: left + width + }; + var diffT = sel.update ? +new Date() - sel.update : sel.refresh; + if (diffT < sel.refresh) { + if (!sel.to) { + sel.to = window.setTimeout(function () { + sel.update = +new Date(); + checkSelected(); + sel.to = undefined; + }, (sel.refresh - diffT)); + } + console.log('cancelled'); + return; + } + sel.update = +new Date(); + checkSelected(); + }; + $content.mousemove(sel.move); + }); + $content.on('mouseup', function (e) { + console.log(sel.pos); + sel.down = false; + sel.$selectBox.hide(); + $content.off('mousemove', sel.move); + delete sel.move; + $content.find('.selectedTmp').removeClass('selectedTmp').addClass('selected'); + }); + + var removeInput = function (cancel) { if (!cancel && $iframe.find('.element-row > input').length === 1) { var $input = $iframe.find('.element-row > input'); @@ -1501,6 +1603,7 @@ define([ currentPath = path; var s = $content.scrollTop() || 0; $content.html(""); + sel.$selectBox = $('
', {'class': 'selectBox'}).appendTo($content); if (!path || path.length === 0) { path = [ROOT]; }