diff --git a/assets/javascripts/discourse/components/add-event-button.js b/assets/javascripts/discourse/components/add-event-button.js new file mode 100644 index 000000000..d7c011f78 --- /dev/null +++ b/assets/javascripts/discourse/components/add-event-button.js @@ -0,0 +1,62 @@ +import Component from '@ember/component'; +import { action } from '@ember/object'; +import EmberObject from "@ember/object"; +import PostEventBuilder from "./modal/post-event-builder"; +import { + addReminder, + onChangeDates, + removeReminder, + updateCustomField, + updateEventRawInvitees, + updateEventStatus, + updateTimezone, +} from "../widgets/discourse-post-event"; + +export default class AddEventButton extends Component { + @action + showAddEventModal() { + const store = this.api.container.lookup('service:store'); + const modal = this.api.container.lookup('service:modal'); + + const eventModel = store.createRecord("discourse-post-event-event"); + + eventModel.setProperties({ + status: "public", + custom_fields: EmberObject.create({}), + starts_at: moment(), + timezone: moment.tz.guess(), + }); + + console.log("Access calendar_categories_id:", this.siteSettings.calendar_categories_id); + + modal.show(PostEventBuilder, { + model: { + event: eventModel, + api: this.api, + updateCustomField: (field, value) => + updateCustomField(eventModel, field, value), + updateEventStatus: (status) => updateEventStatus(eventModel, status), + updateEventRawInvitees: (rawInvitees) => + updateEventRawInvitees(eventModel, rawInvitees), + removeReminder: (reminder) => removeReminder(eventModel, reminder), + addReminder: () => addReminder(eventModel), + onChangeDates: (changes) => onChangeDates(eventModel, changes), + updateTimezone: (newTz, startsAt, endsAt) => + updateTimezone(eventModel, newTz, startsAt, endsAt), + }, + }); + } + + didInsertElement() { + super.didInsertElement(...arguments); + + const $container = $(".composer-fields .title-and-category"); + $container.addClass("show-event-controls"); + + $(".composer-controls-event").appendTo($container); + + this.composerResized(); + } + + composerResized() {} +} diff --git a/assets/javascripts/discourse/components/modal/post-event-builder.js b/assets/javascripts/discourse/components/modal/post-event-builder.js index db4591089..64825dc49 100644 --- a/assets/javascripts/discourse/components/modal/post-event-builder.js +++ b/assets/javascripts/discourse/components/modal/post-event-builder.js @@ -152,12 +152,58 @@ export default class PostEventBuilder extends Component { markdownParams.push(`${key}="${value}"`); }); + // Check if we are from toolbar or composer + if (this.args.model.toolbarEvent) { this.args.model.toolbarEvent.addText( `[event ${markdownParams.join(" ")}]\n[/event]` ); + } else { + this.insertTextIntoComposer( + `[event ${markdownParams.join(" ")}]\n[/event]` + ); + } this.args.closeModal(); } + insertTextIntoComposer(text) { + const composerController = this.args.model.api.container.lookup('controller:composer'); + if (composerController && composerController.model) { + const composerModel = composerController.get('model'); + const currentText = composerModel.get('reply') || ''; + composerModel.set('reply', `${text}\n${currentText}`); + const textarea = document.querySelector('.d-editor-input'); + textarea.focus(); + } else { + console.error('Composer controller or model not found'); + } + } + + // to insert text at the current cursor position + // insertTextIntoComposer(text) { + // const composerController = this.args.model.api.container.lookup('controller:composer'); + // if (composerController && composerController.model) { + // const composerModel = composerController.get('model'); + // const textarea = document.querySelector('.d-editor-input'); + + // if (textarea) { + // const startPos = textarea.selectionStart; + // const endPos = textarea.selectionEnd; + // const currentText = composerModel.get('reply') || ''; + + // const newText = `${currentText.substring(0, startPos)}${text}${currentText.substring(endPos)}`; + // composerModel.set('reply', newText); + + // // Réfocaliser la zone de texte et repositionner le curseur + // textarea.focus(); + // textarea.setSelectionRange(startPos + text.length, startPos + text.length); + // } else { + // console.error('Textarea not found'); + // } + // } else { + // console.error('Composer controller or model not found'); + // } + // } + @action async updateEvent() { try { diff --git a/assets/javascripts/discourse/connectors/composer-fields/composer-controls-event.hbs b/assets/javascripts/discourse/connectors/composer-fields/composer-controls-event.hbs new file mode 100644 index 000000000..27c066b8f --- /dev/null +++ b/assets/javascripts/discourse/connectors/composer-fields/composer-controls-event.hbs @@ -0,0 +1,8 @@ +{{#if (or + (eq siteSettings.calendar_categories_button.length 0) + (includes siteSettings.calendar_categories_button (or model.category.parent_category_id model.category.id)) +)}} + {{#if (or (not model.post) (eq model.post.post_number 1))}} + {{add-event-button class="add-event-button" model=model}} + {{/if}} +{{/if}} diff --git a/assets/javascripts/discourse/initializers/add-event-button-initializer.js b/assets/javascripts/discourse/initializers/add-event-button-initializer.js new file mode 100644 index 000000000..745702cf1 --- /dev/null +++ b/assets/javascripts/discourse/initializers/add-event-button-initializer.js @@ -0,0 +1,20 @@ +import { withPluginApi } from 'discourse/lib/plugin-api'; + +export default { + name: 'add-event-button-initializer', + initialize(container) { + const siteSettings = container.lookup("service:site-settings"); + if (siteSettings.discourse_post_event_enabled) { + withPluginApi('0.8.7', api => { + api.modifyClass('component:add-event-button', { + pluginId: 'discourse-calendar', + + init() { + this._super(...arguments); + this.api = api; + } + }); + }); + } +} +}; diff --git a/assets/javascripts/discourse/templates/components/add-event-button.hbs b/assets/javascripts/discourse/templates/components/add-event-button.hbs new file mode 100644 index 000000000..0a361989a --- /dev/null +++ b/assets/javascripts/discourse/templates/components/add-event-button.hbs @@ -0,0 +1,8 @@ +
+ {{d-button + action=(action "showAddEventModal") + class="btn btn-default" + icon="calendar-day" + label="discourse_calendar.discourse_post_event.builder_modal.attach" + }} +
diff --git a/assets/stylesheets/common/discourse-calendar-button.scss b/assets/stylesheets/common/discourse-calendar-button.scss new file mode 100644 index 000000000..1370561aa --- /dev/null +++ b/assets/stylesheets/common/discourse-calendar-button.scss @@ -0,0 +1,38 @@ +#reply-control .composer-fields { + .title-and-category { + display: flex; + align-items: center; + + .category-input { + flex: 1 0 30%; + } + + .add-event-button { + // margin-left: 5px; + height: 42px; + + .btn-default { + // padding: 0 12px; + border: 1px solid var(--primary-medium); + border-radius: 2px; + &:not(.btn-primary) { + background: var(--secondary); + } + + &:hover { + background-color: var(--primary-medium); + color: var(--secondary); + } + + &:focus { + outline: none; + box-shadow: 0 0 0 3px var(--tertiary); + } + } + + .fa { + margin: 10; + } + } + } +} diff --git a/assets/stylesheets/mobile/discourse-calendar.scss b/assets/stylesheets/mobile/discourse-calendar.scss index e43c0429d..d16fc2b52 100644 --- a/assets/stylesheets/mobile/discourse-calendar.scss +++ b/assets/stylesheets/mobile/discourse-calendar.scss @@ -41,3 +41,23 @@ } } } + +// #reply-control .composer-fields { +// flex-direction: column; + +// .title-and-category { +// .category-input { +// flex: none; +// width: 100%; +// margin-bottom: 10px; +// } + +// .add-event-button { +// width: 100%; +// margin-bottom: 2px; +// height: auto; +// padding: 2px; +// text-align: center; +// } +// } +// } diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 9f269c6af..8cd2cc2ad 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -45,6 +45,7 @@ en: all_day_event_start_time: "Events that do not have a start time specified will start at this time. Format is HH:mm. For 6:00 am, enter 06:00" all_day_event_end_time: "Events that do not have a end time specified will end at this time. Format is HH:mm. For 6:00 pm, enter 18:00" all_day_event_time_error: "Invalid time. Format needs to be HH:mm (ex: 08:00)." + calendar_categories_button: "Category ID where the calendar button will be displayed. Everywhere if not set." calendar_categories: "Display a calendar at the top of a category. Mandatory settings are categoryId and postId. eg: categoryId=6;postId=453\n Other valid settings: tzPicker, weekends and defaultView." calendar_categories_outlet: "Allows to change which outlet should show the category calendar." working_days: "Set working days. You can display the availability of a group using the `timezones` tag in a post, eg: `[timezones group=admins][timezones]`" diff --git a/config/locales/server.es.yml b/config/locales/server.es.yml index 4f24dbff8..11dbf6680 100644 --- a/config/locales/server.es.yml +++ b/config/locales/server.es.yml @@ -49,6 +49,7 @@ es: all_day_event_start_time: "Los eventos que no tienen una hora de inicio especificada comenzarán a esta hora. El formato es HH:mm. Para las 6:00 am, introduce 06:00" all_day_event_end_time: "Los eventos que no tienen una hora de finalización especificada terminarán a esta hora. El formato es HH:mm. Para las 6:00 pm, introduce 18:00" all_day_event_time_error: "Hora no válida. El formato debe ser HH:mm (por ejemplo: 08:00)." + calendar_categories_button: "ID de la categoría donde se mostrará el botón del calendario. En todas partes si no se establece." calendar_categories: "Muestra un calendario en la parte superior de una categoría. Las configuraciones obligatorias son categoryId y postId. por ejemplo: categoryId = 6; postId = 453\n Otras configuraciones válidas: tzPicker, fines de semana y defaultView." calendar_categories_outlet: "Permite cambiar qué salida debe mostrar el calendario de categorías." working_days: "Establecer días laborables. Puede mostrar la disponibilidad de un grupo usando la etiqueta `timezones` en una publicación, por ejemplo: `[timezones group = admins][timezones]`" diff --git a/config/locales/server.fr.yml b/config/locales/server.fr.yml index 14b45a426..b54d4eb53 100644 --- a/config/locales/server.fr.yml +++ b/config/locales/server.fr.yml @@ -49,6 +49,7 @@ fr: all_day_event_start_time: "Les événements qui n'ont pas d'heure de début spécifiée commenceront à cette heure. Le format est HH:mm. Pour indiquer 6:00 heures, saisissez 06:00" all_day_event_end_time: "Les événements qui n'ont pas d'heure de fin spécifiée se termineront à cette heure. Le format est HH:mm. Pour indiquer 18:00 heures, saisissez 18:00" all_day_event_time_error: "Heure invalide. Le format doit être HH:mm (p. ex. : 08:00)." + calendar_categories_button: "ID de la catégorie où le bouton du calendrier sera affiché. Partout si non défini." calendar_categories: "Affiche un calendrier en haut d'une catégorie. Les paramètres obligatoires sont categoryId et postId. P. ex. : categoryId=6;postId=453\n Autres paramètres valides : tzPicker, weekends et defaultView." calendar_categories_outlet: "Permet de changer quelle sortie doit afficher le calendrier de la catégorie." working_days: "Définissez les jours ouvrés. Vous pouvez afficher la disponibilité d'un groupe en utilisant l'étiquette « timezones » dans un message. P. ex. : « [timezones group=admins][timezones] »" diff --git a/config/settings.yml b/config/settings.yml index 4fd08a67b..6ed384f4b 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -19,6 +19,11 @@ discourse_calendar: default: "" client: true validator: "CalendarSettingsValidator" + calendar_categories_button: + client: true + default: "" + type: list + list_type: compact calendar_categories: type: list list_type: simple diff --git a/plugin.rb b/plugin.rb index 080d98c01..158ad2abc 100644 --- a/plugin.rb +++ b/plugin.rb @@ -16,6 +16,7 @@ register_asset "stylesheets/vendor/fullcalendar.min.css" register_asset "stylesheets/common/discourse-calendar.scss" +register_asset "stylesheets/common/discourse-calendar-button.scss" register_asset "stylesheets/common/discourse-calendar-holidays.scss" register_asset "stylesheets/common/upcoming-events-calendar.scss" register_asset "stylesheets/common/discourse-post-event.scss"