Skip to content

Commit

Permalink
FEATURE: chat integration and usability improvements (#22)
Browse files Browse the repository at this point in the history
- Added integration with Discourse Chat to allow creating a link within the options of a chat window
- Open plain meeting links in a new browser tab rather than overwriting the current tab
- Added settings for the new chat button integration
- Separated template from javascript for better maintainability
- Added new settings for choose the default options in regards to iframes
  • Loading branch information
jacobtread authored Feb 28, 2024
1 parent c5ca2de commit fc2885d
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 125 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -1 +1 @@
module.exports = require("@discourse/lint-configs/eslint");
module.exports = require("@discourse/lint-configs/eslint");
103 changes: 0 additions & 103 deletions javascripts/discourse/components/modal/insert-jitsi.gjs

This file was deleted.

58 changes: 58 additions & 0 deletions javascripts/discourse/components/modal/insert-jitsi.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<DModal
@title={{theme-i18n "modal.title"}}
class="insert-jitsi"
@closeModal={{@closeModal}}
>
<:body>
<div class="insert-jitsi-form">
<div class="insert-jitsi-input">
<label>
{{theme-i18n "room_label"}}
</label>
<TextField
@value={{this.jitsiRoom}}
@autofocus="autofocus"
@autocomplete="off"
/>
<div class="desc">{{theme-i18n "modal.room_field_description"}}</div>
</div>

{{#unless @model.plainText}}

<div class="insert-jitsi-input">
<label>
{{theme-i18n "button_text_label"}}
</label>
<TextField
@value={{this.buttonText}}
@placeholderKey={{theme-prefix "launch_jitsi"}}
/>
</div>

{{#unless (theme-setting "hide_iframe_buttons")}}
<div class="insert-jitsi-input">
<label class="checkbox-label">
<Input @type="checkbox" @checked={{this.mobileIframe}} />
{{theme-i18n "modal.mobile_iframe"}}
</label>
</div>

<div class="insert-bbb-input">
<label class="checkbox-label">
<Input @type="checkbox" @checked={{this.desktopIframe}} />
{{theme-i18n "modal.desktop_iframe"}}
</label>
</div>
{{/unless}}
{{/unless}}
</div>
</:body>
<:footer>
<DButton
class="btn-primary"
@disabled={{this.insertDisabled}}
@label={{theme-prefix "modal.insert"}}
@action={{this.insert}}
/>
</:footer>
</DModal>
47 changes: 47 additions & 0 deletions javascripts/discourse/components/modal/insert-jitsi.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*eslint no-undef:0 */

import Component from "@glimmer/component";
import { tracked } from "@glimmer/tracking";
import { action } from "@ember/object";

export default class InsertJitsiComponent extends Component {
@tracked mobileIframe = settings.default_mobile_iframe;
@tracked desktopIframe = settings.default_desktop_iframe;
@tracked jitsiRoom = "";
@tracked buttonText = "";

keyDown(e) {
if (e.keyCode === 13) {
e.preventDefault();
e.stopPropagation();
return false;
}
}

randomID() {
return Math.random().toString(36).slice(-8);
}

@action
insert() {
const btnTxt = this.buttonText ? ` label="${this.buttonText}"` : "";
const roomID = this.jitsiRoom || this.randomID();

let text;

if (this.args.model.plainText) {
const domain = settings.meet_jitsi_domain;
text = `https://${domain}/${roomID}`;
} else {
text = `[wrap=discourse-jitsi room="${roomID}"${btnTxt} mobileIframe="${this.mobileIframe}" desktopIframe="${this.desktopIframe}"][/wrap]`;
}

this.args.model.insertMeeting(text);
this.args.closeModal();
}

@action
cancel() {
this.args.closeModal();
}
}
78 changes: 57 additions & 21 deletions javascripts/discourse/initializers/insert-jitsi.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import loadScript from "discourse/lib/load-script";
import { withPluginApi } from "discourse/lib/plugin-api";
import { iconHTML } from "discourse-common/lib/icon-library";
import I18n from "I18n";
import InsertJitsi from "../components/modal/insert-jitsi";
import InsertJitsiComponent from "../components/modal/insert-jitsi";

/* eslint-disable */
// prettier-ignore
Expand All @@ -16,7 +16,7 @@ function launchJitsi($elem, user, site) {
(site.mobileView && data.mobileIframe === false) ||
(!site.mobileView && data.desktopIframe === false)
) {
window.location.href = `https://${domain}/${data.room}`;
window.open(`https://${domain}/${data.room}`, "_blank");
return false;
}

Expand Down Expand Up @@ -66,6 +66,7 @@ function attachJitsi($elem, helper) {
});
}
}

/* eslint-enable */

export default {
Expand All @@ -76,37 +77,72 @@ export default {
const currentUser = api.getCurrentUser();
const modal = api.container.lookup("service:modal");

api.decorateCooked(attachJitsi, { id: "discourse-jitsi" });

// Ensure the current user has access to the feature
if (
settings.only_available_to_staff &&
currentUser &&
!currentUser.staff
) {
return;
}

// Chat plugin integration
if (settings.chat_button && api.registerChatComposerButton) {
const chat = api.container.lookup("service:chat");

api.registerChatComposerButton({
title: themePrefix("composer_title"),
id: "insertChatJitsi",
group: "insertions",
position: settings.chat_button_position,
icon: settings.button_icon,
label: themePrefix("composer_title"),
action: () => {
modal.show(InsertJitsiComponent, {
model: {
insertMeeting: (text) => {
// Get the active channel ensuring one is present
const activeChannel = chat.activeChannel;
if (activeChannel === null) {
return;
}

// Append the meeting link to the draft
activeChannel.draft.message += text;
},
plainText: true,
},
});
},
});
}

if (settings.show_in_options_dropdown) {
if (!settings.only_available_to_staff || currentUser?.staff) {
api.addComposerToolbarPopupMenuOption({
icon: settings.button_icon,
label: themePrefix("composer_title"),
action: (toolbarEvent) => {
modal.show(InsertJitsi, { model: { toolbarEvent } });
},
});
}
api.addComposerToolbarPopupMenuOption({
icon: settings.button_icon,
label: themePrefix("composer_title"),
action: (toolbarEvent) => {
modal.show(InsertJitsiComponent, {
model: { insertMeeting: toolbarEvent.addText },
});
},
});
} else {
if (
settings.only_available_to_staff &&
currentUser &&
!currentUser.staff
) {
return;
}
api.onToolbarCreate((toolbar) => {
toolbar.addButton({
title: themePrefix("composer_title"),
id: "insertJitsi",
group: "insertions",
icon: settings.button_icon,
perform: (toolbarEvent) =>
modal.show(InsertJitsi, { model: { toolbarEvent } }),
modal.show(InsertJitsiComponent, {
model: { insertMeeting: toolbarEvent.addText },
}),
});
});
}

api.decorateCooked(attachJitsi, { id: "discourse-jitsi" });
});
},
};
19 changes: 19 additions & 0 deletions settings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,25 @@ jitsi_script_src:
button_icon:
default: "video"
description: "Enter the name of the FontAwesome 5 icon to display in the Jitsi button. "
chat_button:
default: true
description: "Integrate with Discourse Chat"
hide_iframe_buttons:
default: false
description: "Hide the choice for iframe settings from users, the default settings below will be used"
default_mobile_iframe:
default: true
description: "Enable iframe mode by default for mobile"
default_desktop_iframe:
default: true
description: "Enable iframe mode by default for desktop"
chat_button_position:
description: "Position of the button within the chat window"
default: dropdown
type: enum
choices:
- dropdown
- inline
svg_icons:
default: "video"
type: "list"
Expand Down

0 comments on commit fc2885d

Please sign in to comment.