diff --git a/umap/static/umap/js/modules/dompurify.js b/umap/static/umap/js/modules/dompurify.js new file mode 100644 index 00000000..27216bcf --- /dev/null +++ b/umap/static/umap/js/modules/dompurify.js @@ -0,0 +1,12 @@ +import {default as DOMPurifyInitializer} from '../../vendors/dompurify/purify.es.mjs' +import { JSDOM } from 'jsdom' + +console.log(DOMPurifyInitializer) + +export default function getPurify() { + if (typeof window === 'undefined') { + return DOMPurifyInitializer(new JSDOM('').window) + } else { + return DOMPurifyInitializer(window) + } +} diff --git a/umap/static/umap/unittests/utils.js b/umap/static/umap/unittests/utils.js new file mode 100644 index 00000000..94b309e5 --- /dev/null +++ b/umap/static/umap/unittests/utils.js @@ -0,0 +1,541 @@ +import { describe, it } from 'mocha' +import * as Utils from '../js/modules/utils.js' +import pkg from 'chai' +const { assert } = pkg + +// Export JSDOM to the global namespace, to be able to check for its presence +// in the actual implementation. Avoiding monkeypatching the implementations here. +import { JSDOM } from 'jsdom' +global.JSDOM = JSDOM + +describe('Utils', function () { + describe('#toHTML()', function () { + it('should handle title', function () { + assert.equal(Utils.toHTML('# A title'), '

A title

') + }) + + it('should handle title in the middle of the content', function () { + assert.equal( + Utils.toHTML('A phrase\n## A title'), + 'A phrase
\n

A title

' + ) + }) + + it('should handle hr', function () { + assert.equal(Utils.toHTML('---'), '
') + }) + + it('should handle bold', function () { + assert.equal(Utils.toHTML('Some **bold**'), 'Some bold') + }) + + it('should handle italic', function () { + assert.equal(Utils.toHTML('Some *italic*'), 'Some italic') + }) + + it('should handle newlines', function () { + assert.equal(Utils.toHTML('two\nlines'), 'two
\nlines') + }) + + it('should not change last newline', function () { + assert.equal(Utils.toHTML('two\nlines\n'), 'two
\nlines\n') + }) + + it('should handle two successive newlines', function () { + assert.equal(Utils.toHTML('two\n\nlines\n'), 'two
\n
\nlines\n') + }) + + it('should handle links without formatting', function () { + assert.equal( + Utils.toHTML('A simple http://osm.org link'), + 'A simple http://osm.org link' + ) + }) + + it('should handle simple link in title', function () { + assert.equal( + Utils.toHTML('# http://osm.org'), + '

http://osm.org

' + ) + }) + + it('should handle links with url parameter', function () { + assert.equal( + Utils.toHTML('A simple https://osm.org/?url=https%3A//anotherurl.com link'), + 'A simple https://osm.org/?url=https%3A//anotherurl.com link' + ) + }) + + it('should handle simple link inside parenthesis', function () { + assert.equal( + Utils.toHTML('A simple link (http://osm.org)'), + 'A simple link (http://osm.org)' + ) + }) + + it('should handle simple link with formatting', function () { + assert.equal( + Utils.toHTML('A simple [[http://osm.org]] link'), + 'A simple http://osm.org link' + ) + }) + + it('should handle simple link with formatting and content', function () { + assert.equal( + Utils.toHTML('A simple [[http://osm.org|link]]'), + 'A simple link' + ) + }) + + it('should handle simple link followed by a carriage return', function () { + assert.equal( + Utils.toHTML('A simple link http://osm.org\nAnother line'), + 'A simple link http://osm.org
\nAnother line' + ) + }) + + it('should handle target option', function () { + assert.equal( + Utils.toHTML('A simple http://osm.org link', { target: 'self' }), + 'A simple http://osm.org link' + ) + }) + + it('should handle image', function () { + assert.equal( + Utils.toHTML('A simple image: {{http://osm.org/pouet.png}}'), + 'A simple image: ' + ) + }) + + it('should handle image without text', function () { + assert.equal( + Utils.toHTML('{{http://osm.org/pouet.png}}'), + '' + ) + }) + + it('should handle image with width', function () { + assert.equal( + Utils.toHTML('A simple image: {{http://osm.org/pouet.png|100}}'), + 'A simple image: ' + ) + }) + + it('should handle iframe', function () { + assert.equal( + Utils.toHTML('A simple iframe: {{{http://osm.org/pouet.html}}}'), + 'A simple iframe:
' + ) + }) + + it('should handle iframe with height', function () { + assert.equal( + Utils.toHTML('A simple iframe: {{{http://osm.org/pouet.html|200}}}'), + 'A simple iframe:
' + ) + }) + + it('should handle iframe with height and width', function () { + assert.equal( + Utils.toHTML('A simple iframe: {{{http://osm.org/pouet.html|200*400}}}'), + 'A simple iframe:
' + ) + }) + + it('should handle iframe with height with px', function () { + assert.equal( + Utils.toHTML('A simple iframe: {{{http://osm.org/pouet.html|200px}}}'), + 'A simple iframe:
' + ) + }) + + it('should handle iframe with url parameter', function () { + assert.equal( + Utils.toHTML( + 'A simple iframe: {{{https://osm.org/?url=https%3A//anotherurl.com}}}' + ), + 'A simple iframe:
' + ) + }) + + it('should handle iframe with height with px', function () { + assert.equal( + Utils.toHTML( + 'A double iframe: {{{https://osm.org/pouet}}}{{{https://osm.org/boudin}}}' + ), + 'A double iframe:
' + ) + }) + + it('http link with http link as parameter as variable', function () { + assert.equal( + Utils.toHTML('A phrase with a [[http://iframeurl.com?to=http://another.com]].'), + 'A phrase with a http://iframeurl.com?to=http://another.com.' + ) + }) + }) + + describe('#escapeHTML', function () { + it('should escape HTML tags', function () { + assert.equal(Utils.escapeHTML(''), '') + }) + + it('should not escape geo: links', function () { + assert.equal(Utils.escapeHTML(''), '') + }) + + it('should not fail with int value', function () { + assert.equal(Utils.escapeHTML(25), '25') + }) + + it('should not fail with null value', function () { + assert.equal(Utils.escapeHTML(null), '') + }) + }) + + describe('#greedyTemplate', function () { + it('should replace simple props', function () { + assert.equal( + Utils.greedyTemplate('A phrase with a {variable}.', { variable: 'thing' }), + 'A phrase with a thing.' + ) + }) + + it('should not fail when missing key', function () { + assert.equal( + Utils.greedyTemplate('A phrase with a {missing}', {}), + 'A phrase with a ' + ) + }) + + it('should process brakets in brakets', function () { + assert.equal( + Utils.greedyTemplate('A phrase with a {{{variable}}}.', { variable: 'value' }), + 'A phrase with a {{value}}.' + ) + }) + + it('should not process http links', function () { + assert.equal( + Utils.greedyTemplate('A phrase with a {{{http://iframeurl.com}}}.', { + 'http://iframeurl.com': 'value', + }), + 'A phrase with a {{{http://iframeurl.com}}}.' + ) + }) + + it('should not accept dash', function () { + assert.equal( + Utils.greedyTemplate('A phrase with a {var-iable}.', { 'var-iable': 'value' }), + 'A phrase with a {var-iable}.' + ) + }) + + it('should accept colon', function () { + assert.equal( + Utils.greedyTemplate('A phrase with a {variable:fr}.', { + 'variable:fr': 'value', + }), + 'A phrase with a value.' + ) + }) + + it('should accept arobase', function () { + assert.equal( + Utils.greedyTemplate('A phrase with a {@variable}.', { + '@variable': 'value', + }), + 'A phrase with a value.' + ) + }) + + it('should accept space', function () { + assert.equal( + Utils.greedyTemplate('A phrase with a {var iable}.', { + 'var iable': 'value', + }), + 'A phrase with a value.' + ) + }) + + it('should accept non ascii chars', function () { + assert.equal( + Utils.greedyTemplate('A phrase with a {Accessibilité} and {переменная}.', { + Accessibilité: 'value', + переменная: 'another', + }), + 'A phrase with a value and another.' + ) + }) + + it('should replace even with ignore if key is found', function () { + assert.equal( + Utils.greedyTemplate( + 'A phrase with a {variable:fr}.', + { 'variable:fr': 'value' }, + true + ), + 'A phrase with a value.' + ) + }) + + it('should keep string when using ignore if key is not found', function () { + assert.equal( + Utils.greedyTemplate('A phrase with a {variable:fr}.', {}, true), + 'A phrase with a {variable:fr}.' + ) + }) + + it('should replace nested variables', function () { + assert.equal( + Utils.greedyTemplate('A phrase with a {fr.var}.', { fr: { var: 'value' } }), + 'A phrase with a value.' + ) + }) + + it('should not fail if nested variable is missing', function () { + assert.equal( + Utils.greedyTemplate('A phrase with a {fr.var.foo}.', { + fr: { var: 'value' }, + }), + 'A phrase with a .' + ) + }) + + it('should not fail with nested variables and no data', function () { + assert.equal( + Utils.greedyTemplate('A phrase with a {fr.var.foo}.', {}), + 'A phrase with a .' + ) + }) + + it('should handle fallback value if any', function () { + assert.equal( + Utils.greedyTemplate('A phrase with a {fr.var.bar|"default"}.', {}), + 'A phrase with a default.' + ) + }) + + it('should handle fallback var if any', function () { + assert.equal( + Utils.greedyTemplate('A phrase with a {fr.var.bar|fallback}.', { + fallback: 'default', + }), + 'A phrase with a default.' + ) + }) + + it('should handle multiple fallbacks', function () { + assert.equal( + Utils.greedyTemplate('A phrase with a {fr.var.bar|try.again|"default"}.', {}), + 'A phrase with a default.' + ) + }) + + it('should use the first defined value', function () { + assert.equal( + Utils.greedyTemplate('A phrase with a {fr.var.bar|try.again|"default"}.', { + try: { again: 'please' }, + }), + 'A phrase with a please.' + ) + }) + + it('should use the first defined value', function () { + assert.equal( + Utils.greedyTemplate('A phrase with a {fr.var.bar|try.again|"default"}.', { + try: { again: 'again' }, + fr: { var: { bar: 'value' } }, + }), + 'A phrase with a value.' + ) + }) + + it('should support the first example from #820 when translated to final syntax', function () { + assert.equal( + Utils.greedyTemplate('# {name} ({ele|"-"} m ü. M.)', { name: 'Portalet' }), + '# Portalet (- m ü. M.)' + ) + }) + + it('should support the first example from #820 when translated to final syntax when no fallback required', function () { + assert.equal( + Utils.greedyTemplate('# {name} ({ele|"-"} m ü. M.)', { + name: 'Portalet', + ele: 3344, + }), + '# Portalet (3344 m ü. M.)' + ) + }) + + it('should support white space in fallback', function () { + assert.equal( + Utils.greedyTemplate('A phrase with {var|"white space in the fallback."}', {}), + 'A phrase with white space in the fallback.' + ) + }) + + it('should support empty string as fallback', function () { + assert.equal( + Utils.greedyTemplate( + 'A phrase with empty string ("{var|""}") in the fallback.', + {} + ), + 'A phrase with empty string ("") in the fallback.' + ) + }) + + it('should support e.g. links as fallback', function () { + assert.equal( + Utils.greedyTemplate( + 'A phrase with {var|"[[https://osm.org|link]]"} as fallback.', + {} + ), + 'A phrase with [[https://osm.org|link]] as fallback.' + ) + }) + }) + + describe('#flattenCoordinates()', function () { + it('should not alter already flat coords', function () { + var coords = [ + [1, 2], + [3, 4], + ] + assert.deepEqual(Utils.flattenCoordinates(coords), coords) + }) + + it('should flatten nested coords', function () { + var coords = [ + [ + [1, 2], + [3, 4], + ], + ] + assert.deepEqual(Utils.flattenCoordinates(coords), coords[0]) + coords = [ + [ + [ + [1, 2], + [3, 4], + ], + ], + ] + assert.deepEqual(Utils.flattenCoordinates(coords), coords[0][0]) + }) + + it('should not fail on empty coords', function () { + var coords = [] + assert.deepEqual(Utils.flattenCoordinates(coords), coords) + }) + }) + + describe('#usableOption()', function () { + it('should consider false', function () { + assert.ok(Utils.usableOption({ key: false }, 'key')) + }) + + it('should consider 0', function () { + assert.ok(Utils.usableOption({ key: 0 }, 'key')) + }) + + it('should not consider undefined', function () { + assert.notOk(Utils.usableOption({}, 'key')) + }) + + it('should not consider empty string', function () { + assert.notOk(Utils.usableOption({ key: '' }, 'key')) + }) + + it('should consider null', function () { + assert.ok(Utils.usableOption({ key: null }, 'key')) + }) + }) + + describe('#normalize()', function () { + if ( + ('should remove accents', + function () { + // French é + assert.equal(Utils.normalize('aéroport'), 'aeroport') + // American é + assert.equal(Utils.normalize('aéroport'), 'aeroport') + }) + ); + }) + + describe('#sortFeatures()', function () { + let feat1, feat2, feat3 + before(function () { + feat1 = { properties: {} } + feat2 = { properties: {} } + feat3 = { properties: {} } + }) + it('should sort feature from custom key', function () { + feat1.properties.mykey = '13. foo' + feat2.properties.mykey = '7. foo' + feat3.properties.mykey = '111. foo' + let features = Utils.sortFeatures([feat1, feat2, feat3], 'mykey') + assert.equal(features[0], feat2) + assert.equal(features[1], feat1) + assert.equal(features[2], feat3) + }) + it('should sort feature from multiple keys', function () { + feat1.properties.mykey = '13. foo' + feat2.properties.mykey = '111. foo' + feat3.properties.mykey = '111. foo' + feat1.properties.otherkey = 'C' + feat2.properties.otherkey = 'B' + feat3.properties.otherkey = 'A' + let features = Utils.sortFeatures([feat1, feat2, feat3], 'mykey,otherkey') + assert.equal(features[0], feat1) + assert.equal(features[1], feat3) + assert.equal(features[2], feat2) + }) + it('should sort feature from custom key reverse', function () { + feat1.properties.mykey = '13. foo' + feat2.properties.mykey = '7. foo' + feat3.properties.mykey = '111. foo' + let features = Utils.sortFeatures([feat1, feat2, feat3], '-mykey') + assert.equal(features[0], feat3) + assert.equal(features[1], feat1) + assert.equal(features[2], feat2) + }) + it('should sort feature from multiple keys with reverse', function () { + feat1.properties.mykey = '13. foo' + feat2.properties.mykey = '111. foo' + feat3.properties.mykey = '111. foo' + feat1.properties.otherkey = 'C' + feat2.properties.otherkey = 'B' + feat3.properties.otherkey = 'A' + let features = Utils.sortFeatures([feat1, feat2, feat3], 'mykey,-otherkey') + assert.equal(features[0], feat1) + assert.equal(features[1], feat2) + assert.equal(features[2], feat3) + }) + it('should sort feature with space first', function () { + feat1.properties.mykey = '1 foo' + feat2.properties.mykey = '2 foo' + feat3.properties.mykey = '1a foo' + let features = Utils.sortFeatures([feat1, feat2, feat3], 'mykey') + assert.equal(features[0], feat1) + assert.equal(features[1], feat3) + assert.equal(features[2], feat2) + }) + }) + + describe("#copyJSON", function () { + it('should actually copy the JSON', function () { + let originalJSON = { "some": "json" } + let returned = Utils.CopyJSON(originalJSON) + + // Change the original JSON + originalJSON["anotherKey"] = "value" + + // ensure the two aren't the same object + assert.notEqual(returned, originalJSON) + assert.deepEqual(returned, { "some": "json" }) + }) + }) +})