123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371 |
- import { ReactiveCache } from '/imports/reactiveCache';
- import DOMPurify from 'dompurify';
- import { TAPi18n } from '/imports/i18n';
- const activitiesPerPage = 500;
- BlazeComponent.extendComponent({
- onCreated() {
- // XXX Should we use ReactiveNumber?
- this.page = new ReactiveVar(1);
- this.loadNextPageLocked = false;
- // TODO is sidebar always available? E.g. on small screens/mobile devices
- const sidebar = Sidebar;
- sidebar && sidebar.callFirstWith(null, 'resetNextPeak');
- this.autorun(() => {
- let mode = this.data().mode;
- const capitalizedMode = Utils.capitalize(mode);
- let searchId;
- if (mode === 'linkedcard' || mode === 'linkedboard') {
- searchId = Utils.getCurrentCard().linkedId;
- mode = mode.replace('linked', '');
- } else if (mode === 'card') {
- searchId = Utils.getCurrentCardId();
- } else {
- searchId = Session.get(`current${capitalizedMode}`);
- }
- const limit = this.page.get() * activitiesPerPage;
- const user = ReactiveCache.getCurrentUser();
- const hideSystem = user ? user.hasHiddenSystemMessages() : false;
- if (searchId === null) return;
- this.subscribe('activities', mode, searchId, limit, hideSystem, () => {
- this.loadNextPageLocked = false;
- // TODO the guard can be removed as soon as the TODO above is resolved
- if (!sidebar) return;
- // If the sibear peak hasn't increased, that mean that there are no more
- // activities, and we can stop calling new subscriptions.
- // XXX This is hacky! We need to know excatly and reactively how many
- // activities there are, we probably want to denormalize this number
- // dirrectly into card and board documents.
- const nextPeakBefore = sidebar.callFirstWith(null, 'getNextPeak');
- sidebar.calculateNextPeak();
- const nextPeakAfter = sidebar.callFirstWith(null, 'getNextPeak');
- if (nextPeakBefore === nextPeakAfter) {
- sidebar.callFirstWith(null, 'resetNextPeak');
- }
- });
- });
- },
- loadNextPage() {
- if (this.loadNextPageLocked === false) {
- this.page.set(this.page.get() + 1);
- this.loadNextPageLocked = true;
- }
- },
- }).register('activities');
- Template.activities.helpers({
- activities() {
- const ret = this.card.activities();
- return ret;
- },
- });
- BlazeComponent.extendComponent({
- checkItem() {
- const checkItemId = this.currentData().activity.checklistItemId;
- const checkItem = ChecklistItems.findOne({ _id: checkItemId });
- return checkItem && checkItem.title;
- },
- boardLabelLink() {
- const data = this.currentData();
- const currentBoardId = Session.get('currentBoard');
- if (data.mode !== 'board') {
- // data.mode: card, linkedcard, linkedboard
- return createBoardLink(data.activity.board(), data.activity.listName ? data.activity.listName : null);
- }
- else if (currentBoardId != data.activity.boardId) {
- // data.mode: board
- // current activitie is linked
- return createBoardLink(data.activity.board(), data.activity.listName ? data.activity.listName : null);
- }
- return TAPi18n.__('this-board');
- },
- cardLabelLink() {
- const data = this.currentData();
- const currentBoardId = Session.get('currentBoard');
- if (data.mode == 'card') {
- // data.mode: card
- return TAPi18n.__('this-card');
- }
- else if (data.mode !== 'board') {
- // data.mode: linkedcard, linkedboard
- return createCardLink(data.activity.card(), null);
- }
- else if (currentBoardId != data.activity.boardId) {
- // data.mode: board
- // current activitie is linked
- return createCardLink(data.activity.card(), data.activity.board().title);
- }
- return createCardLink(this.currentData().activity.card(), null);
- },
- cardLink() {
- const data = this.currentData();
- const currentBoardId = Session.get('currentBoard');
- if (data.mode !== 'board') {
- // data.mode: card, linkedcard, linkedboard
- return createCardLink(data.activity.card(), null);
- }
- else if (currentBoardId != data.activity.boardId) {
- // data.mode: board
- // current activitie is linked
- return createCardLink(data.activity.card(), data.activity.board().title);
- }
- return createCardLink(this.currentData().activity.card(), null);
- },
- receivedDate() {
- const receivedDate = this.currentData().activity.card();
- if (!receivedDate) return null;
- return receivedDate.receivedAt;
- },
- startDate() {
- const startDate = this.currentData().activity.card();
- if (!startDate) return null;
- return startDate.startAt;
- },
- dueDate() {
- const dueDate = this.currentData().activity.card();
- if (!dueDate) return null;
- return dueDate.dueAt;
- },
- endDate() {
- const endDate = this.currentData().activity.card();
- if (!endDate) return null;
- return endDate.endAt;
- },
- lastLabel() {
- const lastLabelId = this.currentData().activity.labelId;
- if (!lastLabelId) return null;
- const lastLabel = ReactiveCache.getBoard(
- this.currentData().activity.boardId,
- ).getLabelById(lastLabelId);
- if (lastLabel && (lastLabel.name === undefined || lastLabel.name === '')) {
- return lastLabel.color;
- } else if (lastLabel.name !== undefined && lastLabel.name !== '') {
- return lastLabel.name;
- } else {
- return null;
- }
- },
- lastCustomField() {
- const lastCustomField = CustomFields.findOne(
- this.currentData().activity.customFieldId,
- );
- if (!lastCustomField) return null;
- return lastCustomField.name;
- },
- lastCustomFieldValue() {
- const lastCustomField = CustomFields.findOne(
- this.currentData().activity.customFieldId,
- );
- if (!lastCustomField) return null;
- const value = this.currentData().activity.value;
- if (
- lastCustomField.settings.dropdownItems &&
- lastCustomField.settings.dropdownItems.length > 0
- ) {
- const dropDownValue = _.find(
- lastCustomField.settings.dropdownItems,
- item => {
- return item._id === value;
- },
- );
- if (dropDownValue) return dropDownValue.name;
- }
- return value;
- },
- listLabel() {
- const activity = this.currentData().activity;
- const list = activity.list();
- return (list && list.title) || activity.title;
- },
- sourceLink() {
- const source = this.currentData().activity.source;
- if (source) {
- if (source.url) {
- return Blaze.toHTML(
- HTML.A(
- {
- href: source.url,
- },
- DOMPurify.sanitize(source.system, {
- ALLOW_UNKNOWN_PROTOCOLS: true,
- }),
- ),
- );
- } else {
- return DOMPurify.sanitize(source.system, {
- ALLOW_UNKNOWN_PROTOCOLS: true,
- });
- }
- }
- return null;
- },
- memberLink() {
- return Blaze.toHTMLWithData(Template.memberName, {
- user: this.currentData().activity.member(),
- });
- },
- attachmentLink() {
- const attachment = this.currentData().activity.attachment();
- // trying to display url before file is stored generates js errors
- return (
- (attachment &&
- attachment.path &&
- Blaze.toHTML(
- HTML.A(
- {
- href: `${attachment.link()}?download=true`,
- target: '_blank',
- },
- DOMPurify.sanitize(attachment.name),
- ),
- )) ||
- DOMPurify.sanitize(this.currentData().activity.attachmentName)
- );
- },
- customField() {
- const customField = this.currentData().activity.customField();
- if (!customField) return null;
- return customField.name;
- },
- events() {
- return [
- {
- // XXX We should use Popup.afterConfirmation here
- 'click .js-delete-comment': Popup.afterConfirm('deleteComment', () => {
- const commentId = this.data().activity.commentId;
- CardComments.remove(commentId);
- Popup.back();
- }),
- 'submit .js-edit-comment'(evt) {
- evt.preventDefault();
- const commentText = this.currentComponent()
- .getValue()
- .trim();
- const commentId = Template.parentData().activity.commentId;
- if (commentText) {
- CardComments.update(commentId, {
- $set: {
- text: commentText,
- },
- });
- }
- },
- },
- ];
- },
- }).register('activity');
- Template.activity.helpers({
- sanitize(value) {
- return DOMPurify.sanitize(value, { ALLOW_UNKNOWN_PROTOCOLS: true });
- },
- });
- Template.commentReactions.events({
- 'click .reaction'(event) {
- if (ReactiveCache.getCurrentUser().isBoardMember()) {
- const codepoint = event.currentTarget.dataset['codepoint'];
- const commentId = Template.instance().data.commentId;
- const cardComment = CardComments.findOne({_id: commentId});
- cardComment.toggleReaction(codepoint);
- }
- },
- 'click .open-comment-reaction-popup': Popup.open('addReaction'),
- })
- Template.addReactionPopup.events({
- 'click .add-comment-reaction'(event) {
- if (ReactiveCache.getCurrentUser().isBoardMember()) {
- const codepoint = event.currentTarget.dataset['codepoint'];
- const commentId = Template.instance().data.commentId;
- const cardComment = CardComments.findOne({_id: commentId});
- cardComment.toggleReaction(codepoint);
- }
- Popup.back();
- },
- })
- Template.addReactionPopup.helpers({
- codepoints() {
- // Starting set of unicode codepoints as comment reactions
- return [
- '👍',
- '👎',
- '👀',
- '✅',
- '❌',
- '🙏',
- '👏',
- '🎉',
- '🚀',
- '😊',
- '🤔',
- '😔'];
- }
- })
- Template.commentReactions.helpers({
- isSelected(userIds) {
- return Meteor.userId() && userIds.includes(Meteor.userId());
- },
- userNames(userIds) {
- return Users.find({_id: {$in: userIds}})
- .map(user => user.profile.fullname)
- .join(', ');
- }
- })
- function createCardLink(card, board) {
- if (!card) return '';
- let text = card.title;
- if (board) text = `${board} > ` + text;
- return (
- card &&
- Blaze.toHTML(
- HTML.A(
- {
- href: card.originRelativeUrl(),
- class: 'action-card',
- },
- DOMPurify.sanitize(text, { ALLOW_UNKNOWN_PROTOCOLS: true }),
- ),
- )
- );
- }
- function createBoardLink(board, list) {
- let text = board.title;
- if (list) text += `: ${list}`;
- return (
- board &&
- Blaze.toHTML(
- HTML.A(
- {
- href: board.originRelativeUrl(),
- class: 'action-board',
- },
- DOMPurify.sanitize(text, { ALLOW_UNKNOWN_PROTOCOLS: true }),
- ),
- )
- );
- }
|