Skip to content
Draft
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .lintstagedrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@
"yii2-adapter/**/*.scss": ["stylelint --fix --allow-empty-input -c ./yii2-adapter/.stylelintrc.json"],
"!(yii2-adapter)/**/*.scss": ["stylelint --fix --allow-empty-input"],
"!(yii2-adapter)/**/*.{html,json,css,scss}": "prettier --ignore-unknown --write",
"resources/js/**/*.{ts,vue}": ["eslint"]
"resources/js/**/*.{ts,vue}": ["eslint", "vue-tsc --noEmit"]
}
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
- Fixed a bug where Single sections had Max Authors settings. ([#19001](https://github.com/craftcms/cms/pull/19001))
- Fixed a bug where Channel and Structure sections didn’t have Max Authors settings. ([#19001](https://github.com/craftcms/cms/pull/19001))
- Fixed a bug where sections’ Min Authors settings were defaulting to `1` when blank. ([#19001](https://github.com/craftcms/cms/pull/19001))
- Fixed a JavaScript error that could occur in the Control Panel when a custom element was registered more than once.
- Fixed a bug where Control Panel action menu items could trigger their action twice when clicked.
- Fixed a bug where legacy Control Panel JavaScript wasn’t loaded and initialized on all Control Panel pages.

## 6.0.0-alpha.5 - 2026-05-27

Expand Down
4 changes: 2 additions & 2 deletions packages/craftcms-cp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
"dev": "node ./scripts/build.js --develop",
"prebuild": "npm run format",
"build": "node ./scripts/build.js",
"format": "npx prettier --write .",
"check:format": "prettier --check .",
"format": "npx prettier --write ./src",
"check:format": "prettier --check ./src",
"check:exports": "attw --pack .",
"check:types": "tsc --noEmit",
"storybook": "storybook dev -p 6006",
Expand Down
8 changes: 6 additions & 2 deletions packages/craftcms-legacy/cp/src/js/CP.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import {QueueService} from '@craftcms/cp';
// Import from the deep service module rather than the package root. The root
// entry (`@craftcms/cp`) side-effect-registers WebAwesome components (e.g.
// `wa-icon`); pulling that into this separately-webpacked legacy bundle causes
// a duplicate custom-element registration when it loads alongside the Vite app.
import {QueueService} from '@craftcms/cp/services/Queue.ts.mjs';
/** global: Craft */
/** global: Garnish */
/** global: $ */
Expand Down Expand Up @@ -1322,7 +1326,7 @@ Craft.CP = Garnish.Base.extend(
if (Array.isArray(alerts) && alerts.length) {
this.$alerts = $('<ul id="alerts"/>').prependTo(this.$pageContainer);

for (const alert of alerts) {
for (let alert of alerts) {
if (!$.isPlainObject(alert)) {
alert = {
content: alert,
Expand Down
206 changes: 7 additions & 199 deletions packages/craftcms-legacy/cp/src/js/Craft.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
// Import from the deep module rather than the package root, which
// side-effect-registers WebAwesome components (e.g. `wa-icon`) and would
// duplicate those registrations in this separately-webpacked legacy bundle.
import {t, formatMessage} from '@craftcms/cp/utilities/translate.ts.mjs';
import * as d3 from 'd3';

/** global: Craft */
Expand Down Expand Up @@ -81,208 +85,12 @@ $.extend(Craft, {
* @param {Object} params
* @returns {string}
*/
t: function (category, message, params) {
if (
typeof Craft.translations[category] !== 'undefined' &&
typeof Craft.translations[category][message] !== 'undefined'
) {
message = Craft.translations[category][message];
}

if (params) {
return this.formatMessage(message, params);
}

return message;
t: function (category, message, params = {}) {
return t(message, params, category = 'app', Craft.translations);
},

formatMessage: function (pattern, args) {
let tokens;
if ((tokens = this._tokenizePattern(pattern)) === false) {
throw 'Message pattern is invalid.';
}
for (let i = 0; i < tokens.length; i++) {
let token = tokens[i];
if (typeof token === 'object') {
if ((tokens[i] = this._parseToken(token, args)) === false) {
throw 'Message pattern is invalid.';
}
}
}
return tokens.join('');
},

_tokenizePattern: function (pattern) {
let depth = 1,
start,
pos;
// Get an array of the string characters (factoring in 3+ byte chars)
const chars = [...pattern];
if ((start = pos = chars.indexOf('{')) === -1) {
return [pattern];
}
let tokens = [chars.slice(0, pos).join('')];
while (true) {
let open = chars.indexOf('{', pos + 1);
let close = chars.indexOf('}', pos + 1);
if (open === -1) {
open = false;
}
if (close === -1) {
close = false;
}
if (open === false && close === false) {
break;
}
if (open === false) {
open = chars.length;
}
if (close > open) {
depth++;
pos = open;
} else {
depth--;
pos = close;
}
if (depth === 0) {
tokens.push(
chars
.slice(start + 1, pos)
.join('')
.split(',', 3)
);
start = pos + 1;
tokens.push(chars.slice(start, open).join(''));
start = open;
}

if (depth !== 0 && (open === false || close === false)) {
break;
}
}
if (depth !== 0) {
return false;
}

return tokens;
},

_parseToken: function (token, args) {
// parsing pattern based on ICU grammar:
// http://icu-project.org/apiref/icu4c/classMessageFormat.html#details
const param = token[0].trim();
if (typeof args[param] === 'undefined') {
return `{${token.join(',')}}`;
}
const arg = args[param];
const type = typeof token[1] !== 'undefined' ? token[1].trim() : 'none';
switch (type) {
case 'number':
return (() => {
let format = typeof token[2] !== 'undefined' ? token[2].trim() : null;
if (format !== null && format !== 'integer') {
throw `Message format 'number' is only supported for integer values.`;
}
let number = Craft.formatNumber(arg);
let pos;
if (format === null && (pos = `${arg}`.indexOf('.')) !== -1) {
number += `.${arg.substring(pos + 1)}`;
}
return number;
})();
case 'none':
return arg;
case 'select':
return (() => {
/* http://icu-project.org/apiref/icu4c/classicu_1_1SelectFormat.html
selectStyle = (selector '{' message '}')+
*/
if (typeof token[2] === 'undefined') {
return false;
}
let select = this._tokenizePattern(token[2]);
let c = select.length;
let message = false;
for (let i = 0; i + 1 < c; i++) {
if (Array.isArray(select[i]) || !Array.isArray(select[i + 1])) {
return false;
}
let selector = select[i++].trim();
if (
(message === false && selector === 'other') ||
selector == arg
) {
message = select[i].join(',');
}
}
if (message === false) {
return false;
}
return this.formatMessage(message, args);
})();
case 'plural':
return (() => {
/* http://icu-project.org/apiref/icu4c/classicu_1_1PluralFormat.html
pluralStyle = [offsetValue] (selector '{' message '}')+
offsetValue = "offset:" number
selector = explicitValue | keyword
explicitValue = '=' number // adjacent, no white space in between
keyword = [^[[:Pattern_Syntax:][:Pattern_White_Space:]]]+
message: see MessageFormat
*/
if (typeof token[2] === 'undefined') {
return false;
}
let plural = this._tokenizePattern(token[2]);
const c = plural.length;
let message = false;
let offset = 0;
for (let i = 0; i + 1 < c; i++) {
if (
typeof plural[i] === 'object' ||
typeof plural[i + 1] !== 'object'
) {
return false;
}
let selector = plural[i++].trim();
let selectorChars = [...selector];

if (i === 1 && selector.substring(0, 7) === 'offset:') {
let pos = [...selector.replace(/[\n\r\t]/g, ' ')].indexOf(' ', 7);
if (pos === -1) {
throw 'Message pattern is invalid.';
}
offset = parseInt(selectorChars.slice(7, pos).join('').trim());
selector = selectorChars
.slice(pos + 1, pos + 1 + selectorChars.length)
.join('')
.trim();
}
if (
(message === false && selector === 'other') ||
(selector[0] === '=' &&
parseInt(
selectorChars.slice(1, 1 + selectorChars.length).join('')
) === arg) ||
(selector === 'one' && arg - offset === 1)
) {
message = (
typeof plural[i] === 'string' ? [plural[i]] : plural[i]
)
.map((p) => {
return p.replace('#', arg - offset);
})
.join(',');
}
}
if (message === false) {
return false;
}
return this.formatMessage(message, args);
})();
default:
throw `Message format '${type}' is not supported.`;
}
return formatMessage(pattern, args);
},

formatDate: function (date) {
Expand Down
2 changes: 1 addition & 1 deletion packages/craftcms-legacy/cp/src/js/UI.js
Original file line number Diff line number Diff line change
Expand Up @@ -1241,7 +1241,7 @@ Craft.ui = {
return $(instance.list);
};

getAccessibleName = () => {
const getAccessibleName = () => {
return $input.attr('aria-label');
};

Expand Down

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion resources/build/assets/AppLayout-CMfRP4dO.js

This file was deleted.

1 change: 1 addition & 0 deletions resources/build/assets/AppLayout-CjKT-72e.js

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading