Skip to content

Commit

Permalink
DOC Make 4.12 changelog more explicit
Browse files Browse the repository at this point in the history
Also fix various minor issues
  • Loading branch information
GuySartorelli committed Nov 15, 2022
1 parent a7097aa commit 784126e
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 10 deletions.
72 changes: 66 additions & 6 deletions en/04_Changelogs/4.12.0.md
Expand Up @@ -58,7 +58,67 @@ jQuery has made some breaking behavioural changes over time. If you are experien

The only change to behaviour we've had to make to accommodate jQuery's breaking changes was with entwine's `onadd` and `onmatch` handlers. jQuery has made substantial changes to its internal functionality, especially in regards to how it adds elements to the DOM, so we had to change with it. Entwine used to change jQuery's internal functionality to fire events synchronously when adding elements to the DOM. It now uses a `MutationObserver` to detect elements being added to the DOM, which means the events are fired asynchronously.

This should only affect your project in the unlikely scenario that you are adding elements to the DOM, then immediately performing some action that relies on something having happened in the `onadd` or `onmatch` handler for those elements. Across all of the core and supported modules we only found one instance of this occurring.
This should only affect your project in the unlikely scenario that you are adding elements to the DOM, then immediately performing some action that relies on something having happened in the `onadd` or `onmatch` handler for those elements. Across all of the core and supported modules we only found one instance of this occurring. If you do have a scenario like this, you could defer the action like so:

**Before:**
```js
$('.some-class').entwine({
// Initialise something in the onmatch or onadd handler
onmatch: function() {
this.data('some-data', 'some-value');
}
});
$('.some-other-class').entwine({
// Add an instance of the above element into the DOM and then try to use the initialised data
onclick: function() {
this.parent(parentSelector).append('<div class="some-class"></div>');
// Expects the data to have been set in onmatch instantly because the event used to be synchronous
const initiliasedData = this.siblings('.some-class').data('some-data');
console.log(initiliasedData); // this will almost certainly print "undefined" to the console, because the MutationObserver event hasn't fired yet
}
});
```

**After:**
```js
$('.some-class').entwine({
// Add an entwine property to defer initialisation events
DeferredInitilisationCallback: null,
// Add an entwine property to indicate whether this element has been initialised
IsInitialised: false,
// Initialise something in the onmatch or onadd handler
onmatch: function() {
this.data('some-data', 'some-value');
this.setIsInitialised(true);
// If some action was deferred, perform that action now
const deferredCallback = this.getDeferredInitilisationCallback();
if (typeof deferredCallback === 'function') {
deferredCallback();
this.setDeferredInitilisationCallback(null);
}
}
});
// Add an instance of the above element into the DOM and then try to use the initialised data
$('.some-other-class').entwine({
onclick: function() {
this.parent(parentSelector).append('<div class="some-class"></div>');
const newElement = this.siblings('.some-class');
// Check if the element has been initialised before performing the action
if (newElement.getIsInitialised()) {
const initiliasedData = newElement.data('some-data');
console.log(initiliasedData); // this will almost never be reached but you might get a situation where the event fires immediately, so it pays to be safe
} else {
// Defer the action until the element has been initialised
newElement.setDeferredInitilisationCallback(function() {
const initiliasedData = newElement.data('some-data');
console.log(initiliasedData); // this will print "some-data" to the console, because it will be called after initialisation has finished
});
}
}
});
```

Note that if you are not trying to use the initialised data/functionality _immediately_ after adding the element to the DOM, this kind of change is not necessary (e.g. click event handlers which rely on _the element the user is clicking_ having been initialised do not need to defer their actions like this, because the user is extremely unlikely to click the element in the time it takes for the `MutationObserver` to fire its events). It is very much exclusive to scenarios where code which adds or replaces elements in the DOM then immediately expects some initialisation to have occurred.

### Search multiple `searchable_fields` by default {#general-search-field}

Expand All @@ -84,7 +144,7 @@ There is also additional configuration, such as which `SearchFilter` it uses ([P

### Samesite attribute on cookies {#cookies-samesite}

The `samesite` attribute is now set on all cookies. To avoid backward compatability issues, the `Lax` value has been set by default, but we recommend reviewing the requirements of your project and setting an appropriate value.
The `samesite` attribute is now set on all cookies. To avoid backward compatibility issues, the `Lax` value has been set by default, but we recommend reviewing the requirements of your project and setting an appropriate value.

The default value can be set for all cookies (except for the session cookie) in yaml configuration like so:

Expand All @@ -111,7 +171,7 @@ For more information about the `samesite` attribute check out https://developer.
A security enhancement to `UserForm` has been made to protect files uploaded using `UserDefinedForm` from unauthorised access by content authors who do not have access to the submitted files folder.
If a content author with access to the UserForm page does not have sufficient *can view* rights on submitted files, they will see the message "Insufficient rights to view the file" and will not be able to access the file.

If you want to retain the previous behaviour and automatically grant content authors access to view submitted file, you can apply the following extension to your project.
If you want to retain the previous behaviour and automatically grant content authors access to view submitted files, you can apply the following extension to your project.

**app/src/extensions/MyFileExtension.php**

Expand Down Expand Up @@ -160,18 +220,18 @@ The `silverstripe/admin` module has a new [CMSEditLinkExtension](api:SilverStrip

This allows you to share `DataObject` edit links directly with others. This extension is also used to facilitate CMS preview of `DataObject` records

See [managing records](/developer_guides/model/data_model_and_orm/managing_records/) for a detailed explanation of this extension.
See [managing records](/developer_guides/model/managing_records/) for a detailed explanation of this extension.

### Assets API formalisation and deprecations {#assets-api-formalisation-deprecation}

In the [Silverstripe CMS 4.4 release](4.4.0/#optional-migration-tasks-overview), many aspects of the `silverstripe/assets` module were refactored to support permanent links.

Many new abstractions were created in the process. However, those new abstraction were marked as `@internal` and were not covered by Silverstripe CMS's semantic versioning commitment. Multiple file migration tasks were also added in that releases.
Many new abstractions were created in the process. However, those new abstractions were marked as `@internal` and were not covered by Silverstripe CMS's semantic versioning commitment. Multiple file migration tasks were also added in that release.

With Silverstripe CMS 5 on the horizon, it is an opportune time to formalise some of those abstractions and to deprecate those migration tasks.

The following classes and methods are now officially part of the Silverstripe CMS API:
- [`SilverStripe\Assets\FilenameParsingFileIDHelper`](api:SilverStripe\Assets\FilenameParsingF\ileIDHelper)
- [`SilverStripe\Assets\FilenameParsingFileIDHelper`](api:SilverStripe\Assets\FilenameParsing\FileIDHelper)
- [`SilverStripe\Assets\FilenameParsing\FileIDHelperResolutionStrategy`](api:SilverStripe\Assets\FilenameParsing\FileIDHelperResolutionStrategy)
- [`SilverStripe\Assets\FilenameParsing\FileResolutionStrategy`](api:SilverStripe\Assets\FilenameParsing\FileResolutionStrategy)
- [`SilverStripe\Assets\FilenameParsing\HashFileIDHelper`](api:SilverStripe\Assets\FilenameParsing\HashFileIDHelper)
Expand Down
68 changes: 64 additions & 4 deletions en/04_Changelogs/beta/4.12.0-beta1.md
Expand Up @@ -133,7 +133,67 @@ jQuery has made some breaking behavioural changes over time. If you are experien

The only change to behaviour we've had to make to accommodate jQuery's breaking changes was with entwine's `onadd` and `onmatch` handlers. jQuery has made substantial changes to its internal functionality, especially in regards to how it adds elements to the DOM, so we had to change with it. Entwine used to change jQuery's internal functionality to fire events synchronously when adding elements to the DOM. It now uses a `MutationObserver` to detect elements being added to the DOM, which means the events are fired asynchronously.

This should only affect your project in the unlikely scenario that you are adding elements to the DOM, then immediately performing some action that relies on something having happened in the `onadd` or `onmatch` handler for those elements. Across all of the core and supported modules we only found one instance of this occurring.
This should only affect your project in the unlikely scenario that you are adding elements to the DOM, then immediately performing some action that relies on something having happened in the `onadd` or `onmatch` handler for those elements. Across all of the core and supported modules we only found one instance of this occurring. If you do have a scenario like this, you could defer the action like so:

**Before:**
```js
$('.some-class').entwine({
// Initialise something in the onmatch or onadd handler
onmatch: function() {
this.data('some-data', 'some-value');
}
});
$('.some-other-class').entwine({
// Add an instance of the above element into the DOM and then try to use the initialised data
onclick: function() {
this.parent(parentSelector).append('<div class="some-class"></div>');
// Expects the data to have been set in onmatch instantly because the event used to be synchronous
const initiliasedData = this.siblings('.some-class').data('some-data');
console.log(initiliasedData); // this will almost certainly print "undefined" to the console, because the MutationObserver event hasn't fired yet
}
});
```

**After:**
```js
$('.some-class').entwine({
// Add an entwine property to defer initialisation events
DeferredInitilisationCallback: null,
// Add an entwine property to indicate whether this element has been initialised
IsInitialised: false,
// Initialise something in the onmatch or onadd handler
onmatch: function() {
this.data('some-data', 'some-value');
this.setIsInitialised(true);
// If some action was deferred, perform that action now
const deferredCallback = this.getDeferredInitilisationCallback();
if (typeof deferredCallback === 'function') {
deferredCallback();
this.setDeferredInitilisationCallback(null);
}
}
});
// Add an instance of the above element into the DOM and then try to use the initialised data
$('.some-other-class').entwine({
onclick: function() {
this.parent(parentSelector).append('<div class="some-class"></div>');
const newElement = this.siblings('.some-class');
// Check if the element has been initialised before performing the action
if (newElement.getIsInitialised()) {
const initiliasedData = newElement.data('some-data');
console.log(initiliasedData); // this will almost never be reached but you might get a situation where the event fires immediately, so it pays to be safe
} else {
// Defer the action until the element has been initialised
newElement.setDeferredInitilisationCallback(function() {
const initiliasedData = newElement.data('some-data');
console.log(initiliasedData); // this will print "some-data" to the console, because it will be called after initialisation has finished
});
}
}
});
```

Note that if you are not trying to use the initialised data/functionality _immediately_ after adding the element to the DOM, this kind of change is not necessary (e.g. click event handlers which rely on _the element the user is clicking_ having been initialised do not need to defer their actions like this, because the user is extremely unlikely to click the element in the time it takes for the `MutationObserver` to fire its events). It is very much exclusive to scenarios where code which adds or replaces elements in the DOM then immediately expects some initialisation to have occurred.

### Search multiple `searchable_fields` by default {#general-search-field}

Expand Down Expand Up @@ -235,18 +295,18 @@ The `silverstripe/admin` module has a new [CMSEditLinkExtension](api:SilverStrip

This allows you to share `DataObject` edit links directly with others. This extension is also used to facilitate CMS preview of `DataObject` records

See [managing records](/developer_guides/model/data_model_and_orm/managing_records/) for a detailed explanation of this extension.
See [managing records](/developer_guides/model/managing_records/) for a detailed explanation of this extension.

### Assets API formalisation and deprecations {#assets-api-formalisation-deprecation}

In the [Silverstripe CMS 4.4 release](4.4.0/#optional-migration-tasks-overview), many aspects of the `silverstripe/assets` module were refactored to support permanent links.

Many new abstractions were created in the process. However, those new abstractions were marked as `@internal` and were not covered by Silverstripe CMS's semantic versioning commitment. Multiple file migration tasks were also added in that releases.
Many new abstractions were created in the process. However, those new abstractions were marked as `@internal` and were not covered by Silverstripe CMS's semantic versioning commitment. Multiple file migration tasks were also added in that release.

With Silverstripe CMS 5 on the horizon, it is an opportune time to formalise some of those abstractions and to deprecate those migration tasks.

The following classes and methods are now officially part of the Silverstripe CMS API:
- [`SilverStripe\Assets\FilenameParsingFileIDHelper`](api:SilverStripe\Assets\FilenameParsingF\ileIDHelper)
- [`SilverStripe\Assets\FilenameParsingFileIDHelper`](api:SilverStripe\Assets\FilenameParsing\FileIDHelper)
- [`SilverStripe\Assets\FilenameParsing\FileIDHelperResolutionStrategy`](api:SilverStripe\Assets\FilenameParsing\FileIDHelperResolutionStrategy)
- [`SilverStripe\Assets\FilenameParsing\FileResolutionStrategy`](api:SilverStripe\Assets\FilenameParsing\FileResolutionStrategy)
- [`SilverStripe\Assets\FilenameParsing\HashFileIDHelper`](api:SilverStripe\Assets\FilenameParsing\HashFileIDHelper)
Expand Down

0 comments on commit 784126e

Please sign in to comment.