Skip to content

Commit

Permalink
Merge branch 'master' into fix-reddit-link-generation-crashing-websit…
Browse files Browse the repository at this point in the history
…e-if-encodeURI-fails
  • Loading branch information
calculuschild authored Dec 16, 2024
2 parents cb16b32 + 889f80f commit 962a46a
Show file tree
Hide file tree
Showing 85 changed files with 2,543 additions and 1,548 deletions.
3 changes: 3 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ jobs:
- run:
name: Test - Routes
command: npm run test:route
- run:
name: Test - HTML sanitization
command: npm run test:safehtml
- run:
name: Test - Coverage
command: npm run test:coverage
Expand Down
25 changes: 13 additions & 12 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
<!--
Before submitting a Pull Request, please consider the following to speed up reviews:
- 👷‍♀️ Create small PRs. Large PRs can usually be broken down into incremental PRs.
- 🚩 Do you already have several open PRs? Consider finishing or asking for help with existing PRs first.
- 🔧 Does your PR reference a discussed and approved issue, especially for personal or edge-case requests?
- 💡 Is the solution agreed upon? Save rework time by discussing strategy before coding.
-->
> [!TIP]
> Before submitting a Pull Request, please consider the following to speed up reviews:
> - 👷‍♀️ Create small PRs. Large PRs can usually be broken down into incremental PRs.
> - 🚩 Do you already have several open PRs? Consider finishing or asking for help with existing PRs first.
> - 🔧 Does your PR reference a discussed and approved issue, especially for personal or edge-case requests?
> - 💡 Is the solution agreed upon? Save rework time by discussing strategy before coding.
## Description

_Describe what your PR accomplishes. Consider walking through the main changes to aid reviewers in following your code, especially if it covers multiple files._

## Related Issues or Discussions

> [!CAUTION]
> If no issue exists yet, create it, and get agreement on the approach (or paste in a previous agreement from chat, etc.) before moving forward. (Experimental PRs are OK without prior discussion, but do not expect to get merged.)
- Closes #

## QA Instructions, Screenshots, Recordings

_Please replace this line with instructions on how to test or view your changes, as well as any before/after
images for UI changes._
_Replace this line with instructions on how to test or view your changes, as well as any before/after
screenshots or recordings for UI changes._

### Reviewer Checklist

_Please replace the list below with specific features you want reviewers to look at._
_Replace the list below with specific features you want reviewers to look at._

*Reviewers, refer to this list when testing features, or suggest new items *
- [ ] Verify new features are functional
Expand All @@ -32,5 +35,3 @@ _Please replace the list below with specific features you want reviewers to look
- [ ] Feature A handles negative numbers
- [ ] Identify opportunities for simplification and refactoring
- [ ] Check for code legibility and appropriate comments

<details><summary>Copy this list</summary>
10 changes: 10 additions & 0 deletions babel.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"presets": [
"@babel/preset-env",
"@babel/preset-react"
],
"plugins": [
"@babel/plugin-transform-runtime",
"babel-plugin-transform-import-meta"
]
}
46 changes: 46 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,52 @@ pre {
## changelog
For a full record of development, visit our [Github Page](https://github.com/naturalcrit/homebrewery).

### Wednesday 11/27/2024 - v3.16.1

{{taskList
##### 5e-Cleric

* [x] Allow linking to specific HTML IDs via `#ID` at the end of the URL, e.g.: `homebrewery.naturalcrit.com/share/share/a6RCXwaDS58i#p4` to link to Page 4 directly

Fixes issues [#2820](https://github.com/naturalcrit/homebrewery/issues/2820), [#3505](https://github.com/naturalcrit/homebrewery/issues/3505)

* [x] Fix generation of link to certain Google Drive brews

Fixes issue [#3776](https://github.com/naturalcrit/homebrewery/issues/3776)

##### abquintic

* [x] Fix blank pages appearing when pasting text

Fixes issue [#3718](https://github.com/naturalcrit/homebrewery/issues/3718)

##### Gazook89

* [x] Add new brew viewing options to the view toolbar
- {{fac,single-spread}} {{openSans **SINGLE PAGE**}}
- {{fac,facing-spread}} {{openSans **TWO PAGE**}}
- {{fac,flow-spread}} {{openSans **GRID**}}

Fixes issue [#1379](https://github.com/naturalcrit/homebrewery/issues/1379)

* [x] Updates to tag input boxes

##### G-Ambatte

* [x] Admin tools to fix certain corrupted documents

Fixes issue [#3801](https://github.com/naturalcrit/homebrewery/issues/3801)

* [x] Fix print window being affected by document zoom

Fixes issue [#3744](https://github.com/naturalcrit/homebrewery/issues/3744)


##### calculuschild, 5e-Cleric, G-Ambatte, Gazook89, abquintic

* [x] Multiple code refactors, cleanups, and security fixes
}}

### Saturday 10/12/2024 - v3.16.0

{{taskList
Expand Down
48 changes: 41 additions & 7 deletions client/admin/brewUtils/brewLookup/brewLookup.jsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
require('./brewLookup.less');

const React = require('react');
const createClass = require('create-react-class');
const cx = require('classnames');
Expand All @@ -12,22 +14,43 @@ const BrewLookup = createClass({
},
getInitialState() {
return {
query : '',
foundBrew : null,
searching : false,
error : null
query : '',
foundBrew : null,
searching : false,
error : null,
scriptCount : 0
};
},
handleChange(e){
this.setState({ query: e.target.value });
},
lookup(){
this.setState({ searching: true, error: null });
this.setState({ searching: true, error: null, scriptCount: 0 });

request.get(`/admin/lookup/${this.state.query}`)
.then((res)=>this.setState({ foundBrew: res.body }))
.then((res)=>{
const foundBrew = res.body;
const scriptCheck = foundBrew?.text.match(/(<\/?s)cript/g);
this.setState({
foundBrew : foundBrew,
scriptCount : scriptCheck?.length || 0,
});
})
.catch((err)=>this.setState({ error: err }))
.finally(()=>this.setState({ searching: false }));
.finally(()=>{
this.setState({
searching : false
});
});
},

async cleanScript(){
if(!this.state.foundBrew?.shareId) return;

await request.put(`/admin/clean/script/${this.state.foundBrew.shareId}`)
.catch((err)=>{ this.setState({ error: err }); return; });

this.lookup();
},

renderFoundBrew(){
Expand All @@ -46,12 +69,23 @@ const BrewLookup = createClass({
<dt>Share Link</dt>
<dd><a href={`/share/${brew.shareId}`} target='_blank' rel='noopener noreferrer'>/share/{brew.shareId}</a></dd>

<dt>Created Time</dt>
<dd>{brew.createdAt ? Moment(brew.createdAt).toLocaleString() : 'No creation date'}</dd>

<dt>Last Updated</dt>
<dd>{Moment(brew.updatedAt).fromNow()}</dd>

<dt>Num of Views</dt>
<dd>{brew.views}</dd>

<dt>SCRIPT tags detected</dt>
<dd>{this.state.scriptCount}</dd>
</dl>
{this.state.scriptCount > 0 &&
<div className='cleanButton'>
<button onClick={this.cleanScript}>CLEAN BREW</button>
</div>
}
</div>;
},

Expand Down
6 changes: 6 additions & 0 deletions client/admin/brewUtils/brewLookup/brewLookup.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.brewLookup {
.cleanButton {
display : inline-block;
width : 100%;
}
}
91 changes: 91 additions & 0 deletions client/components/Anchored.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import React, { useState, useRef, forwardRef, useEffect, cloneElement, Children } from 'react';
import './Anchored.less';

// Anchored is a wrapper component that must have as children an <AnchoredTrigger> and a <AnchoredBox> component.
// AnchoredTrigger must have a unique `id` prop, which is passed up to Anchored, saved in state on mount, and
// then passed down through props into AnchoredBox. The `id` is used for the CSS Anchor Positioning properties.
// **The Anchor Positioning API is not available in Firefox yet**
// So in Firefox the positioning isn't perfect but is likely sufficient, and FF team seems to be working on the API quickly.


const Anchored = ({ children })=>{
const [visible, setVisible] = useState(false);
const [anchorId, setAnchorId] = useState(null);
const boxRef = useRef(null);
const triggerRef = useRef(null);

// promote trigger id to Anchored id (to pass it back down to the box as "anchorId")
useEffect(()=>{
if(triggerRef.current){
setAnchorId(triggerRef.current.id);
}
}, []);

// close box on outside click or Escape key
useEffect(()=>{
const handleClickOutside = (evt)=>{
if(
boxRef.current &&
!boxRef.current.contains(evt.target) &&
triggerRef.current &&
!triggerRef.current.contains(evt.target)
) {
setVisible(false);
}
};

const handleEscapeKey = (evt)=>{
if(evt.key === 'Escape') setVisible(false);
};

window.addEventListener('click', handleClickOutside);
window.addEventListener('keydown', handleEscapeKey);

return ()=>{
window.removeEventListener('click', handleClickOutside);
window.removeEventListener('keydown', handleEscapeKey);
};
}, []);

const toggleVisibility = ()=>setVisible((prev)=>!prev);

// Map children to inject necessary props
const mappedChildren = Children.map(children, (child)=>{
if(child.type === AnchoredTrigger) {
return cloneElement(child, { ref: triggerRef, toggleVisibility, visible });
}
if(child.type === AnchoredBox) {
return cloneElement(child, { ref: boxRef, visible, anchorId });
}
return child;
});

return <>{mappedChildren}</>;
};

// forward ref for AnchoredTrigger
const AnchoredTrigger = forwardRef(({ toggleVisibility, visible, children, className, ...props }, ref)=>(
<button
ref={ref}
className={`anchored-trigger${visible ? ' active' : ''} ${className}`}
onClick={toggleVisibility}
style={{ anchorName: `--${props.id}` }} // setting anchor properties here allows greater recyclability.
{...props}
>
{children}
</button>
));

// forward ref for AnchoredBox
const AnchoredBox = forwardRef(({ visible, children, className, anchorId, ...props }, ref)=>(
<div
ref={ref}
className={`anchored-box${visible ? ' active' : ''} ${className}`}
style={{ positionAnchor: `--${anchorId}` }} // setting anchor properties here allows greater recyclability.
{...props}
>
{children}
</div>
));

export { Anchored, AnchoredTrigger, AnchoredBox };
13 changes: 13 additions & 0 deletions client/components/Anchored.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@


.anchored-box {
position:absolute;
@supports (inset-block-start: anchor(bottom)){
inset-block-start: anchor(bottom);
}
justify-self: anchor-center;
visibility: hidden;
&.active {
visibility: visible;
}
}
14 changes: 7 additions & 7 deletions client/components/dialog.jsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
// Dialog box, for popups and modal blocking messages
import React from "react";
import React from 'react';
const { useRef, useEffect } = React;

function Dialog({ dismisskeys, closeText = 'Close', blocking = false, ...rest }) {
function Dialog({ dismisskeys = [], closeText = 'Close', blocking = false, ...rest }) {
const dialogRef = useRef(null);

useEffect(()=>{
if (dismisskeys.length !== 0) {
if(dismisskeys.length !== 0) {
blocking ? dialogRef.current?.showModal() : dialogRef.current?.show();
}
}, [dialogRef.current, dismisskeys]);

const dismiss = () => {
dismisskeys.forEach(key => {
if (key) {
const dismiss = ()=>{
dismisskeys.forEach((key)=>{
if(key) {
localStorage.setItem(key, 'true');
}
});
dialogRef.current?.close();
};

return (
<dialog ref={dialogRef} onCancel={dismiss} {...rest}>
{rest.children}
Expand Down
Loading

0 comments on commit 962a46a

Please sign in to comment.