Skip to content

Commit 4d2692f

Browse files
authored
Merge branch 'develop' into clairep94-patch-3714
2 parents 7a6640d + a29ccf6 commit 4d2692f

File tree

14 files changed

+222
-55
lines changed

14 files changed

+222
-55
lines changed

client/index.jsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@ const store = setupStore(initialState);
2323

2424
const DONATE_LOGO_IMAGE_URL = 'https://donorbox.org/images/white_logo.svg';
2525

26+
const showDonateCampaign = false;
27+
2628
if (
29+
showDonateCampaign &&
2730
window.location.href.indexOf('full') === -1 &&
2831
window.location.href.indexOf('embed') === -1
2932
) {

client/modules/IDE/components/Preferences/index.jsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,8 @@ import {
2121
setLinewrap,
2222
setPreferencesTab
2323
} from '../../actions/preferences';
24-
import {
25-
majorVersion,
26-
p5SoundURL,
27-
p5URL,
28-
useP5Version
29-
} from '../../hooks/useP5Version';
24+
import { majorVersion, p5URL, useP5Version } from '../../hooks/useP5Version';
25+
import p5SoundURL from '../../../../../common/p5URLs';
3026
import VersionPicker from '../VersionPicker';
3127
import { updateFileContent } from '../../actions/files';
3228
import { CmControllerContext } from '../../pages/IDEView';

client/modules/IDE/hooks/useP5Version.jsx

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,22 @@ import React, { useContext, useMemo } from 'react';
33
import { useSelector } from 'react-redux';
44
import PropTypes from 'prop-types';
55
import { currentP5Version, p5Versions } from '../../../../common/p5Versions';
6+
import {
7+
p5SoundURLOldTemplate,
8+
p5SoundURL,
9+
p5PreloadAddonURL,
10+
p5ShapesAddonURL,
11+
p5DataAddonURL,
12+
p5URLTemplate
13+
} from '../../../../common/p5URLs';
614

715
export const majorVersion = (version) => version.split('.')[0];
816

9-
export const p5SoundURLOldTemplate =
10-
'https://cdnjs.cloudflare.com/ajax/libs/p5.js/$VERSION/addons/p5.sound.min.js';
1117
export const p5SoundURLOld = p5SoundURLOldTemplate.replace(
1218
'$VERSION',
1319
currentP5Version
1420
);
15-
export const p5SoundURL =
16-
'https://cdn.jsdelivr.net/npm/[email protected]/dist/p5.sound.min.js';
17-
export const p5PreloadAddonURL =
18-
'https://cdn.jsdelivr.net/npm/[email protected]/src/preload.js';
19-
export const p5ShapesAddonURL =
20-
'https://cdn.jsdelivr.net/npm/[email protected]/src/shapes.js';
21-
export const p5DataAddonURL =
22-
'https://cdn.jsdelivr.net/npm/[email protected]/src/data.js';
23-
export const p5URL = `https://cdn.jsdelivr.net/npm/p5@${currentP5Version}/lib/p5.js`;
21+
export const p5URL = p5URLTemplate.replace('$VERSION', currentP5Version);
2422

2523
const P5VersionContext = React.createContext({});
2624

client/modules/IDE/reducers/files.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@ import {
55
defaultCSS,
66
defaultHTML
77
} from '../../../../server/domain-objects/createDefaultFiles';
8+
import { parseUrlParams } from '../../../utils/parseURLParams';
89

910
export const initialState = () => {
1011
const a = objectID().toHexString();
1112
const b = objectID().toHexString();
1213
const c = objectID().toHexString();
1314
const r = objectID().toHexString();
15+
const params = parseUrlParams(window.location.href);
1416
return [
1517
{
1618
name: 'root',
@@ -32,7 +34,7 @@ export const initialState = () => {
3234
},
3335
{
3436
name: 'index.html',
35-
content: defaultHTML,
37+
content: defaultHTML(params),
3638
id: b,
3739
_id: b,
3840
fileType: 'file',

client/utils/parseURLParams.js

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import { p5Versions, currentP5Version } from '../../common/p5Versions';
2+
3+
const DEFAULTS = {
4+
sound: true,
5+
preload: false,
6+
shapes: false,
7+
data: false
8+
};
9+
10+
/**
11+
* Sorts version strings in descending order and returns the highest version
12+
* @param {string[]} versions - Array of version strings (e.g., ['1.11.2', '1.11.1'])
13+
* @returns {string} The highest version from the array
14+
*/
15+
function getNewestVersion(versions) {
16+
return versions.sort((a, b) => {
17+
const pa = a.split('.').map((n) => parseInt(n, 10));
18+
const pb = b.split('.').map((n) => parseInt(n, 10));
19+
for (let i = 0; i < 3; i++) {
20+
const na = pa[i] || 0;
21+
const nb = pb[i] || 0;
22+
if (na !== nb) return nb - na;
23+
}
24+
return 0;
25+
})[0];
26+
}
27+
28+
function validateVersion(version) {
29+
if (!version) return currentP5Version;
30+
31+
const ver = String(version).trim();
32+
33+
if (p5Versions.includes(ver)) return ver;
34+
35+
// if only major.minor provided like "1.11"
36+
const majorMinorMatch = /^(\d+)\.(\d+)$/.exec(ver);
37+
if (majorMinorMatch) {
38+
const [, major, minor] = majorMinorMatch;
39+
const matches = p5Versions.filter((v) => {
40+
const parts = v.split('.');
41+
return parts[0] === major && parts[1] === minor;
42+
});
43+
if (matches.length) {
44+
return getNewestVersion(matches);
45+
}
46+
}
47+
48+
// if only major provided like "1"
49+
const majorOnlyMatch = /^(\d+)$/.exec(ver);
50+
if (majorOnlyMatch) {
51+
const [, major] = majorOnlyMatch;
52+
const matches = p5Versions.filter((v) => v.split('.')[0] === major);
53+
if (matches.length) {
54+
return getNewestVersion(matches);
55+
}
56+
}
57+
58+
return currentP5Version;
59+
}
60+
61+
function validateBool(value, defaultValue) {
62+
if (!value) return defaultValue;
63+
64+
const v = String(value).trim().toLowerCase();
65+
66+
const TRUTHY = new Set(['on', 'true', '1']);
67+
const FALSY = new Set(['off', 'false', '0']);
68+
69+
if (TRUTHY.has(v)) return true;
70+
if (FALSY.has(v)) return false;
71+
72+
return defaultValue;
73+
}
74+
75+
export function parseUrlParams(url) {
76+
const params = new URLSearchParams(
77+
new URL(url, 'https://dummy.origin').search
78+
);
79+
80+
return {
81+
version: validateVersion(params.get('version')),
82+
sound: validateBool(params.get('sound'), DEFAULTS.sound),
83+
preload: validateBool(params.get('preload'), DEFAULTS.preload),
84+
shapes: validateBool(params.get('shapes'), DEFAULTS.shapes),
85+
data: validateBool(params.get('data'), DEFAULTS.data)
86+
};
87+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { parseUrlParams } from './parseURLParams';
2+
import { currentP5Version } from '../../common/p5Versions';
3+
4+
describe('parseUrlParams', () => {
5+
test('returns defaults when no params are provided', () => {
6+
const url = 'https://example.com';
7+
const result = parseUrlParams(url);
8+
9+
expect(result).toEqual({
10+
version: currentP5Version,
11+
sound: true,
12+
preload: false,
13+
shapes: false,
14+
data: false
15+
});
16+
});
17+
18+
test('parses a valid p5 version and falls back for invalid versions', () => {
19+
const good = parseUrlParams('https://example.com?version=1.4.0');
20+
expect(good.version).toBe('1.4.0');
21+
22+
const bad = parseUrlParams('https://example.com?version=9.9.9');
23+
expect(bad.version).toBe(currentP5Version);
24+
});
25+
26+
test('parses boolean-like params for sound/preload/shapes/data (true variants)', () => {
27+
const trueVariants = ['on', 'true', '1', 'ON', 'True'];
28+
29+
trueVariants.forEach((v) => {
30+
const url = `https://example.com?sound=${v}&preload=${v}&shapes=${v}&data=${v}`;
31+
const result = parseUrlParams(url);
32+
expect(result.sound).toBe(true);
33+
expect(result.preload).toBe(true);
34+
expect(result.shapes).toBe(true);
35+
expect(result.data).toBe(true);
36+
});
37+
});
38+
39+
test('parses boolean-like params for sound/preload/shapes/data (false variants)', () => {
40+
const falseVariants = ['off', 'false', '0', 'OFF', 'False'];
41+
42+
falseVariants.forEach((v) => {
43+
const url = `https://example.com?sound=${v}&preload=${v}&shapes=${v}&data=${v}`;
44+
const result = parseUrlParams(url);
45+
expect(result.sound).toBe(false);
46+
expect(result.preload).toBe(false);
47+
expect(result.shapes).toBe(false);
48+
expect(result.data).toBe(false);
49+
});
50+
});
51+
});

client/utils/rename-variable.js

Lines changed: 11 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,6 @@ function startRenaming(cm, ast, fromPos, newName, oldName) {
4646

4747
const startIndex = node.start;
4848
const endIndex = node.end;
49-
50-
if (node.name !== oldName) return;
51-
5249
const pos = cm.posFromIndex(startIndex);
5350

5451
if (
@@ -57,19 +54,15 @@ function startRenaming(cm, ast, fromPos, newName, oldName) {
5754
parent.type === 'ArrowFunctionExpression') &&
5855
parent.params.some((p) => p.type === 'Identifier' && p.name === oldName)
5956
) {
60-
if (!parent.params.includes(node)) {
61-
return;
62-
}
57+
if (!parent.params.includes(node)) return;
6358
}
6459

6560
if (
6661
parent.type === 'MemberExpression' &&
6762
parent.property === node &&
6863
!parent.computed
6964
) {
70-
if (parent.object.type === 'ThisExpression' && !isBaseThis) {
71-
return;
72-
}
65+
if (parent.object.type === 'ThisExpression' && !isBaseThis) return;
7366
}
7467

7568
const thisContext = getContext(
@@ -84,6 +77,8 @@ function startRenaming(cm, ast, fromPos, newName, oldName) {
8477
let shouldRenameGlobalVar = false;
8578
const isThis = isThisReference(cm, ast, pos, oldName);
8679

80+
shouldRenameGlobalVar = isGlobal && thisContext === 'global';
81+
8782
// Handle renaming inside classes
8883
if (isInsideClassContext) {
8984
const tempPos = {
@@ -121,14 +116,6 @@ function startRenaming(cm, ast, fromPos, newName, oldName) {
121116
isThis === isBaseThis &&
122117
baseContext === thisContext
123118
) {
124-
Object.entries(classMeta.methodVars || {}).forEach(
125-
([methodName, vars]) => {
126-
if (!vars.includes(oldName) && thisContext === methodName) {
127-
const shouldRenameMethodVar = true;
128-
}
129-
}
130-
);
131-
132119
shouldRename =
133120
thisContext === baseContext &&
134121
(currentMethodName === 'constructor' || shouldRenameGlobalVar);
@@ -162,7 +149,6 @@ function startRenaming(cm, ast, fromPos, newName, oldName) {
162149
isGlobal &&
163150
!Object.prototype.hasOwnProperty.call(thisScopeVars, oldName);
164151
}
165-
shouldRenameGlobalVar = isGlobal && thisContext === 'global';
166152
}
167153
// Handle renaming outside classes
168154
else {
@@ -201,15 +187,13 @@ function startRenaming(cm, ast, fromPos, newName, oldName) {
201187
isBaseThis
202188
);
203189

204-
if (
205-
isThisGlobal &&
206-
thisContext in userDefinedFunctionMetadata &&
207-
userDefinedFunctionMetadata[thisContext].params.some(
208-
(param) => param.p === oldName
209-
)
210-
) {
211-
return;
212-
}
190+
const params = userDefinedFunctionMetadata[thisContext]?.params || [];
191+
const hasParamNamedOldName = params.some((param) =>
192+
typeof param === 'string'
193+
? param === oldName
194+
: param?.name === oldName || param?.p === oldName
195+
);
196+
if (isThisGlobal && hasParamNamedOldName) return;
213197

214198
const methodPath = path.findParent((p) => p.isClassMethod());
215199
let currentMethodName = null;

client/utils/showRenameDialog.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import announceToScreenReader from './ScreenReaderHelper';
22
import p5CodeAstAnalyzer from './p5CodeAstAnalyzer';
3-
import { getClassContext, getContext, getAST } from './renameVariableHelper';
3+
import { getContext, getAST } from './renameVariableHelper';
44

55
const allFuncs = require('./p5-reference-functions.json');
66

common/p5URLs.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
export const p5SoundURLOldTemplate =
2+
'https://cdnjs.cloudflare.com/ajax/libs/p5.js/$VERSION/addons/p5.sound.min.js';
3+
export const p5SoundURL =
4+
'https://cdn.jsdelivr.net/npm/[email protected]/dist/p5.sound.min.js';
5+
export const p5PreloadAddonURL =
6+
'https://cdn.jsdelivr.net/npm/[email protected]/src/preload.js';
7+
export const p5ShapesAddonURL =
8+
'https://cdn.jsdelivr.net/npm/[email protected]/src/shapes.js';
9+
export const p5DataAddonURL =
10+
'https://cdn.jsdelivr.net/npm/[email protected]/src/data.js';
11+
export const p5URLTemplate =
12+
'https://cdn.jsdelivr.net/npm/p5@$VERSION/lib/p5.js';

common/p5Versions.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
export const currentP5Version = '1.11.10'; // Don't update to 2.x until 2026
1+
export const currentP5Version = '1.11.11'; // Don't update to 2.x until 2026
22

33
// Generated from https://www.npmjs.com/package/p5?activeTab=versions
44
// Run this in the console:
55
// JSON.stringify([...document.querySelectorAll('._132722c7')].map(n => n.innerText), null, 2)
66
// TODO: use their API for this to grab these at build time?
77
export const p5Versions = [
8+
'2.1.1',
89
'2.0.5',
910
'2.0.4',
1011
'2.0.3',

0 commit comments

Comments
 (0)