From 2f2ece2bc9a0c303a6ad8b97e214d6f44140236a Mon Sep 17 00:00:00 2001 From: Hamish Willee Date: Mon, 22 Jul 2024 13:53:17 +1000 Subject: [PATCH] CSSPageDescriptors and related fixes --- .../en-us/web/api/csspagedescriptors/index.md | 153 ++++++++++++++++++ files/en-us/web/api/csspagerule/index.md | 60 ++++++- .../en-us/web/api/csspagerule/style/index.md | 96 +++++++++-- files/jsondata/GroupData.json | 1 + 4 files changed, 293 insertions(+), 17 deletions(-) create mode 100644 files/en-us/web/api/csspagedescriptors/index.md diff --git a/files/en-us/web/api/csspagedescriptors/index.md b/files/en-us/web/api/csspagedescriptors/index.md new file mode 100644 index 000000000000000..f7ff8cd2ff62997 --- /dev/null +++ b/files/en-us/web/api/csspagedescriptors/index.md @@ -0,0 +1,153 @@ +--- +title: CSSPageDescriptors +slug: Web/API/CSSPageDescriptors +page-type: web-api-interface +browser-compat: api.CSSPageDescriptors +--- + +{{APIRef("CSSOM")}} + +The **`CSSPageDescriptors`** interface represents a CSS declaration block for an {{cssxref("@page")}} rule. + +The interface exposes style information and various style-related methods and properties for the page. +Each multi-word property has versions in camel- and snake-case, following both CSS and Web API naming conventions. + +A `CSSPageDescriptors` object is accessed through the {{DOMxRef("CSSPageRule.style", "style")}} property of the `CSSPageRule` interface, which can in turn be found using the {{DOMxRef("CSSStyleSheet")}} API. + +{{InheritanceDiagram}} + +## Attributes + +_This interface also inherits properties of its parent, {{domxref("CSSStyleDeclaration")}}._ + +- `margin` + - : A string representing the `margin` property of the corresponding `@page` rule. +- `marginTop` + - : A string representing the `margin-top` property of the corresponding `@page` rule. +- `marginRight` + - : A string representing the `margin-right` property of the corresponding `@page` rule. +- `marginBottom` + - : A string representing the `margin-bottom` property of the corresponding `@page` rule. +- `marginLeft` + - : A string representing the `margin-left` property of the corresponding `@page` rule. +- `margin-top` + - : A string representing the `margin-top` property of the corresponding `@page` rule. +- `margin-right` + - : A string representing the `margin-right` property of the corresponding `@page` rule. +- `margin-bottom` + - : A string representing the `margin-bottom` property of the corresponding `@page` rule. +- `margin-left` + - : A string representing the `margin-left` property of the corresponding `@page` rule. +- `pageOrientation` + - : A string representing the `page-orientation` property of the corresponding `@page` rule. +- `page-orientation` + - : A string representing the `page-orientation` property of the corresponding `@page` rule. +- `size` + - : A string representing the `size` property of the corresponding `@page` rule. + +## Instance methods + +_This interface inherits the methods of its parent, {{domxref("CSSStyleDeclaration")}}._ + +## Examples + +### Inspecting a page rule + +This example gets the `CSSPageDescriptors` for a {{cssxref("@page")}} rule, if the object is supported on the browser, and then logs its properties. + +```html hidden +

+```
+
+```js hidden
+const logElement = document.querySelector("#log");
+function log(text) {
+  logElement.innerText = `${logElement.innerText}${text}\n`;
+  logElement.scrollTop = logElement.scrollHeight;
+}
+```
+
+```css hidden
+#log {
+  height: 280px;
+  overflow: scroll;
+  padding: 0.5rem;
+  border: 1px solid black;
+}
+```
+
+#### CSS
+
+Below we define styles for the page using a {{cssxref("@page")}} rule.
+We assign different values for each margin property using the `margin` shorthand, and also specify the `size`.
+We don't set the `page-orientation`.
+This allows us to see how the properties map in the Web API object.
+
+```css
+@page {
+  margin: 1cm 2px 3px 4px;
+  /* page-orientation: upright; */
+  size: A4;
+}
+```
+
+#### JavaScript
+
+First we check if `CSSPageDescriptors` is defined on the global window object, and if not we log that the interface is not supported.
+
+If `CSSPageDescriptors` is supported, we get the document stylesheet at index `1`, and then gets the `cssRules` defined in that stylesheet.
+We need to get this stylesheet because the example is embedded in a separate frame with its own sheet.
+
+We then iterate through the rules defined for the live example and match any that are of type `CSSPageRule`, as these correspond to `@page` rules.
+For the matching objects we then log the `style` and all its values.
+
+```js
+if (typeof window.CSSPageDescriptors === "undefined") {
+  log("CSSPageDescriptors is not supported on this browser.");
+} else {
+  // Get stylesheets for example and then get its cssRules
+  const myRules = document.styleSheets[1].cssRules;
+  for (let i = 0; i < myRules.length; i++) {
+    if (myRules[i] instanceof CSSPageRule) {
+      log(`${myRules[i].style}`);
+      log(`margin: ${myRules[i].style.margin}`);
+
+      // Access properties using CamelCase properties
+      log(`marginTop: ${myRules[i].style.marginTop}`);
+      log(`marginRight: ${myRules[i].style.marginRight}`);
+      log(`marginBottom: ${myRules[i].style.marginBottom}`);
+      log(`marginLeft: ${myRules[i].style.marginLeft}`);
+      log(`pageOrientation: ${myRules[i].style.pageOrientation}`);
+
+      // Access properties using snake-case properties
+      log(`margin-top: ${myRules[i].style["margin-top"]}`);
+      log(`margin-right: ${myRules[i].style["margin-right"]}`);
+      log(`margin-left: ${myRules[i].style["margin-left"]}`);
+      log(`margin-bottom: ${myRules[i].style["margin-bottom"]}`);
+      log(`page-orientation: ${myRules[i].style["page-orientation"]}`);
+
+      log(`size: ${myRules[i].style.size}`);
+
+      // Log the original CSS text using inherited property: cssText
+      log(`cssText: ${myRules[i].style.cssText}`);
+      log("\n");
+    }
+  }
+}
+```
+
+#### Results
+
+The results are shown below.
+Note that the `style` object displayed at the top of the log should be a `CSSPageDescriptors` to match the current specification, but may be a `CSSStyleDeclaration` in some browsers.
+Note also that the corresponding values for properties in camel- and snake-case match each other and the `@page` declaration, and that `page-orientation` is the empty string `""` because it is not defined in `@page`.
+
+{{EmbedLiveSample("Inspecting a page rule", "100%", "350px")}}
+
+## Specifications
+
+{{Specifications}}
+
+## Browser compatibility
+
+{{Compat}}
diff --git a/files/en-us/web/api/csspagerule/index.md b/files/en-us/web/api/csspagerule/index.md
index 0ad4d4338204748..1e7f6e357931070 100644
--- a/files/en-us/web/api/csspagerule/index.md
+++ b/files/en-us/web/api/csspagerule/index.md
@@ -26,7 +26,34 @@ _Inherits methods from its ancestors {{domxref("CSSGroupingRule")}} and {{domxre
 
 ## Examples
 
-The stylesheet includes a single {{cssxref("@page")}} rule, therefore the first (and only) rule returned will be a `CSSPageRule`.
+### Filtering for page rules
+
+This example shows how you can find `CSSPageRule` objects for {{cssxref("@page")}} rules loaded by the document.
+
+```html hidden
+

+```
+
+```js hidden
+const logElement = document.querySelector("#log");
+function log(text) {
+  logElement.innerText = `${logElement.innerText}${text}\n`;
+  logElement.scrollTop = logElement.scrollHeight;
+}
+```
+
+```css hidden
+#log {
+  height: 220px;
+  overflow: scroll;
+  padding: 0.5rem;
+  border: 1px solid black;
+}
+```
+
+#### CSS
+
+Below we define styles for the page using a {{cssxref("@page")}} rule.
 
 ```css
 @page {
@@ -34,11 +61,38 @@ The stylesheet includes a single {{cssxref("@page")}} rule, therefore the first
 }
 ```
 
+#### JavaScript
+
+The code iterates through all the sheets in the document, and through all the `cssRules` in each sheet, logging the sheet number, the number of rules, and the type of each rule object.
+We then detect `CSSPageRule` objects using their type (doing nothing with the information).
+
 ```js
-let myRules = document.styleSheets[0].cssRules;
-console.log(myRules[0]); // a CSSPageRule
+for (
+  let sheetCount = 0;
+  sheetCount < document.styleSheets.length;
+  sheetCount++
+) {
+  const sheet = document.styleSheets[sheetCount].cssRules;
+  log(`styleSheet: ${sheetCount}`);
+
+  const myRules = document.styleSheets[sheetCount].cssRules;
+  log(`rules: ${myRules.length}`);
+  for (let i = 0; i < myRules.length; i++) {
+    log(`rule: ${myRules[i]}`);
+    if (myRules[i] instanceof CSSPageRule) {
+      //... Do something with CSSPageRule
+    }
+  }
+}
 ```
 
+#### Results
+
+The results are shown below.
+As you can see there are a two sheets, corresponding to this main document and the example code frame, and each have a number of rules, only one of which is our `CSSPageRule`.
+
+{{EmbedLiveSample("Filtering for page rules", "100%", "300px")}}
+
 ## Specifications
 
 {{Specifications}}
diff --git a/files/en-us/web/api/csspagerule/style/index.md b/files/en-us/web/api/csspagerule/style/index.md
index d4463b04daa32d2..2e89397ed3e062c 100644
--- a/files/en-us/web/api/csspagerule/style/index.md
+++ b/files/en-us/web/api/csspagerule/style/index.md
@@ -8,36 +8,104 @@ browser-compat: api.CSSPageRule.style
 
 {{APIRef("CSSOM")}}
 
-The **`style`** read-only property of the {{domxref("CSSPageRule")}} interface returns a {{domxref("CSSStyleDeclaration")}} object. This represents an object that is a [CSS declaration block](/en-US/docs/Web/API/CSS_Object_Model/CSS_Declaration_Block), and exposes style information and various style-related methods and properties.
+The **`style`** read-only property of the {{domxref("CSSPageRule")}} interface returns a {{domxref("CSSPageDescriptors")}} object.
+This represents a [CSS declaration block](/en-US/docs/Web/API/CSS_Object_Model/CSS_Declaration_Block) for a CSS {{cssxref("@page")}} rule, and exposes style information and various style-related methods and properties for the page.
 
 ## Value
 
-A {{domxref("CSSStyleDeclaration")}} object, which represents a [CSS declaration block](/en-US/docs/Web/API/CSS_Object_Model/CSS_Declaration_Block) with the following properties:
+A {{domxref("CSSPageDescriptors")}} object with properties that match the associated {{cssxref("@page")}} rule.
 
-- computed flag
-  - : Unset.
-- declarations
-  - : The declared declarations in the rule, in the order they were specified, shorthand properties expanded to longhands.
-- parent CSS rule
-  - : The context object, which is an alias for [this](https://heycam.github.io/webidl/#this).
-- owner node
-  - : Null.
+> **Note:** Earlier versions of the specification defined this property as a {{domxref("CSSStyleDeclaration")}}.
+> Check the compatibility data below for your browser.
 
 ## Examples
 
-The stylesheet includes a {{cssxref("@page")}} rule. Getting a list of rules, then returning the value of the style property will return a {{domxref("CSSStyleDeclaration")}} object.
+### Inspecting a page rule
+
+This example uses the Web API to inspect the content of a {{cssxref("@page")}} rule.
+
+```html hidden
+

+```
+
+```js hidden
+const logElement = document.querySelector("#log");
+function log(text) {
+  logElement.innerText = `${logElement.innerText}${text}\n`;
+  logElement.scrollTop = logElement.scrollHeight;
+}
+```
+
+```css hidden
+#log {
+  height: 230px;
+  overflow: scroll;
+  padding: 0.5rem;
+  border: 1px solid black;
+}
+```
+
+#### CSS
+
+Below we define styles for the page using a {{cssxref("@page")}} rule.
+We assign different values for each margin property using the `margin` shorthand, and also specify the `size`.
+We don't set the `page-orientation`.
+This allows us to see how the properties map in the Web API object.
 
 ```css
 @page {
-  margin: 1cm;
+  margin: 1cm 2px 3px 4px;
+  /* page-orientation: upright; */
+  size: A4;
 }
 ```
 
+#### JavaScript
+
+The code first gets the document stylesheet at index `1`, and then gets the `cssRules` defined in that stylesheet.
+We need to get this stylesheet because the example is embedded in a separate frame with its own sheet (index `0` is the CSS for this page).
+
+```js
+const myRules = document.styleSheets[1].cssRules;
+```
+
+We then iterate through the rules defined for the live example and match any that are of type `CSSPageRule`, as these correspond to `@page` rules.
+For the matching objects we then log the `style` and all its values.
+
 ```js
-let myRules = document.styleSheets[0].cssRules;
-console.log(myRules[0].style); // returns a CSSStyleDeclaration object
+for (let i = 0; i < myRules.length; i++) {
+  if (myRules[i] instanceof CSSPageRule) {
+    log(`${myRules[i].style}`);
+    log(`margin: ${myRules[i].style.margin}`);
+
+    // Access properties using CamelCase properties
+    log(`marginTop: ${myRules[i].style.marginTop}`);
+    log(`marginRight: ${myRules[i].style.marginRight}`);
+    log(`marginBottom: ${myRules[i].style.marginBottom}`);
+    log(`marginLeft: ${myRules[i].style.marginLeft}`);
+    log(`pageOrientation: ${myRules[i].style.pageOrientation}`);
+
+    // Access properties using snake-case properties
+    log(`margin-top: ${myRules[i].style["margin-top"]}`);
+    log(`margin-right: ${myRules[i].style["margin-right"]}`);
+    log(`margin-left: ${myRules[i].style["margin-left"]}`);
+    log(`margin-bottom: ${myRules[i].style["margin-bottom"]}`);
+    log(`page-orientation: ${myRules[i].style["page-orientation"]}`);
+
+    log(`size: ${myRules[i].style.size}`);
+    log("\n");
+  }
+}
 ```
 
+#### Results
+
+The results are shown below.
+Note that the object should be a `CSSPageDescriptors` to match the current specification, but may be a `CSSStyleDeclaration` in some browsers.
+Note also that the corresponding values for properties in camel- and snake-case match each other and the `@page` declaration, and that `page-orientation` is the empty string `""` because it is not defined in `@page`.
+
+{{EmbedLiveSample("Inspecting a page rule", "100%", "300px")}}
+
 ## Specifications
 
 {{Specifications}}
diff --git a/files/jsondata/GroupData.json b/files/jsondata/GroupData.json
index c17cc36d46709b6..1a4a96197193f5f 100644
--- a/files/jsondata/GroupData.json
+++ b/files/jsondata/GroupData.json
@@ -325,6 +325,7 @@
         "CSSMediaRule",
         "CSSNamespaceRule",
         "CSSPageRule",
+        "CSSPageDescriptors",
         "CSSFontFeatureValuesRule",
         "CSSFontPaletteValuesRule",
         "CSSPropertyRule",