Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
node_modules
/gems
/auto_generated
.eslintcache
2 changes: 1 addition & 1 deletion .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1 +1 @@
yarn lint-staged
pnpm lint-staged
3 changes: 2 additions & 1 deletion .npmrc
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
engine-strict=true
engine-strict = true
auto-install-peers = false
1 change: 0 additions & 1 deletion .template-lintrc.cjs

This file was deleted.

125 changes: 72 additions & 53 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,80 +1,99 @@
GEM
remote: https://rubygems.org/
specs:
activesupport (7.1.3.3)
activesupport (8.1.3)
base64
bigdecimal
concurrent-ruby (~> 1.0, >= 1.0.2)
concurrent-ruby (~> 1.0, >= 1.3.1)
connection_pool (>= 2.2.5)
drb
i18n (>= 1.6, < 2)
json
logger (>= 1.4.2)
minitest (>= 5.1)
mutex_m
tzinfo (~> 2.0)
ast (2.4.2)
base64 (0.2.0)
bigdecimal (3.1.8)
concurrent-ruby (1.2.3)
connection_pool (2.4.1)
drb (2.2.1)
i18n (1.14.5)
securerandom (>= 0.3)
tzinfo (~> 2.0, >= 2.0.5)
uri (>= 0.13.1)
ast (2.4.3)
base64 (0.3.0)
bigdecimal (4.1.2)
concurrent-ruby (1.3.7)
connection_pool (3.0.2)
drb (2.2.3)
i18n (1.15.2)
concurrent-ruby (~> 1.0)
json (2.7.2)
language_server-protocol (3.17.0.3)
minitest (5.23.1)
mutex_m (0.2.0)
parallel (1.24.0)
parser (3.3.1.0)
json (2.20.0)
language_server-protocol (3.17.0.6)
lint_roller (1.1.0)
logger (1.7.0)
minitest (6.0.6)
drb (~> 2.0)
prism (~> 1.5)
parallel (2.1.0)
parser (3.3.11.1)
ast (~> 2.4.1)
racc
prettier_print (1.2.1)
racc (1.8.0)
rack (3.0.12)
prism (1.9.0)
racc (1.8.1)
rack (3.2.6)
rainbow (3.1.1)
regexp_parser (2.9.2)
rexml (3.3.9)
rubocop (1.64.0)
regexp_parser (2.12.0)
rubocop (1.88.2)
json (~> 2.3)
language_server-protocol (>= 3.17.0)
parallel (~> 1.10)
language_server-protocol (~> 3.17.0.2)
lint_roller (~> 1.1.0)
parallel (>= 1.10)
parser (>= 3.3.0.2)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.8, < 3.0)
rexml (>= 3.2.5, < 4.0)
rubocop-ast (>= 1.31.1, < 2.0)
regexp_parser (>= 2.9.3, < 3.0)
rubocop-ast (>= 1.49.0, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 3.0)
rubocop-ast (1.31.3)
parser (>= 3.3.1.0)
rubocop-capybara (2.20.0)
rubocop (~> 1.41)
rubocop-discourse (3.8.0)
unicode-display_width (>= 2.4.0, < 4.0)
rubocop-ast (1.50.0)
parser (>= 3.3.7.2)
prism (~> 1.7)
rubocop-capybara (3.0.0)
lint_roller (~> 1.1)
rubocop (~> 1.81)
rubocop-discourse (3.18.0)
activesupport (>= 6.1)
rubocop (>= 1.59.0)
rubocop-capybara (>= 2.0.0)
rubocop-factory_bot (>= 2.0.0)
rubocop-rails (>= 2.25.0)
rubocop-rspec (>= 2.25.0)
rubocop-factory_bot (2.25.1)
rubocop (~> 1.41)
rubocop-rails (2.25.0)
lint_roller (>= 1.1.0)
rubocop-capybara (>= 2.23.0)
rubocop-discourse-base (>= 1.0.0)
rubocop-factory_bot (>= 2.27.0)
rubocop-rails (>= 2.30.3)
rubocop-rspec (>= 3.0.1)
rubocop-rspec_rails (>= 2.31.0)
rubocop-discourse-base (1.0.0)
rubocop (>= 1.80.0)
rubocop-factory_bot (2.28.0)
lint_roller (~> 1.1)
rubocop (~> 1.72, >= 1.72.1)
rubocop-rails (2.35.5)
activesupport (>= 4.2.0)
lint_roller (~> 1.1)
rack (>= 1.1)
rubocop (>= 1.33.0, < 2.0)
rubocop-ast (>= 1.31.1, < 2.0)
rubocop-rspec (2.29.2)
rubocop (~> 1.40)
rubocop-capybara (~> 2.17)
rubocop-factory_bot (~> 2.22)
rubocop-rspec_rails (~> 2.28)
rubocop-rspec_rails (2.28.3)
rubocop (~> 1.40)
rubocop (>= 1.75.0, < 2.0)
rubocop-ast (>= 1.44.0, < 2.0)
rubocop-rspec (3.10.2)
lint_roller (~> 1.1)
regexp_parser (>= 2.0)
rubocop (~> 1.86, >= 1.86.2)
rubocop-rspec_rails (2.32.0)
lint_roller (~> 1.1)
rubocop (~> 1.72, >= 1.72.1)
rubocop-rspec (~> 3.5)
ruby-progressbar (1.13.0)
syntax_tree (6.2.0)
securerandom (0.4.1)
syntax_tree (6.3.0)
prettier_print (>= 1.2.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
unicode-display_width (2.5.0)
unicode-display_width (3.2.0)
unicode-emoji (~> 4.1)
unicode-emoji (4.2.0)
uri (1.1.1)

PLATFORMS
ruby
Expand All @@ -84,4 +103,4 @@ DEPENDENCIES
syntax_tree

BUNDLED WITH
2.5.10
4.0.15
4 changes: 2 additions & 2 deletions app/controllers/bb_code/admin/refresh_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ def index
begin
# Skip warmup in development mode - it makes boot take ~2s longer
PrettyText.cook("warm up **pretty text**")
render json: nil, status: 200
render json: nil, status: :ok
rescue => e
Rails.logger.error("Failed to warm up pretty text: #{e}")
render json: nil, status: 500
render json: nil, status: :internal_server_error
end
end
end
Expand Down
198 changes: 13 additions & 185 deletions assets/javascripts/discourse/initializers/accordion.js
Original file line number Diff line number Diff line change
@@ -1,192 +1,20 @@
/**
* @file Initializes any accordion tag with proper js/event handling
*/
import { withPluginApi } from "discourse/lib/plugin-api";
import { createDisclosureDecorator } from "../lib/bbcode-disclosures";

/**
* Adds the inline js for accordion inside a given post
* @param {HTMLElement} post the post itself
*/
function addAccordionCode(post) {
post.querySelectorAll("div.bb-accordion").forEach((el) => {
// eslint-disable-next-line no-new
new Accordion(el);
});
}

/**
* @typedef Slide
* @type {object}
* @property {HTMLDetailsElement} details
* @property {HTMLElement} summary
* @property {HTMLElement} content
* @property {Animation | null} animation
* @property {boolean} isClosing
* @property {boolean} isExpanding
*/

class Accordion {
/** @type {Element} */
accordion;
/** @type {Slide[]} */
slides = [];

/**
* Constructs the WAAPI powered accordion
* @param {Element} el
*/
constructor(el) {
this.accordion = el;
const details = this.accordion.querySelectorAll("details.bb-slide");
details.forEach((detail) => {
/** @type {Slide} */
const slide = {
details: detail,
summary: detail.querySelector("summary.bb-slide-title"),
content: detail.querySelector(".bb-slide-content"),
animation: null, // Store the animation object (so we can cancel it if needed)
isClosing: false,
isExpanding: false,
};
slide.summary?.addEventListener("click", (ev) => this.onClick(ev, slide));
this.slides.push(slide);
});
}

/**
* @param {MouseEvent} ev
* @param {Slide} slide
*/
onClick(ev, slide) {
// Stop default behaviour from the browser
ev.preventDefault();
// Add an overflow on the <details> to avoid content overflowing
slide.details.style.overflow = "hidden";
// Check if the element is being closed or is already closed
if (slide.isClosing || !slide.details.open) {
this.open(slide);
// Check if the element is being openned or is already open
} else if (slide.isExpanding || slide.details.open) {
this.shrink(slide);
}
}

/**
* @param {Slide} slide
*/
shrink(slide) {
// Set the element as "being closed"
slide.isClosing = true;
slide.details.style.overflow = "hidden";

// Store the current height of the element
const startHeight = `${slide.details.offsetHeight}px`;
// Calculate the height of the summary
const endHeight = `${slide.summary.offsetHeight}px`;

// If there is already an animation running
if (slide.animation) {
// Cancel the current animation
slide.animation.cancel();
}

// Start a WAAPI animation
slide.animation = slide.details.animate(
{
// Set the keyframes from the startHeight to endHeight
height: [startHeight, endHeight],
},
{
duration: 400,
easing: "linear",
}
);

// When the animation is complete, call onAnimationFinish()
slide.animation.onfinish = () => this.onAnimationFinish(false, slide);
// If the animation is cancelled, isClosing variable is set to false
slide.animation.oncancel = () => (slide.isClosing = false);
}

/**
* @param {Slide} slide
*/
open(slide) {
// Apply a fixed height on the element
slide.details.style.height = `${slide.details.offsetHeight}px`;
// Force the [open] attribute on the details element
slide.details.open = true;
// Wait for the next frame to call the expand function
const otherSlides = this.slides.filter((x) => x !== slide);
for (const otherSlide of otherSlides) {
this.shrink(otherSlide);
}
window.requestAnimationFrame(() => this.expand(slide));
}

/**
* @param {Slide} slide
*/
expand(slide) {
// Set the element as "being expanding"
slide.isExpanding = true;
// Get the current fixed height of the element
const startHeight = `${slide.details.offsetHeight}px`;
// Calculate the open height of the element (summary height + content height)
const endHeight = `${slide.summary.offsetHeight + slide.content.offsetHeight}px`;

// If there is already an animation running
if (slide.animation) {
// Cancel the current animation
slide.animation.cancel();
}

// Start a WAAPI animation
slide.animation = slide.details.animate(
{
// Set the keyframes from the startHeight to endHeight
height: [startHeight, endHeight],
},
{
duration: 400,
easing: "linear",
}
);
// When the animation is complete, call onAnimationFinish()
slide.animation.onfinish = () => this.onAnimationFinish(true, slide);
// If the animation is cancelled, isExpanding variable is set to false
slide.animation.oncancel = () => (slide.isExpanding = false);
}

/**
* @param {boolean} open
* @param {Slide} slide
*/
onAnimationFinish(open, slide) {
// Set the open attribute based on the parameter
slide.details.open = open;
// Clear the stored animation
slide.animation = null;
// Reset isClosing & isExpanding
slide.isClosing = false;
slide.isExpanding = false;
// Remove the overflow hidden and the fixed height
slide.details.style.height = slide.details.style.overflow = "";
}
}

/**
* The initial called function.
* Any calls to the PluginAPI should be done in here
* @param api
*/
function initializeAccordion(api) {
api.decorateCookedElement(addAccordionCode, { id: "add accordions" });
}
export const addAccordionCode = createDisclosureDecorator({
selector: ".bb-accordion details.bb-slide",
groupSelector: ".bb-accordion",
duration: 400,
easing: "linear",
});

export default {
name: "accordion",
name: "bbcode-accordion",
initialize() {
withPluginApi("0.11.1", initializeAccordion);
withPluginApi((api) => {
if (api.container.lookup("service:site-settings").bbcode_enabled) {
api.decorateCookedElement(addAccordionCode);
}
});
},
};
Loading
Loading