Skip to content

Commit

Permalink
Crossdomain support for Craft.appendHeadHtml() & appendBodyHtml()
Browse files Browse the repository at this point in the history
Fixes #13715
  • Loading branch information
brandonkelly committed Sep 25, 2023
1 parent 2ab8a3e commit 94ed5f9
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 49 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
## Unreleased

- When slideouts are opened within Live Preview, they now slide up over the editor pane, rather than covering the preview pane. ([#13739](https://github.com/craftcms/cms/pull/13739))
- `Craft.appendHeadHtml()` and `appendBodyHtml()` now load external scripts asynchronously, and return promises.
- Fixed a bug where it wasn’t always possible to create new entries from custom sources which were limited to one section.
- Fixed a bug where relational fields weren’t factoring in cross-site elements when enforcing their “Min Relations”, “Max Relations”, and “Validate related entries” settings. ([#13699](https://github.com/craftcms/cms/issues/13699))
- Fixed a bug where pagination wasn’t working for admin tables, if the `onQueryParams` callback method wasn’t set. ([#13677](https://github.com/craftcms/cms/issues/13677))
- Fixed JavaScript errors that could occur when control panel resources were being loaded from a different domain. ([#13715](https://github.com/craftcms/cms/issues/13715))

## 4.5.5 - 2023-09-14

Expand Down
3 changes: 2 additions & 1 deletion src/web/assets/cp/dist/cp.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/web/assets/cp/dist/cp.js.LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
2 changes: 1 addition & 1 deletion src/web/assets/cp/dist/cp.js.map

Large diffs are not rendered by default.

120 changes: 73 additions & 47 deletions src/web/assets/cp/src/js/Craft.js
Original file line number Diff line number Diff line change
Expand Up @@ -1811,70 +1811,96 @@ $.extend(Craft, {
return $ul;
},

/**
* Appends HTML to the page `<head>`.
*
* @param {string} html
*/
appendHeadHtml: function (html) {
_existingCss: null,
_existingJs: null,

_appendHtml: async function (html, $parent) {
if (!html) {
return;
}

// Prune out any link tags that are already included
var $existingCss = $('link[href]');
const scriptUrls = [];

if ($existingCss.length) {
var existingCss = [];
var href;
const nodes = $.parseHTML(html.trim(), true).filter((node) => {
if (node.nodeName === 'LINK' && node.href) {
if (!this._existingCss) {
this._existingCss = $('link[href]')
.toArray()
.map((n) => n.href.replace(/&/g, '&amp;'));
}

for (var i = 0; i < $existingCss.length; i++) {
href = $existingCss.eq(i).attr('href').replace(/&/g, '&amp;');
existingCss.push(Craft.escapeRegex(href));
}
if (this._existingCss.includes(node.href)) {
return false;
}

const regexp = new RegExp(
'<link\\s[^>]*href="(?:' + existingCss.join('|') + ')".*?></link>',
'g'
);
this._existingCss.push(node.href);
return true;
}

html = html.replace(regexp, '');
}
if (node.nodeName === 'SCRIPT' && node.src) {
if (!this._existingJs) {
this._existingJs = $('script[src]')
.toArray()
.map((n) => n.src.replace(/&/g, '&amp;'));
}

$('head').append(html);
},
if (!this._existingJs.includes(node.src)) {
scriptUrls.push(node.src);
this._existingJs.push(node.src);
}

/**
* Appends HTML to the page `<body>`.
*
* @param {string} html
*/
appendBodyHtml: function (html) {
if (!html) {
return;
}
// return false either way since we are going to load it ourselves
return false;
}

// Prune out any script tags that are already included
var $existingJs = $('script[src]');
return true;
});

if ($existingJs.length) {
var existingJs = [];
var src;
await this._loadScripts(scriptUrls);
$parent.append(nodes);
},

for (var i = 0; i < $existingJs.length; i++) {
src = $existingJs.eq(i).attr('src').replace(/&/g, '&amp;');
existingJs.push(Craft.escapeRegex(src));
_loadScripts: function (urls) {
return new Promise((resolve) => {
if (!urls.length) {
resolve();
return;
}

var regexp = new RegExp(
'<script\\s[^>]*src="(?:' + existingJs.join('|') + ')".*?></script>',
'g'
);
const url = urls.shift();
$.ajaxSetup({cache: true});

html = html.replace(regexp, '');
}
$.getScript(url)
.done(() => {
$.ajaxSetup({cache: false});
this._loadScripts(urls).then(resolve);
})
.fail(() => {
console.error(`Failed to load ${url}:`);
$.ajaxSetup({cache: false});
this._loadScripts(urls).then(resolve);
});
});
},

Garnish.$bod.append(html);
/**
* Appends HTML to the page `<head>`.
*
* @param {string} html
* @returns {Promise}
*/
appendHeadHtml: async function (html) {
this._appendHtml(html, $('head'));
},

/**
* Appends HTML to the page `<body>`.
*
* @param {string} html
* @returns {Promise}
*/
appendBodyHtml: async function (html) {
this._appendHtml(html, Garnish.$bod);
},

/**
Expand Down

0 comments on commit 94ed5f9

Please sign in to comment.