autumnnote 1.11.0 → 1.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/sitemap.xml CHANGED
@@ -2,16 +2,19 @@
2
2
  <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
3
3
  <url>
4
4
  <loc>https://autumn.konexforge.com/</loc>
5
+ <lastmod>2026-07-07</lastmod>
5
6
  <changefreq>monthly</changefreq>
6
7
  <priority>1.0</priority>
7
8
  </url>
8
9
  <url>
9
10
  <loc>https://autumn.konexforge.com/docs.html</loc>
11
+ <lastmod>2026-07-07</lastmod>
10
12
  <changefreq>monthly</changefreq>
11
13
  <priority>0.9</priority>
12
14
  </url>
13
15
  <url>
14
16
  <loc>https://autumn.konexforge.com/playground.html</loc>
17
+ <lastmod>2026-07-07</lastmod>
15
18
  <changefreq>monthly</changefreq>
16
19
  <priority>0.7</priority>
17
20
  </url>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "autumnnote",
3
- "version": "1.11.0",
3
+ "version": "1.12.0",
4
4
  "description": "WYSIWYG rich-text editor built with vanilla JavaScript — zero dependencies, no jQuery. Dark mode, @mention, markdown shortcuts, bubble toolbar. React and Vue 3 wrappers included.",
5
5
  "main": "dist/autumnnote.umd.js",
6
6
  "module": "dist/autumnnote.es.js",
@@ -6,13 +6,24 @@
6
6
  */
7
7
 
8
8
  /** Tags that are unconditionally removed from editor content. */
9
- const PROHIBITED_TAGS = ['script', 'style', 'iframe', 'object', 'embed', 'form', 'base'];
9
+ const PROHIBITED_TAGS = ['script', 'style', 'iframe', 'object', 'embed', 'form', 'base', 'template', 'link', 'meta'];
10
10
 
11
11
  /** Tags whose element wrapper is stripped but content (child nodes) is preserved. */
12
12
  const UNWRAP_TAGS = new Set(['button']);
13
13
 
14
14
  /** Attributes whose values must be sanitised as URLs. */
15
- const URL_ATTRS = ['href', 'src', 'action', 'formaction'];
15
+ const URL_ATTRS = ['href', 'src', 'action', 'formaction', 'xlink:href'];
16
+
17
+ /** Inline style properties the editor's own toolbar/table features persist on saved content. */
18
+ const ALLOWED_STYLE_PROPS = new Set([
19
+ 'color', 'background-color', 'font-size', 'line-height',
20
+ 'text-align', 'vertical-align',
21
+ 'width', 'min-width', 'height', 'min-height',
22
+ 'border-width', 'border-style', 'border-color', 'padding',
23
+ ]);
24
+
25
+ /** Value patterns that are never safe regardless of property. */
26
+ const DANGEROUS_STYLE_VALUE_RE = /url\s*\(|expression\s*\(|@import|javascript:|vbscript:|behavior\s*:|-moz-binding/i;
16
27
 
17
28
  /** Trusted hosts for iframe embeds when allowIframes is enabled. */
18
29
  const TRUSTED_IFRAME_HOSTS = new Set([
@@ -70,6 +81,17 @@ export function sanitiseHTML(html, { allowIframes = false } = {}) {
70
81
  el.removeAttribute(attr.name);
71
82
  continue;
72
83
  }
84
+ // Filter the style attribute down to an allowlisted set of safe
85
+ // properties (see ALLOWED_STYLE_PROPS) — not a blanket strip, since
86
+ // the editor's own toolbar/table features persist inline styles
87
+ // (text color/highlight, font size, line height, table alignment/
88
+ // sizing/borders) that must survive sanitisation.
89
+ if (attr.name === 'style') {
90
+ const cleaned = sanitiseStyleValue(attr.value);
91
+ if (cleaned) el.setAttribute('style', cleaned);
92
+ else el.removeAttribute('style');
93
+ continue;
94
+ }
73
95
  // Sanitise URL attributes
74
96
  if (URL_ATTRS.includes(attr.name)) {
75
97
  const val = attr.value.trim();
@@ -113,6 +135,29 @@ export function sanitiseHTML(html, { allowIframes = false } = {}) {
113
135
  return doc.body.innerHTML;
114
136
  }
115
137
 
138
+ /**
139
+ * Filters a style attribute value down to an allowlisted set of CSS
140
+ * properties (ALLOWED_STYLE_PROPS), dropping any declaration whose value
141
+ * contains a dangerous construct — url(), expression(), an "import" rule,
142
+ * javascript:/vbscript:, IE behavior/-moz-binding — regardless of property.
143
+ * @param {string} value
144
+ * @returns {string} The filtered declaration list, or '' if nothing survives.
145
+ */
146
+ function sanitiseStyleValue(value) {
147
+ const kept = [];
148
+ for (const decl of (value || '').split(';')) {
149
+ const idx = decl.indexOf(':');
150
+ if (idx === -1) continue;
151
+ const prop = decl.slice(0, idx).trim().toLowerCase();
152
+ const val = decl.slice(idx + 1).trim();
153
+ if (!prop || !val) continue;
154
+ if (!ALLOWED_STYLE_PROPS.has(prop)) continue;
155
+ if (DANGEROUS_STYLE_VALUE_RE.test(val)) continue;
156
+ kept.push(`${prop}: ${val}`);
157
+ }
158
+ return kept.join('; ');
159
+ }
160
+
116
161
  /**
117
162
  * Returns true if iframe src points to an approved video host.
118
163
  * Relative, protocol-relative and invalid URLs are rejected.
package/src/js/index.js CHANGED
@@ -144,7 +144,7 @@ const AutumnNote = {
144
144
  buttons,
145
145
 
146
146
  /** Library version */
147
- version: '1.11.0',
147
+ version: '1.12.0',
148
148
  };
149
149
 
150
150
  // ---------------------------------------------------------------------------
package/types/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * AutumnNote – TypeScript declarations
3
- * @version 1.11.0
3
+ * @version 1.12.0
4
4
  */
5
5
 
6
6
  // ---------------------------------------------------------------------------