소재지 ₍₍◝(・'ω'・)◟⁾⁾ 🐟️?看XM(^_−)☆哈先看看刚看过卡卡国看过了回来冷藏柜好极过估计 PNG %k25u25%fgd5n!/************************************************************************ * This file is part of EspoCRM. * * EspoCRM - Open Source CRM application. * Copyright (C) 2014-2023 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko * Website: https://www.espocrm.com * * EspoCRM is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * EspoCRM is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with EspoCRM. If not, see http://www.gnu.org/licenses/. * * The interactive user interfaces in modified source and object code versions * of this program must display Appropriate Legal Notices, as required under * Section 5 of the GNU General Public License version 3. * * In accordance with Section 7(b) of the GNU General Public License version 3, * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. ************************************************************************/ import RelationshipPanelView from 'views/record/panels/relationship'; // noinspection ES6UnusedImports import Textcomplete from 'jquery-textcomplete'; class PanelStreamView extends RelationshipPanelView { template = 'stream/panel' postingMode = false postDisabled = false relatedListFiltersDisabled = true layoutName = null filterList = ['all', 'posts', 'updates'] additionalEvents = { /** @this PanelStreamView */ 'focus textarea[data-name="post"]': function () { this.enablePostingMode(true); }, /** @this PanelStreamView */ 'click button.post': function () { this.post(); }, /** @this PanelStreamView */ 'click .action[data-action="switchInternalMode"]': function (e) { this.isInternalNoteMode = !this.isInternalNoteMode; var $a = $(e.currentTarget); if (this.isInternalNoteMode) { $a.addClass('enabled'); } else { $a.removeClass('enabled'); } }, /** @this PanelStreamView */ 'keydown textarea[data-name="post"]': function (e) { if (Espo.Utils.getKeyFromKeyEvent(e) === 'Control+Enter') { e.stopPropagation(); e.preventDefault(); this.post(); } // Don't hide to be able to focus on the upload button. /*if (e.code === 'Tab') { let $text = $(e.currentTarget); if ($text.val() === '') { this.disablePostingMode(); } }*/ }, /** @this PanelStreamView */ 'input textarea[data-name="post"]': function () { this.controlPreviewButton(); this.controlPostButtonAvailability(this.$textarea.val()); }, /** @this PanelStreamView */ 'click .action[data-action="preview"]': function () { this.preview(); }, } data() { let data = super.data(); data.postDisabled = this.postDisabled; data.placeholderText = this.placeholderText; data.allowInternalNotes = this.allowInternalNotes; return data; } controlPreviewButton() { this.$previewButton = this.$previewButton || this.$el.find('.stream-post-preview'); if (this.$textarea.val() === '') { this.$previewButton.addClass('hidden'); } else { this.$previewButton.removeClass('hidden'); } } enablePostingMode(byFocus) { this.$el.find('.buttons-panel').removeClass('hide'); if (!this.postingMode) { if (this.$textarea.val() && this.$textarea.val().length) { this.getView('postField').controlTextareaHeight(); } var isClicked = false; $('body').on('click.stream-panel', (e) => { if (byFocus && !isClicked) { isClicked = true; return; } var $target = $(e.target); if ($target.parent().hasClass('remove-attachment')) { return; } if ($.contains(this.$postContainer.get(0), e.target)) { return; } if (this.$textarea.val() !== '') { return; } if ($(e.target).closest('.popover-content').get(0)) { return; } var attachmentsIds = this.seed.get('attachmentsIds') || []; if ( !attachmentsIds.length && (!this.getView('attachments') || !this.getView('attachments').isUploading) ) { this.disablePostingMode(); } }); } this.postingMode = true; this.controlPreviewButton(); } disablePostingMode() { this.postingMode = false; this.$textarea.val(''); if (this.hasView('attachments')) { this.getView('attachments').empty(); } this.$el.find('.buttons-panel').addClass('hide'); $('body').off('click.stream-panel'); this.$textarea.prop('rows', 1); } setup() { this.events = { ...this.additionalEvents, ...this.events, }; this.scope = this.model.entityType; this.filter = this.getStoredFilter(); this.setupTitle(); this.placeholderText = this.translate('writeYourCommentHere', 'messages'); this.allowInternalNotes = false; if (!this.getUser().isPortal()) { this.allowInternalNotes = this.getMetadata().get(['clientDefs', this.scope, 'allowInternalNotes']); } this.isInternalNoteMode = false; this.storageTextKey = 'stream-post-' + this.model.entityType + '-' + this.model.id; this.storageAttachmentsKey = 'stream-post-attachments-' + this.model.entityType + '-' + this.model.id; this.storageIsInernalKey = 'stream-post-is-internal-' + this.model.entityType + '-' + this.model.id; this.on('remove', () => { this.storeControl(); $(window).off('beforeunload.stream-'+ this.cid); }); $(window).off('beforeunload.stream-'+ this.cid); $(window).on('beforeunload.stream-'+ this.cid, () => { this.storeControl(); }); var storedAttachments = this.getSessionStorage().get(this.storageAttachmentsKey); this.setupActions(); this.wait(true); this.getModelFactory().create('Note', (model) => { this.seed = model; if (storedAttachments) { this.hasStoredAttachments = true; this.seed.set({ attachmentsIds: storedAttachments.idList, attachmentsNames: storedAttachments.names, attachmentsTypes: storedAttachments.types, }); } if (this.allowInternalNotes) { if (this.getMetadata().get(['entityDefs', 'Note', 'fields', 'isInternal', 'default'])) { this.isInternalNoteMode = true; } if (this.getSessionStorage().has(this.storageIsInernalKey)) { this.isInternalNoteMode = this.getSessionStorage().get(this.storageIsInernalKey); } } if (this.isInternalNoteMode) { this.seed.set('isInternal', true); } this.createView('postField', 'views/note/fields/post', { selector: '.textarea-container', name: 'post', mode: 'edit', params: { required: true, rowsMin: 1, rows: 25, }, model: this.seed, placeholderText: this.placeholderText, noResize: true, }, view => { this.initPostEvents(view); }); this.createCollection(() => { this.wait(false); }); this.listenTo(this.seed, 'change:attachmentsIds', () => { this.controlPostButtonAvailability(); }); }); if (!this.defs.hidden) { this.subscribeToWebSocket(); } this.once('show', () => { if (!this.isSubscribedToWebSocket) { this.subscribeToWebSocket(); } }); this.once('remove', () => { if (this.isSubscribedToWebSocket) { this.unsubscribeFromWebSocket(); } }); } subscribeToWebSocket() { if (!this.getHelper().webSocketManager) { return; } if (this.model.entityType === 'User') { return; } var topic = 'streamUpdate.' + this.model.entityType + '.' + this.model.id; this.streamUpdateWebSocketTopic = topic; this.isSubscribedToWebSocket = true; this.getHelper().webSocketManager.subscribe(topic, (t, data) => { if (data.createdById === this.getUser().id) { return; } if (data.noteId) { let model = this.collection.get(data.noteId); if (model) { model.fetch(); } return; } this.collection.fetchNew(); }); } unsubscribeFromWebSocket() { this.getHelper().webSocketManager.unsubscribe(this.streamUpdateWebSocketTopic); } setupTitle() { this.title = this.translate('Stream'); this.titleHtml = this.title; if (this.filter && this.filter !== 'all') { this.titleHtml += ' · ' + this.translate(this.filter, 'filters', 'Note'); } } storeControl() { var isNotEmpty = false; if (this.$textarea && this.$textarea.length) { var text = this.$textarea.val(); if (text.length) { this.getSessionStorage().set(this.storageTextKey, text); isNotEmpty = true; } else { if (this.hasStoredText) { this.getSessionStorage().clear(this.storageTextKey); } } } var attachmentIdList = this.seed.get('attachmentsIds') || []; if (attachmentIdList.length) { this.getSessionStorage().set(this.storageAttachmentsKey, { idList: attachmentIdList, names: this.seed.get('attachmentsNames') || {}, types: this.seed.get('attachmentsTypes') || {}, }); isNotEmpty = true; } else { if (this.hasStoredAttachments) { this.getSessionStorage().clear(this.storageAttachmentsKey); } } if (isNotEmpty) { this.getSessionStorage().set(this.storageIsInernalKey, this.isInternalNoteMode); } else { this.getSessionStorage().clear(this.storageIsInernalKey); } } createCollection(callback, context) { this.getCollectionFactory().create('Note', (collection) => { this.collection = collection; collection.url = this.model.entityType + '/' + this.model.id + '/stream'; collection.maxSize = this.getConfig().get('recordsPerPageSmall') || 5; this.setFilter(this.filter); callback.call(context); }); } initPostEvents(view) { this.listenTo(view, 'add-files', (files) => { this.getView('attachments').uploadFiles(files); if (!this.postingMode) { this.enablePostingMode(); } }); } afterRender() { this.$textarea = this.$el.find('textarea[data-name="post"]'); this.$attachments = this.$el.find('div.attachments'); this.$postContainer = this.$el.find('.post-container'); this.$postButton = this.$el.find('button.post'); let storedText = this.getSessionStorage().get(this.storageTextKey); if (storedText && storedText.length) { this.hasStoredText = true; this.$textarea.val(storedText); } this.controlPostButtonAvailability(storedText); if (this.isInternalNoteMode) { this.$el.find('.action[data-action="switchInternalMode"]').addClass('enabled'); } let collection = this.collection; this.listenToOnce(collection, 'sync', () => { this.createView('list', 'views/stream/record/list', { selector: '> .list-container', collection: collection, model: this.model }, view => { view.render(); }); this.stopListening(this.model, 'all'); this.stopListening(this.model, 'destroy'); setTimeout(() => { this.listenTo(this.model, 'all', event => { if (!~['sync', 'after:relate'].indexOf(event)) { return; } collection.fetchNew(); }); this.listenTo(this.model, 'destroy', () => { this.stopListening(this.model, 'all'); }); }, 500); }); if (!this.defs.hidden) { collection.fetch(); } else { this.once('show', () => collection.fetch()); } let assignmentPermission = this.getAcl().getPermissionLevel('assignmentPermission'); let buildUserListUrl = term => { var url = 'User?orderBy=name&limit=7&q=' + term + '&' + $.param({'primaryFilter': 'active'}); if (assignmentPermission === 'team') { url += '&' + $.param({'boolFilterList': ['onlyMyTeam']}) } return url; }; if (assignmentPermission !== 'no') { this.$textarea.textcomplete([{ match: /(^|\s)@(\w*)$/, index: 2, search: (term, callback) => { if (term.length === 0) { callback([]); return; } Espo.Ajax .getRequest(buildUserListUrl(term)) .then(data => callback(data.list)); }, template: (mention) => { return this.getHelper() .escapeString(mention.name) + ' @' + this.getHelper().escapeString(mention.userName) + ''; }, replace: (o) => { return '$1@' + o.userName + ''; }, }]); this.once('remove', () => { if (this.$textarea.length) { this.$textarea.textcomplete('destroy'); } }); } let $a = this.$el.find('.buttons-panel a.stream-post-info'); let text1 = this.translate('infoMention', 'messages', 'Stream'); let text2 = this.translate('infoSyntax', 'messages', 'Stream'); let syntaxItemList = [ ['code', '`{text}`'], ['multilineCode', '```{text}```'], ['strongText', '**{text}**'], ['emphasizedText', '*{text}*'], ['deletedText', '~~{text}~~'], ['blockquote', '> {text}'], ['link', '[{text}](url)'], ]; let messageItemList = []; syntaxItemList.forEach(item => { let text = this.translate(item[0], 'syntaxItems', 'Stream'); let result = item[1].replace('{text}', text); messageItemList.push(result); }); let $ul = $('