From 0306438ecf0a3cc49966c256d3720ede8bc9c2a0 Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Wed, 18 Jul 2018 23:44:58 -0300 Subject: [PATCH] [NEW] Room files search form (#11486) * Keep only one PhotoSwipe gallery open * Refactor PhotoSwipe code * Handle preloading in PhotoSwipe * Use common fixCordova helper in uploadFilesList * Fix log helper * Fix the server-side handling of room_files collection * Improvements in uploadedFilesList * Adjust margins * Add file name filter for uploaded files * Add search form for uploaded files * Add missing translation key * Fix indentation in template * Add layout changes * Fix progressive loading in uploaded files list * Add rel="noopener noreferrer" to links in uploaded files list * Rename parameter * Handle image loading for PhotoShipe gallery * Show images in uploaded files list in PhotoSwipe gallery * Add escapeCssUrl helper * Escape thumbnail URL in uploaded files list * Force download on uploaded files list * Add a publication for uploaded files list with search text * Update roomFiles.js * Update roomFilesWithSearchText.js --- client/helpers/escapeCssUrl.js | 3 + client/helpers/log.js | 4 +- packages/rocketchat-i18n/i18n/en.i18n.json | 2 + .../rocketchat-lib/server/models/Uploads.js | 6 +- .../imports/components/contextual-bar.css | 28 +-- .../client/imports/components/file-list.css | 3 - .../client/imports/general/base_old.css | 44 ---- .../client/imports/general/rtl.css | 16 -- packages/rocketchat-theme/client/main.css | 1 - .../client/tabs/uploadedFilesList.html | 54 +++-- .../client/tabs/uploadedFilesList.js | 207 +++++++----------- .../client/components/contextualBar.html | 42 ++-- .../client/views/app/photoswipe.js | 113 ++++++---- server/lib/roomFiles.js | 27 +++ server/publications/roomFiles.js | 28 +-- .../publications/roomFilesWithSearchText.js | 5 + 16 files changed, 257 insertions(+), 326 deletions(-) create mode 100644 client/helpers/escapeCssUrl.js delete mode 100644 packages/rocketchat-theme/client/imports/components/file-list.css create mode 100644 server/lib/roomFiles.js create mode 100644 server/publications/roomFilesWithSearchText.js diff --git a/client/helpers/escapeCssUrl.js b/client/helpers/escapeCssUrl.js new file mode 100644 index 00000000000..da096052273 --- /dev/null +++ b/client/helpers/escapeCssUrl.js @@ -0,0 +1,3 @@ +Template.registerHelper('escapeCssUrl', url => { + return url.replace(/(['"])/g, '\\$1'); +}); diff --git a/client/helpers/log.js b/client/helpers/log.js index 0c6ee1e3c00..cdbd6fa466d 100644 --- a/client/helpers/log.js +++ b/client/helpers/log.js @@ -1,3 +1,3 @@ -Template.registerHelper('log', () => { - console.log.apply(console, arguments); +Template.registerHelper('log', (...args) => { + console.log.apply(console, args); }); diff --git a/packages/rocketchat-i18n/i18n/en.i18n.json b/packages/rocketchat-i18n/i18n/en.i18n.json index bde2f6a1112..89158993af2 100644 --- a/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/packages/rocketchat-i18n/i18n/en.i18n.json @@ -1113,6 +1113,7 @@ "Field_removed": "Field removed", "Field_required": "Field required", "File_exceeds_allowed_size_of_bytes": "File exceeds allowed size of __size__.", + "File_name_Placeholder": "Search files...", "File_not_allowed_direct_messages": "File sharing not allowed in direct messages.", "File_type_is_not_accepted": "File type is not accepted.", "File_uploaded": "File uploaded", @@ -2160,6 +2161,7 @@ "Screen_Share": "Screen Share", "Script_Enabled": "Script Enabled", "Search": "Search", + "Search_by_file_name": "Search by file name", "Search_by_username": "Search by username", "Search_Channels": "Search Channels", "Search_current_provider_not_active": "Current Search Provider is not active", diff --git a/packages/rocketchat-lib/server/models/Uploads.js b/packages/rocketchat-lib/server/models/Uploads.js index 49693c06b39..80f3827e30d 100644 --- a/packages/rocketchat-lib/server/models/Uploads.js +++ b/packages/rocketchat-lib/server/models/Uploads.js @@ -14,7 +14,7 @@ RocketChat.models.Uploads = new class extends RocketChat.models._Base { this.tryEnsureIndex({ 'uploadedAt': 1 }); } - findNotHiddenFilesOfRoom(roomId, limit) { + findNotHiddenFilesOfRoom(roomId, searchText, limit) { const fileQuery = { rid: roomId, complete: true, @@ -24,6 +24,10 @@ RocketChat.models.Uploads = new class extends RocketChat.models._Base { } }; + if (searchText) { + fileQuery.name = { $regex: new RegExp(RegExp.escape(searchText), 'i') }; + } + const fileOptions = { limit, sort: { diff --git a/packages/rocketchat-theme/client/imports/components/contextual-bar.css b/packages/rocketchat-theme/client/imports/components/contextual-bar.css index f130232f4ba..fece268827a 100644 --- a/packages/rocketchat-theme/client/imports/components/contextual-bar.css +++ b/packages/rocketchat-theme/client/imports/components/contextual-bar.css @@ -119,20 +119,21 @@ .attachments { &__item { - display: flex; - overflow: hidden; - - flex: 1; - - transition: background-color 0.3s; - - align-items: center; + transition: background-color 300ms linear; + margin-bottom: 10px; &:hover { cursor: pointer; background-color: #f7f8fa; } + + &-link { + padding: 8px 0; + display: flex; + flex-direction: row; + align-items: center; + } } &__file, @@ -145,7 +146,7 @@ width: 50px; height: 50px; - margin: 8px; + margin: 0 8px; border-radius: 2px; @@ -187,16 +188,17 @@ } &__name { - overflow: hidden; - - margin: 0 8px 8px; + margin: 0 8px; + overflow: hidden; white-space: nowrap; text-overflow: ellipsis; + min-width: 0; color: #2f343d; font-size: 14px; + line-height: 1.5; } &__details { @@ -220,8 +222,6 @@ flex: 1 1 100%; - height: 50px; - color: #9ea2a8; } } diff --git a/packages/rocketchat-theme/client/imports/components/file-list.css b/packages/rocketchat-theme/client/imports/components/file-list.css deleted file mode 100644 index b2a7178a7d7..00000000000 --- a/packages/rocketchat-theme/client/imports/components/file-list.css +++ /dev/null @@ -1,3 +0,0 @@ -.attachments__content .attachments__name { - overflow: unset; -} diff --git a/packages/rocketchat-theme/client/imports/general/base_old.css b/packages/rocketchat-theme/client/imports/general/base_old.css index 4fc00ed1deb..af8a948704f 100644 --- a/packages/rocketchat-theme/client/imports/general/base_old.css +++ b/packages/rocketchat-theme/client/imports/general/base_old.css @@ -3779,50 +3779,6 @@ body:not(.is-cordova) { margin: 1em auto 0; } - - &.uploaded-files-list { - & ul { - & li { - margin-bottom: 10px; - } - } - - & .file-name { - display: block; - - padding: 10px 5px; - - color: #008ce3; - border-width: 0 0 1px; - border-bottom: 1px solid #eaeaea; - - &:hover { - text-decoration: underline; - - color: #006db0; - } - - & p { - overflow: hidden; - - white-space: nowrap; - text-overflow: ellipsis; - } - } - - & i { - float: left; - margin-right: 10px; - - &.file-delete { - float: right; - } - - &.file-download { - float: right; - } - } - } } .rc-old .user-view { diff --git a/packages/rocketchat-theme/client/imports/general/rtl.css b/packages/rocketchat-theme/client/imports/general/rtl.css index 084936878a8..cd233ee7f70 100644 --- a/packages/rocketchat-theme/client/imports/general/rtl.css +++ b/packages/rocketchat-theme/client/imports/general/rtl.css @@ -670,22 +670,6 @@ & > .title .see-all { float: left; } - - &.uploaded-files-list { - & i { - float: right; - margin-right: auto; - margin-left: 10px; - - &.file-delete { - float: left; - } - - &.file-download { - float: left; - } - } - } } & .page-list .list { diff --git a/packages/rocketchat-theme/client/main.css b/packages/rocketchat-theme/client/main.css index 25a3d80b4d9..b70e1ebb299 100644 --- a/packages/rocketchat-theme/client/main.css +++ b/packages/rocketchat-theme/client/main.css @@ -48,7 +48,6 @@ @import 'imports/components/contextual-bar.css'; @import 'imports/components/emojiPicker.css'; @import 'imports/components/table.css'; -@import 'imports/components/file-list.css'; @import 'imports/components/tabs.css'; /* Modal */ diff --git a/packages/rocketchat-ui-flextab/client/tabs/uploadedFilesList.html b/packages/rocketchat-ui-flextab/client/tabs/uploadedFilesList.html index 9ccc831cd7d..1722cf1cd44 100644 --- a/packages/rocketchat-ui-flextab/client/tabs/uploadedFilesList.html +++ b/packages/rocketchat-ui-flextab/client/tabs/uploadedFilesList.html @@ -1,27 +1,43 @@ diff --git a/packages/rocketchat-ui/client/views/app/photoswipe.js b/packages/rocketchat-ui/client/views/app/photoswipe.js index 31f6a91c223..6102f120f96 100644 --- a/packages/rocketchat-ui/client/views/app/photoswipe.js +++ b/packages/rocketchat-ui/client/views/app/photoswipe.js @@ -1,70 +1,89 @@ import PhotoSwipe from 'photoswipe'; import PhotoSwipeUI_Default from 'photoswipe/dist/photoswipe-ui-default'; import 'photoswipe/dist/photoswipe.css'; +import s from 'underscore.string'; -const escapeHTML = (html) => (html || '').replace(/&/g, '&').replace(//g, '>'); Meteor.startup(() => { - const initGallery = (selector, items, options) => { - const gallery = new PhotoSwipe(selector, PhotoSwipeUI_Default, items, options); - gallery.init(); - }; - const getItems = (selector, imageSrc) => { - const results = { - index: 0, - items: [] - }; - for (let i = 0, len = selector.length; i < len; i++) { - results.items.push({ - src: selector[i].src, - w: selector[i].naturalWidth, - h: selector[i].naturalHeight, - title: selector[i].dataset.title, - description: selector[i].dataset.description + let currentGallery = null; + const initGallery = (items, options) => { + if (!currentGallery) { + currentGallery = new PhotoSwipe(document.getElementById('pswp'), PhotoSwipeUI_Default, items, options); + currentGallery.listen('destroy', () => { + currentGallery = null; }); - - if (imageSrc === selector[i].src) { - results.index = i; - } + currentGallery.init(); } - - return results; }; - const galleryOptions = { - index: 0, + const defaultGalleryOptions = { bgOpacity: 0.8, showHideOpacity: true, counterEl: false, shareEl: false }; - $(document).on('click', '.gallery-item', function() { - const images = getItems(document.querySelectorAll('.gallery-item'), $(this)[0].src); + const createEventListenerFor = className => event => { + event.preventDefault(); + event.stopPropagation(); + + if (currentGallery) { + return; + } - galleryOptions.index = images.index; - galleryOptions.addCaptionHTMLFn = function(item, captionEl) { - captionEl.children[0].innerHTML = `${ escapeHTML(item.title) }
${ escapeHTML(item.description) } `; - return true; + const galleryOptions = { + ...defaultGalleryOptions, + index: 0, + addCaptionHTMLFn(item, captionEl) { + captionEl.children[0].innerHTML = + `${ s.escapeHTML(item.title) }
${ s.escapeHTML(item.description) }`; + return true; + } }; - initGallery(document.getElementById('pswp'), images.items, galleryOptions); - }); + const items = Array.from(document.querySelectorAll(className)) + .map((element, i) => { + if (element === event.currentTarget) { + galleryOptions.index = i; + } + + if (element.dataset.src || element.href) { + const img = new Image(); + + img.addEventListener('load', () => { + if (!currentGallery) { + return; + } + + delete currentGallery.items[i].html; + currentGallery.items[i].src = img.src; + currentGallery.items[i].w = img.naturalWidth; + currentGallery.items[i].h = img.naturalHeight; + currentGallery.invalidateCurrItems(); + currentGallery.updateSize(true); + }); - $(document).on('click', '.room-files-image', (e) => { - e.preventDefault(); - e.stopPropagation(); + img.src = element.dataset.src || element.href; - const img = new Image(); - img.src = e.currentTarget.href; - img.addEventListener('load', function() { - const item = [{ - src: this.src, - w: this.naturalWidth, - h: this.naturalHeight - }]; + return { + html: '', + title: element.dataset.title || element.title, + description: element.dataset.description + }; + } + + return { + src: element.src, + w: element.naturalWidth, + h: element.naturalHeight, + title: element.dataset.title || element.title, + description: element.dataset.description + }; + }); + + initGallery(items, galleryOptions); + }; - initGallery(document.getElementById('pswp'), item, galleryOptions); - }); - }); + $(document).on('click', '.gallery-item', createEventListenerFor('.gallery-item')); + $(document).on('click', '.room-files-image', createEventListenerFor('.room-files-image')); }); diff --git a/server/lib/roomFiles.js b/server/lib/roomFiles.js new file mode 100644 index 00000000000..88c679dc00c --- /dev/null +++ b/server/lib/roomFiles.js @@ -0,0 +1,27 @@ +export const roomFiles = (pub, { rid, searchText, limit = 50 }) => { + if (!pub.userId) { + return pub.ready(); + } + + const cursorFileListHandle = RocketChat.models.Uploads.findNotHiddenFilesOfRoom(rid, searchText, limit).observeChanges({ + added(_id, record) { + const { username, name } = record.userId ? RocketChat.models.Users.findOneById(record.userId) : {}; + return pub.added('room_files', _id, { ...record, user: { username, name } }); + }, + changed(_id, recordChanges) { + if (!recordChanges.hasOwnProperty('user') && recordChanges.userId) { + recordChanges.user = RocketChat.models.Users.findOneById(recordChanges.userId); + } + return pub.changed('room_files', _id, recordChanges); + }, + removed(_id) { + return pub.removed('room_files', _id); + } + }); + + pub.ready(); + + return pub.onStop(function() { + return cursorFileListHandle.stop(); + }); +}; diff --git a/server/publications/roomFiles.js b/server/publications/roomFiles.js index dc500d16ac1..f31d9c828c7 100644 --- a/server/publications/roomFiles.js +++ b/server/publications/roomFiles.js @@ -1,27 +1,5 @@ -Meteor.publish('roomFiles', function(rid, limit = 50) { - if (!this.userId) { - return this.ready(); - } - - const pub = this; - - const cursorFileListHandle = RocketChat.models.Uploads.findNotHiddenFilesOfRoom(rid, limit).observeChanges({ - added(_id, record) { - const {username, name} = record.userId ? RocketChat.models.Users.findOneById(record.userId) : {}; - return pub.added('room_files', _id, {...record, user:{username, name}}); - }, - changed(_id, record) { - const {username, name} = record.userId ? RocketChat.models.Users.findOneById(record.userId) : {}; - return pub.changed('room_files', _id, {...record, user:{username, name}}); - }, - removed(_id, record) { - return pub.removed('room_files', _id, record); - } - }); +import { roomFiles } from '../lib/roomFiles'; - this.ready(); - - return this.onStop(function() { - return cursorFileListHandle.stop(); - }); +Meteor.publish('roomFiles', function(rid, limit = 50) { + return roomFiles(this, { rid, limit }); }); diff --git a/server/publications/roomFilesWithSearchText.js b/server/publications/roomFilesWithSearchText.js new file mode 100644 index 00000000000..9d7dacdd6c7 --- /dev/null +++ b/server/publications/roomFilesWithSearchText.js @@ -0,0 +1,5 @@ +import { roomFiles } from '../lib/roomFiles'; + +Meteor.publish('roomFilesWithSearchText', function(rid, searchText, limit = 50) { + return roomFiles(this, { rid, searchText, limit }); +});