]> git.ipfire.org Git - thirdparty/bootstrap.git/commitdiff
Add js-docs shortcode to ensure consistency between doc and js code (#38316)
authorHannah Issermann <hannah.issermann@orange.com>
Mon, 27 Mar 2023 09:10:25 +0000 (11:10 +0200)
committerGitHub <noreply@github.com>
Mon, 27 Mar 2023 09:10:25 +0000 (12:10 +0300)
Co-authored-by: XhmikosR <xhmikosr@gmail.com>
js/src/util/sanitizer.js
site/assets/js/snippets.js
site/content/docs/5.3/components/alerts.md
site/content/docs/5.3/components/modal.md
site/content/docs/5.3/components/toasts.md
site/content/docs/5.3/getting-started/javascript.md
site/layouts/shortcodes/js-docs.html [new file with mode: 0644]

index af846a21e897e31da61f5d4130d0517e59e2da34..5a07a67c1a827ff328e27dfbc635ac2266b0f271 100644 (file)
@@ -16,8 +16,6 @@ const uriAttributes = new Set([
   'xlink:href'
 ])
 
-const ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i
-
 /**
  * A pattern that recognizes a commonly useful subset of URLs that are safe.
  *
@@ -48,6 +46,9 @@ const allowedAttribute = (attribute, allowedAttributeList) => {
     .some(regex => regex.test(attributeName))
 }
 
+// js-docs-start allow-list
+const ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i
+
 export const DefaultAllowlist = {
   // Global attributes allowed on any supplied element below.
   '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],
@@ -81,6 +82,7 @@ export const DefaultAllowlist = {
   u: [],
   ul: []
 }
+// js-docs-end allow-list
 
 export function sanitizeHtml(unsafeHtml, allowList, sanitizeFunction) {
   if (!unsafeHtml.length) {
index 95fce2da85116d0780baf469cf92c527a1d27df9..66c7a005ce2128c427271b05914777d62b777d65 100644 (file)
@@ -60,6 +60,7 @@
     })
 
   // Instantiate all toasts in docs pages only
+  // js-docs-start live-toast
   const toastTrigger = document.getElementById('liveToastBtn')
   const toastLiveExample = document.getElementById('liveToast')
 
       toastBootstrap.show()
     })
   }
+  // js-docs-end live-toast
 
   // -------------------------------
   // Alerts
   // -------------------------------
-  // Used in 'Show live toast' example in docs or StackBlitz
-  const alertPlaceholder = document.getElementById('liveAlertPlaceholder')
-  const alertTrigger = document.getElementById('liveAlertBtn')
+  // Used in 'Show live alert' example in docs or StackBlitz
 
+  // js-docs-start live-alert
+  const alertPlaceholder = document.getElementById('liveAlertPlaceholder')
   const appendAlert = (message, type) => {
     const wrapper = document.createElement('div')
     wrapper.innerHTML = [
     alertPlaceholder.append(wrapper)
   }
 
+  const alertTrigger = document.getElementById('liveAlertBtn')
   if (alertTrigger) {
     alertTrigger.addEventListener('click', () => {
       appendAlert('Nice, you triggered this alert message!', 'success')
     })
   }
+  // js-docs-end live-alert
 
   // --------
   // Carousels
   // Modal
   // -------------------------------
   // Modal 'Varying modal content' example in docs and StackBlitz
+  // js-docs-start varying-modal-content
   const exampleModal = document.getElementById('exampleModal')
   if (exampleModal) {
     exampleModal.addEventListener('show.bs.modal', event => {
       const button = event.relatedTarget
       // Extract info from data-bs-* attributes
       const recipient = button.getAttribute('data-bs-whatever')
+      // If necessary, you could initiate an Ajax request here
+      // and then do the updating in a callback.
 
       // Update the modal's content.
       const modalTitle = exampleModal.querySelector('.modal-title')
       modalBodyInput.value = recipient
     })
   }
+  // js-docs-end varying-modal-content
 
   // -------------------------------
   // Offcanvas
index 7ea5b9b42810ebb4439d95c16e8428e71869cc7f..b6e78ea4285ee1d47233229a53db374d3ed88965 100644 (file)
@@ -38,28 +38,7 @@ Click the button below to show an alert (hidden with inline styles to start), th
 
 We use the following JavaScript to trigger our live alert demo:
 
-```js
-const alertPlaceholder = document.getElementById('liveAlertPlaceholder')
-
-const alert = (message, type) => {
-  const wrapper = document.createElement('div')
-  wrapper.innerHTML = [
-    `<div class="alert alert-${type} alert-dismissible" role="alert">`,
-    `   <div>${message}</div>`,
-    '   <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>',
-    '</div>'
-  ].join('')
-
-  alertPlaceholder.append(wrapper)
-}
-
-const alertTrigger = document.getElementById('liveAlertBtn')
-if (alertTrigger) {
-  alertTrigger.addEventListener('click', () => {
-    alert('Nice, you triggered this alert message!', 'success')
-  })
-}
-```
+{{< js-docs name="live-alert" file="site/assets/js/snippets.js" >}}
 
 ### Link color
 
index f556ed9f825d569eb158c39f434daef74dac7d44..55272b33f6c24a01cfa6daf8a2246995a89dd5c2 100644 (file)
@@ -481,24 +481,7 @@ Below is a live demo followed by example HTML and JavaScript. For more informati
 </div>
 {{< /example >}}
 
-```js
-const exampleModal = document.getElementById('exampleModal')
-exampleModal.addEventListener('show.bs.modal', event => {
-  // Button that triggered the modal
-  const button = event.relatedTarget
-  // Extract info from data-bs-* attributes
-  const recipient = button.getAttribute('data-bs-whatever')
-  // If necessary, you could initiate an Ajax request here
-  // and then do the updating in a callback.
-  //
-  // Update the modal's content.
-  const modalTitle = exampleModal.querySelector('.modal-title')
-  const modalBodyInput = exampleModal.querySelector('.modal-body input')
-
-  modalTitle.textContent = `New message to ${recipient}`
-  modalBodyInput.value = recipient
-})
-```
+{{< js-docs name="varying-modal-content" file="site/assets/js/snippets.js" >}}
 
 ### Toggle between modals
 
index d882fc04b521ddcaf1ac5a6f1438cf152e71c380..a7d1cb7130e23cd48a6414b6bde81c28d9a3c27d 100644 (file)
@@ -87,17 +87,7 @@ Click the button below to show a toast (positioned with our utilities in the low
 
 We use the following JavaScript to trigger our live toast demo:
 
-```js
-const toastTrigger = document.getElementById('liveToastBtn')
-const toastLiveExample = document.getElementById('liveToast')
-
-if (toastTrigger) {
-  const toastBootstrap = bootstrap.Toast.getOrCreateInstance(toastLiveExample)
-  toastTrigger.addEventListener('click', () => {
-    toastBootstrap.show()
-  })
-}
-```
+{{< js-docs name="live-toast" file="site/assets/js/snippets.js" >}}
 
 ### Translucent
 
index 827cd2199e5a25fa576d41fa16590410627580ef..739e9ef63ef30c04cd76a29c09b587238896a447 100644 (file)
@@ -231,42 +231,7 @@ Tooltips and Popovers use our built-in sanitizer to sanitize options which accep
 
 The default `allowList` value is the following:
 
-```js
-const ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i
-const DefaultAllowlist = {
-  // Global attributes allowed on any supplied element below.
-  '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],
-  a: ['target', 'href', 'title', 'rel'],
-  area: [],
-  b: [],
-  br: [],
-  col: [],
-  code: [],
-  div: [],
-  em: [],
-  hr: [],
-  h1: [],
-  h2: [],
-  h3: [],
-  h4: [],
-  h5: [],
-  h6: [],
-  i: [],
-  img: ['src', 'srcset', 'alt', 'title', 'width', 'height'],
-  li: [],
-  ol: [],
-  p: [],
-  pre: [],
-  s: [],
-  small: [],
-  span: [],
-  sub: [],
-  sup: [],
-  strong: [],
-  u: [],
-  ul: []
-}
-```
+{{< js-docs name="allow-list" file="js/src/util/sanitizer.js" >}}
 
 If you want to add new values to this default `allowList` you can do the following:
 
diff --git a/site/layouts/shortcodes/js-docs.html b/site/layouts/shortcodes/js-docs.html
new file mode 100644 (file)
index 0000000..1a479db
--- /dev/null
@@ -0,0 +1,37 @@
+{{- /*
+  Usage: `js-docs name="name" file="file/_location.js`
+
+  Prints everything between `// js-docs-start "name"` and `// js-docs-end "name"`
+  comments in the docs.
+*/ -}}
+
+{{- $name := .Get "name" -}}
+{{- $file := .Get "file" -}}
+
+{{- /* If any parameters are missing, print an error and exit */ -}}
+{{- if or (not $name) (not $file) -}}
+  {{- errorf "%s: %q: Missing required parameters! Got: name=%q file=%q!" .Position .Name $name $file -}}
+{{- else -}}
+  {{- $capture_start := printf "// js-docs-start %s\n" $name -}}
+  {{- $capture_end := printf "// js-docs-end %s" $name -}}
+  {{- $regex := printf `%s((?:.|\n)*)%s` $capture_start $capture_end -}}
+
+  {{- $match := findRE $regex (readFile $file) -}}
+  {{- $match = index $match 0 -}}
+
+  {{- if not $match -}}
+    {{- errorf "%s: %q: Got no matches for name=%q in file=%q!" .Position .Name $name $file -}}
+  {{- end -}}
+
+  {{- $match = replace $match $capture_start "" -}}
+  {{- $match = replace $match $capture_end "" -}}
+
+  <div class="bd-example-snippet bd-code-snippet">
+    <div class="bd-clipboard">
+      <button type="button" class="btn-clipboard" title="Copy to clipboard">
+        <svg class="bi" aria-hidden="true"><use xlink:href="#clipboard"></use></svg>
+      </button>
+    </div>
+    {{- highlight $match "js" "" -}}
+  </div>
+{{- end -}}