mirror of
https://github.com/Retrospring/retrospring.git
synced 2025-02-13 21:33:20 +01:00
Merge pull request #736 from Retrospring/feature/stimulus-character-count
This commit is contained in:
commit
8eb53d39c8
13 changed files with 87 additions and 37 deletions
|
@ -1,5 +1,8 @@
|
|||
require('../styles/application.scss');
|
||||
|
||||
import { Application } from '@hotwired/stimulus';
|
||||
import { definitionsFromContext } from '@hotwired/stimulus-webpack-helpers';
|
||||
|
||||
import start from 'retrospring/common';
|
||||
import initAnnouncements from 'retrospring/features/announcement';
|
||||
import initAnswerbox from 'retrospring/features/answerbox/index';
|
||||
|
@ -27,3 +30,7 @@ document.addEventListener('DOMContentLoaded', initMemes);
|
|||
document.addEventListener('turbo:load', initAnnouncements);
|
||||
document.addEventListener('turbo:load', initLocales);
|
||||
document.addEventListener('turbo:load', initFront);
|
||||
|
||||
window['Stimulus'] = Application.start();
|
||||
const context = require.context('../retrospring/controllers', true, /\.ts$/);
|
||||
window['Stimulus'].load(definitionsFromContext(context));
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
import { Controller } from '@hotwired/stimulus';
|
||||
|
||||
export default class extends Controller {
|
||||
static targets = ['input', 'counter', 'action'];
|
||||
|
||||
declare readonly inputTarget: HTMLInputElement;
|
||||
declare readonly counterTarget: HTMLElement;
|
||||
declare readonly actionTarget: HTMLInputElement;
|
||||
|
||||
static values = {
|
||||
max: Number
|
||||
};
|
||||
|
||||
declare readonly maxValue: number;
|
||||
|
||||
connect(): void {
|
||||
this.inputTarget.addEventListener('input', this.update.bind(this));
|
||||
}
|
||||
|
||||
update(): void {
|
||||
this.counterTarget.innerHTML = String(`${this.maxValue - this.inputTarget.value.length}`);
|
||||
|
||||
if (this.inputTarget.value.length > this.maxValue) {
|
||||
if (!this.inputTarget.classList.contains('is-invalid') && !this.actionTarget.disabled) {
|
||||
this.inputTarget.classList.add('is-invalid');
|
||||
this.actionTarget.disabled = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (this.inputTarget.classList.contains('is-invalid') && this.actionTarget.disabled) {
|
||||
this.inputTarget.classList.remove('is-invalid');
|
||||
this.actionTarget.disabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
export function commentCharacterCountHandler(event: Event): void {
|
||||
const input = event.target as HTMLInputElement;
|
||||
const id = input.dataset.aId;
|
||||
const counter = document.querySelector(`#ab-comment-charcount-${id}`);
|
||||
const group = document.querySelector(`[name=ab-comment-new-group][data-a-id="${id}"]`);
|
||||
|
||||
if (group.classList.contains('has-error')) {
|
||||
group.classList.remove('has-error');
|
||||
}
|
||||
|
||||
counter.innerHTML = String(160 - input.value.length);
|
||||
if (Number(counter.innerHTML) < 0) {
|
||||
counter.classList.remove('text-muted');
|
||||
counter.classList.add('text-danger');
|
||||
} else {
|
||||
counter.classList.remove('text-danger');
|
||||
counter.classList.add('text-muted');
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
import registerEvents from "retrospring/utilities/registerEvents"
|
||||
import { commentCharacterCountHandler } from "./count";
|
||||
import registerEvents from "retrospring/utilities/registerEvents";
|
||||
import { commentDestroyHandler } from "./destroy";
|
||||
import {commentComposeEnd, commentComposeStart, commentCreateHandler} from "./new";
|
||||
import { commentReportHandler } from "./report";
|
||||
|
@ -14,7 +13,6 @@ export default (): void => {
|
|||
{ type: 'click', target: '[data-action=ab-comment-destroy]', handler: commentDestroyHandler, global: true },
|
||||
{ type: 'compositionstart', target: '[name=ab-comment-new]', handler: commentComposeStart, global: true },
|
||||
{ type: 'compositionend', target: '[name=ab-comment-new]', handler: commentComposeEnd, global: true },
|
||||
{ type: 'keyup', target: '[name=ab-comment-new]', handler: commentCreateHandler, global: true },
|
||||
{ type: 'input', target: '[name=ab-comment-new]', handler: commentCharacterCountHandler, global: true }
|
||||
{ type: 'keyup', target: '[name=ab-comment-new]', handler: commentCreateHandler, global: true }
|
||||
]);
|
||||
}
|
||||
|
|
|
@ -22,6 +22,10 @@ export function questionboxAllHandler(event: Event): void {
|
|||
if (data.success) {
|
||||
document.querySelector<HTMLInputElement>('textarea[name=qb-all-question]').value = '';
|
||||
window['$']('#modal-ask-followers').modal('hide');
|
||||
|
||||
// FIXME: also solve this using a Stimulus controller
|
||||
const characterCount = document.querySelector<HTMLElement>('#modal-ask-followers [data-character-count-max-value]').dataset.characterCountMaxValue;
|
||||
document.querySelector<HTMLElement>('#modal-ask-followers [data-character-count-target="counter"]').innerHTML = characterCount;
|
||||
}
|
||||
|
||||
showNotification(data.message, data.success);
|
||||
|
|
|
@ -19,7 +19,7 @@ export function questionboxUserHandler(event: Event): void {
|
|||
body: {
|
||||
rcpt: document.querySelector<HTMLInputElement>('input[name=qb-to]').value,
|
||||
question: document.querySelector<HTMLInputElement>('textarea[name=qb-question]').value,
|
||||
anonymousQuestion: String(anonymousQuestion)
|
||||
anonymousQuestion: String(anonymousQuestion)
|
||||
},
|
||||
contentType: 'application/json'
|
||||
})
|
||||
|
@ -29,6 +29,10 @@ export function questionboxUserHandler(event: Event): void {
|
|||
if (data.success) {
|
||||
document.querySelector<HTMLInputElement>('textarea[name=qb-question]').value = '';
|
||||
|
||||
// FIXME: also solve this using a Stimulus controller
|
||||
const characterCount = document.querySelector<HTMLElement>('#question-box[data-character-count-max-value]').dataset.characterCountMaxValue;
|
||||
document.querySelector<HTMLElement>('#question-box [data-character-count-target="counter"]').innerHTML = characterCount;
|
||||
|
||||
if (promote) {
|
||||
const questionbox = document.querySelector('#question-box');
|
||||
questionbox.classList.toggle('d-none');
|
||||
|
@ -37,7 +41,7 @@ export function questionboxUserHandler(event: Event): void {
|
|||
promote.classList.toggle('d-none');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
showNotification(data.message, data.success);
|
||||
})
|
||||
.catch(err => {
|
||||
|
@ -62,4 +66,4 @@ export function questionboxUserInputHandler(event: KeyboardEvent): void {
|
|||
if (event.keyCode == 13 && (event.ctrlKey || event.metaKey)) {
|
||||
document.querySelector<HTMLButtonElement>(`button[name=qb-ask]`).click();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,10 @@
|
|||
&__input {
|
||||
z-index: 99;
|
||||
padding-right: 2.5rem;
|
||||
|
||||
&.is-invalid {
|
||||
background-image: none;
|
||||
}
|
||||
}
|
||||
|
||||
&__character-count {
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
%span.caret
|
||||
= render "actions/comment", comment: comment, answer: a
|
||||
- if user_signed_in?
|
||||
.form-group.has-feedback.comment__input-group{ name: "ab-comment-new-group", data: { a_id: a.id } }
|
||||
%input.form-control.comment__input{ type: :text, placeholder: t(".placeholder"), name: "ab-comment-new", data: { a_id: a.id } }
|
||||
%span.text-muted.form-control-feedback.comment__character-count{ id: "ab-comment-charcount-#{a.id}" } 160
|
||||
.form-group.has-feedback.comment__input-group.input-group{ name: "ab-comment-new-group", data: { a_id: a.id, controller: "character-count", "character-count-max-value": 160 } }
|
||||
%input.form-control.comment__input{ type: :text, placeholder: t(".placeholder"), name: "ab-comment-new", data: { a_id: a.id, "character-count-target": "input" } }
|
||||
%span.text-muted.form-control-feedback.comment__character-count{ id: "ab-comment-charcount-#{a.id}", data: { "character-count-target": "counter" } } 160
|
||||
%button.btn.btn-primary.d-none{ type: :button, name: "ab-comment-new-submit", data: { a_id: a.id, "character-count-target": "action" } }= t(".action")
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
%strong= t(".status.blocked")
|
||||
- else
|
||||
- if user_signed_in? || user.privacy_allow_anonymous_questions?
|
||||
#question-box
|
||||
%textarea.form-control{ name: "qb-question", placeholder: t(".placeholder") }
|
||||
.row{ style: "padding-top: 5px; padding-left: 5px; padding-right: 5px;" }
|
||||
#question-box{ data: { controller: "character-count", "character-count-max-value": 512 }}
|
||||
%textarea.form-control{ name: "qb-question", placeholder: t(".placeholder"), data: { "character-count-target": "input" } }
|
||||
.row{ style: "padding-top: 5px;" }
|
||||
.col-6
|
||||
- if user_signed_in?
|
||||
- if user.privacy_allow_anonymous_questions?
|
||||
|
@ -30,10 +30,11 @@
|
|||
%input{ name: "qb-anonymous", type: :hidden, value: false }/
|
||||
.col-6
|
||||
%p.pull-right
|
||||
%span.text-muted.mr-1{ data: { "character-count-target": "counter" } } 512
|
||||
%input{ name: "qb-to", type: "hidden", value: user.id }/
|
||||
%button.btn.btn-primary{ name: "qb-ask",
|
||||
type: :button,
|
||||
data: { loading_text: t(".load"), promote: user_signed_in? ? "false" : "true" } }
|
||||
data: { loading_text: t(".load"), promote: user_signed_in? ? "false" : "true", "character-count-target": "action" } }
|
||||
Ask
|
||||
- unless user_signed_in?
|
||||
- if user.privacy_allow_anonymous_questions?
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
.modal.fade#modal-ask-followers{ aria: { hidden: true, labelledby: "modal-ask-followers-label" }, role: :dialog, tabindex: -1 }
|
||||
.modal-dialog
|
||||
.modal-content
|
||||
.modal-content{ data: { controller: "character-count", "character-count-max-value": 512 }}
|
||||
.modal-header
|
||||
%h5.modal-title#modal-ask-followers-label= t(".title")
|
||||
%button.close{ data: { dismiss: :modal }, type: :button }
|
||||
%span{ aria: { hidden: true } } ×
|
||||
%span.sr-only= t("voc.close")
|
||||
.modal-body
|
||||
%textarea.form-control{ name: "qb-all-question", placeholder: t(".placeholder") }
|
||||
.form-group.has-feedback
|
||||
%textarea.form-control{ name: "qb-all-question", placeholder: t(".placeholder"), data: { "character-count-target": "input" } }
|
||||
%p.text-right.text-muted.form-control-feedback{ data: { "character-count-target": "counter" } } 512
|
||||
.modal-footer
|
||||
%button.btn.btn-default{ type: :button, data: { dismiss: :modal } }= t("voc.cancel")
|
||||
%button.btn.btn-primary{ name: "qb-all-ask", type: :button, data: { loading_text: t(".loading") } }= t(".action")
|
||||
%button.btn.btn-primary{ name: "qb-all-ask", type: :button, data: { "character-count-target": "action", loading_text: t(".loading") } }= t(".action")
|
||||
|
|
|
@ -35,12 +35,12 @@ module.exports = function(api) {
|
|||
exclude: ['transform-typeof-symbol']
|
||||
}
|
||||
],
|
||||
['@babel/preset-typescript', { 'allExtensions': true, 'isTSX': true }]
|
||||
].filter(Boolean),
|
||||
plugins: [
|
||||
'babel-plugin-macros',
|
||||
'@babel/plugin-syntax-dynamic-import',
|
||||
isTestEnv && 'babel-plugin-dynamic-import-node',
|
||||
["@babel/plugin-transform-typescript", { 'allExtensions': true, 'isTSX': true, 'allowDeclareFields': true }],
|
||||
'@babel/plugin-transform-destructuring',
|
||||
[
|
||||
'@babel/plugin-proposal-class-properties',
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@babel/preset-typescript": "^7.18.6",
|
||||
"@hotwired/stimulus": "^3.1.0",
|
||||
"@hotwired/stimulus-webpack-helpers": "^1.0.1",
|
||||
"@fontsource/lexend": "^4.5.13",
|
||||
"@hotwired/turbo-rails": "^7.1.3",
|
||||
"@melloware/coloris": "^0.16.1",
|
||||
|
|
10
yarn.lock
10
yarn.lock
|
@ -1115,6 +1115,16 @@
|
|||
resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.2.tgz#30aa825f11d438671d585bd44e7fd564535fc210"
|
||||
integrity sha512-82cpyJyKRoQoRi+14ibCeGPu0CwypgtBAdBhq1WfvagpCZNKqwXbKwXllYSMG91DhmG4jt9gN8eP6lGOtozuaw==
|
||||
|
||||
"@hotwired/stimulus-webpack-helpers@^1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@hotwired/stimulus-webpack-helpers/-/stimulus-webpack-helpers-1.0.1.tgz#4cd74487adeca576c9865ac2b9fe5cb20cef16dd"
|
||||
integrity sha512-wa/zupVG0eWxRYJjC1IiPBdt3Lruv0RqGN+/DTMmUWUyMAEB27KXmVY6a8YpUVTM7QwVuaLNGW4EqDgrS2upXQ==
|
||||
|
||||
"@hotwired/stimulus@^3.1.0":
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@hotwired/stimulus/-/stimulus-3.1.0.tgz#20215251e5afe6e0a3787285181ba1bfc9097df0"
|
||||
integrity sha512-iDMHUhiEJ1xFeicyHcZQQgBzhtk5mPR0QZO3L6wtqzMsJEk2TKECuCQTGKjm+KJTHVY0dKq1dOOAWvODjpd2Mg==
|
||||
|
||||
"@hotwired/turbo-rails@^7.1.0", "@hotwired/turbo-rails@^7.1.3":
|
||||
version "7.1.3"
|
||||
resolved "https://registry.yarnpkg.com/@hotwired/turbo-rails/-/turbo-rails-7.1.3.tgz#a4e04ecb800a06e7f9aa6e298170fa4580b74216"
|
||||
|
|
Loading…
Reference in a new issue