You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3350 lines
94 KiB

4 years ago
  1. /******/ (function(modules) { // webpackBootstrap
  2. /******/ // The module cache
  3. /******/ var installedModules = {};
  4. /******/
  5. /******/ // The require function
  6. /******/ function __webpack_require__(moduleId) {
  7. /******/
  8. /******/ // Check if module is in cache
  9. /******/ if(installedModules[moduleId]) {
  10. /******/ return installedModules[moduleId].exports;
  11. /******/ }
  12. /******/ // Create a new module (and put it into the cache)
  13. /******/ var module = installedModules[moduleId] = {
  14. /******/ i: moduleId,
  15. /******/ l: false,
  16. /******/ exports: {}
  17. /******/ };
  18. /******/
  19. /******/ // Execute the module function
  20. /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
  21. /******/
  22. /******/ // Flag the module as loaded
  23. /******/ module.l = true;
  24. /******/
  25. /******/ // Return the exports of the module
  26. /******/ return module.exports;
  27. /******/ }
  28. /******/
  29. /******/
  30. /******/ // expose the modules object (__webpack_modules__)
  31. /******/ __webpack_require__.m = modules;
  32. /******/
  33. /******/ // expose the module cache
  34. /******/ __webpack_require__.c = installedModules;
  35. /******/
  36. /******/ // define getter function for harmony exports
  37. /******/ __webpack_require__.d = function(exports, name, getter) {
  38. /******/ if(!__webpack_require__.o(exports, name)) {
  39. /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
  40. /******/ }
  41. /******/ };
  42. /******/
  43. /******/ // define __esModule on exports
  44. /******/ __webpack_require__.r = function(exports) {
  45. /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
  46. /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
  47. /******/ }
  48. /******/ Object.defineProperty(exports, '__esModule', { value: true });
  49. /******/ };
  50. /******/
  51. /******/ // create a fake namespace object
  52. /******/ // mode & 1: value is a module id, require it
  53. /******/ // mode & 2: merge all properties of value into the ns
  54. /******/ // mode & 4: return value when already ns object
  55. /******/ // mode & 8|1: behave like require
  56. /******/ __webpack_require__.t = function(value, mode) {
  57. /******/ if(mode & 1) value = __webpack_require__(value);
  58. /******/ if(mode & 8) return value;
  59. /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
  60. /******/ var ns = Object.create(null);
  61. /******/ __webpack_require__.r(ns);
  62. /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
  63. /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
  64. /******/ return ns;
  65. /******/ };
  66. /******/
  67. /******/ // getDefaultExport function for compatibility with non-harmony modules
  68. /******/ __webpack_require__.n = function(module) {
  69. /******/ var getter = module && module.__esModule ?
  70. /******/ function getDefault() { return module['default']; } :
  71. /******/ function getModuleExports() { return module; };
  72. /******/ __webpack_require__.d(getter, 'a', getter);
  73. /******/ return getter;
  74. /******/ };
  75. /******/
  76. /******/ // Object.prototype.hasOwnProperty.call
  77. /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
  78. /******/
  79. /******/ // __webpack_public_path__
  80. /******/ __webpack_require__.p = "/";
  81. /******/
  82. /******/
  83. /******/ // Load entry module and return exports
  84. /******/ return __webpack_require__(__webpack_require__.s = 0);
  85. /******/ })
  86. /************************************************************************/
  87. /******/ ({
  88. /***/ "./demo.js":
  89. /*!*****************!*\
  90. !*** ./demo.js ***!
  91. \*****************/
  92. /*! no exports provided */
  93. /***/ (function(module, __webpack_exports__, __webpack_require__) {
  94. "use strict";
  95. __webpack_require__.r(__webpack_exports__);
  96. /* harmony import */ var riot__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! riot */ "./node_modules/riot/riot.esm.js");
  97. /* harmony import */ var _src_TinyConsent_riot__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./src/TinyConsent.riot */ "./src/TinyConsent.riot");
  98. riot__WEBPACK_IMPORTED_MODULE_0__["register"]('tiny-consent', _src_TinyConsent_riot__WEBPACK_IMPORTED_MODULE_1__["default"]);
  99. var consent = {
  100. cookies: [{
  101. id: 'wordpress',
  102. name: 'wordpress_*',
  103. content: 'Wordpress und WooCommerce nutzen Session, diese werden zum einen für den Login genutzt, aber auch für den Warenkorb.',
  104. essential: true
  105. }, {
  106. name: 'matamo',
  107. content: 'test',
  108. handleAgree: function handleAgree() {
  109. console.log('agree');
  110. },
  111. handleReject: function handleReject() {
  112. console.log('reject');
  113. }
  114. }]
  115. };
  116. riot__WEBPACK_IMPORTED_MODULE_0__["mount"]('tiny-consent', consent);
  117. /***/ }),
  118. /***/ "./node_modules/js-cookie/src/js.cookie.js":
  119. /*!*************************************************!*\
  120. !*** ./node_modules/js-cookie/src/js.cookie.js ***!
  121. \*************************************************/
  122. /*! no static exports found */
  123. /***/ (function(module, exports, __webpack_require__) {
  124. var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;/*!
  125. * JavaScript Cookie v2.2.1
  126. * https://github.com/js-cookie/js-cookie
  127. *
  128. * Copyright 2006, 2015 Klaus Hartl & Fagner Brack
  129. * Released under the MIT license
  130. */
  131. ;(function (factory) {
  132. var registeredInModuleLoader;
  133. if (true) {
  134. !(__WEBPACK_AMD_DEFINE_FACTORY__ = (factory),
  135. __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ?
  136. (__WEBPACK_AMD_DEFINE_FACTORY__.call(exports, __webpack_require__, exports, module)) :
  137. __WEBPACK_AMD_DEFINE_FACTORY__),
  138. __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
  139. registeredInModuleLoader = true;
  140. }
  141. if (true) {
  142. module.exports = factory();
  143. registeredInModuleLoader = true;
  144. }
  145. if (!registeredInModuleLoader) {
  146. var OldCookies = window.Cookies;
  147. var api = window.Cookies = factory();
  148. api.noConflict = function () {
  149. window.Cookies = OldCookies;
  150. return api;
  151. };
  152. }
  153. }(function () {
  154. function extend () {
  155. var i = 0;
  156. var result = {};
  157. for (; i < arguments.length; i++) {
  158. var attributes = arguments[ i ];
  159. for (var key in attributes) {
  160. result[key] = attributes[key];
  161. }
  162. }
  163. return result;
  164. }
  165. function decode (s) {
  166. return s.replace(/(%[0-9A-Z]{2})+/g, decodeURIComponent);
  167. }
  168. function init (converter) {
  169. function api() {}
  170. function set (key, value, attributes) {
  171. if (typeof document === 'undefined') {
  172. return;
  173. }
  174. attributes = extend({
  175. path: '/'
  176. }, api.defaults, attributes);
  177. if (typeof attributes.expires === 'number') {
  178. attributes.expires = new Date(new Date() * 1 + attributes.expires * 864e+5);
  179. }
  180. // We're using "expires" because "max-age" is not supported by IE
  181. attributes.expires = attributes.expires ? attributes.expires.toUTCString() : '';
  182. try {
  183. var result = JSON.stringify(value);
  184. if (/^[\{\[]/.test(result)) {
  185. value = result;
  186. }
  187. } catch (e) {}
  188. value = converter.write ?
  189. converter.write(value, key) :
  190. encodeURIComponent(String(value))
  191. .replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent);
  192. key = encodeURIComponent(String(key))
  193. .replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent)
  194. .replace(/[\(\)]/g, escape);
  195. var stringifiedAttributes = '';
  196. for (var attributeName in attributes) {
  197. if (!attributes[attributeName]) {
  198. continue;
  199. }
  200. stringifiedAttributes += '; ' + attributeName;
  201. if (attributes[attributeName] === true) {
  202. continue;
  203. }
  204. // Considers RFC 6265 section 5.2:
  205. // ...
  206. // 3. If the remaining unparsed-attributes contains a %x3B (";")
  207. // character:
  208. // Consume the characters of the unparsed-attributes up to,
  209. // not including, the first %x3B (";") character.
  210. // ...
  211. stringifiedAttributes += '=' + attributes[attributeName].split(';')[0];
  212. }
  213. return (document.cookie = key + '=' + value + stringifiedAttributes);
  214. }
  215. function get (key, json) {
  216. if (typeof document === 'undefined') {
  217. return;
  218. }
  219. var jar = {};
  220. // To prevent the for loop in the first place assign an empty array
  221. // in case there are no cookies at all.
  222. var cookies = document.cookie ? document.cookie.split('; ') : [];
  223. var i = 0;
  224. for (; i < cookies.length; i++) {
  225. var parts = cookies[i].split('=');
  226. var cookie = parts.slice(1).join('=');
  227. if (!json && cookie.charAt(0) === '"') {
  228. cookie = cookie.slice(1, -1);
  229. }
  230. try {
  231. var name = decode(parts[0]);
  232. cookie = (converter.read || converter)(cookie, name) ||
  233. decode(cookie);
  234. if (json) {
  235. try {
  236. cookie = JSON.parse(cookie);
  237. } catch (e) {}
  238. }
  239. jar[name] = cookie;
  240. if (key === name) {
  241. break;
  242. }
  243. } catch (e) {}
  244. }
  245. return key ? jar[key] : jar;
  246. }
  247. api.set = set;
  248. api.get = function (key) {
  249. return get(key, false /* read as raw */);
  250. };
  251. api.getJSON = function (key) {
  252. return get(key, true /* read as json */);
  253. };
  254. api.remove = function (key, attributes) {
  255. set(key, '', extend(attributes, {
  256. expires: -1
  257. }));
  258. };
  259. api.defaults = {};
  260. api.withConverter = init;
  261. return api;
  262. }
  263. return init(function () {});
  264. }));
  265. /***/ }),
  266. /***/ "./node_modules/riot/riot.esm.js":
  267. /*!***************************************!*\
  268. !*** ./node_modules/riot/riot.esm.js ***!
  269. \***************************************/
  270. /*! exports provided: __, component, install, mount, pure, register, uninstall, unmount, unregister, version */
  271. /***/ (function(module, __webpack_exports__, __webpack_require__) {
  272. "use strict";
  273. __webpack_require__.r(__webpack_exports__);
  274. /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "__", function() { return __; });
  275. /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "component", function() { return component; });
  276. /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "install", function() { return install; });
  277. /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mount", function() { return mount; });
  278. /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "pure", function() { return pure; });
  279. /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "register", function() { return register; });
  280. /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "uninstall", function() { return uninstall; });
  281. /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "unmount", function() { return unmount; });
  282. /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "unregister", function() { return unregister; });
  283. /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "version", function() { return version; });
  284. /* Riot v4.8.6, @license MIT */
  285. const COMPONENTS_IMPLEMENTATION_MAP = new Map(),
  286. DOM_COMPONENT_INSTANCE_PROPERTY = Symbol('riot-component'),
  287. PLUGINS_SET = new Set(),
  288. IS_DIRECTIVE = 'is',
  289. VALUE_ATTRIBUTE = 'value',
  290. MOUNT_METHOD_KEY = 'mount',
  291. UPDATE_METHOD_KEY = 'update',
  292. UNMOUNT_METHOD_KEY = 'unmount',
  293. SHOULD_UPDATE_KEY = 'shouldUpdate',
  294. ON_BEFORE_MOUNT_KEY = 'onBeforeMount',
  295. ON_MOUNTED_KEY = 'onMounted',
  296. ON_BEFORE_UPDATE_KEY = 'onBeforeUpdate',
  297. ON_UPDATED_KEY = 'onUpdated',
  298. ON_BEFORE_UNMOUNT_KEY = 'onBeforeUnmount',
  299. ON_UNMOUNTED_KEY = 'onUnmounted',
  300. PROPS_KEY = 'props',
  301. STATE_KEY = 'state',
  302. SLOTS_KEY = 'slots',
  303. ROOT_KEY = 'root',
  304. IS_PURE_SYMBOL = Symbol.for('pure'),
  305. PARENT_KEY_SYMBOL = Symbol('parent'),
  306. ATTRIBUTES_KEY_SYMBOL = Symbol('attributes'),
  307. TEMPLATE_KEY_SYMBOL = Symbol('template');
  308. var globals = /*#__PURE__*/Object.freeze({
  309. __proto__: null,
  310. COMPONENTS_IMPLEMENTATION_MAP: COMPONENTS_IMPLEMENTATION_MAP,
  311. DOM_COMPONENT_INSTANCE_PROPERTY: DOM_COMPONENT_INSTANCE_PROPERTY,
  312. PLUGINS_SET: PLUGINS_SET,
  313. IS_DIRECTIVE: IS_DIRECTIVE,
  314. VALUE_ATTRIBUTE: VALUE_ATTRIBUTE,
  315. MOUNT_METHOD_KEY: MOUNT_METHOD_KEY,
  316. UPDATE_METHOD_KEY: UPDATE_METHOD_KEY,
  317. UNMOUNT_METHOD_KEY: UNMOUNT_METHOD_KEY,
  318. SHOULD_UPDATE_KEY: SHOULD_UPDATE_KEY,
  319. ON_BEFORE_MOUNT_KEY: ON_BEFORE_MOUNT_KEY,
  320. ON_MOUNTED_KEY: ON_MOUNTED_KEY,
  321. ON_BEFORE_UPDATE_KEY: ON_BEFORE_UPDATE_KEY,
  322. ON_UPDATED_KEY: ON_UPDATED_KEY,
  323. ON_BEFORE_UNMOUNT_KEY: ON_BEFORE_UNMOUNT_KEY,
  324. ON_UNMOUNTED_KEY: ON_UNMOUNTED_KEY,
  325. PROPS_KEY: PROPS_KEY,
  326. STATE_KEY: STATE_KEY,
  327. SLOTS_KEY: SLOTS_KEY,
  328. ROOT_KEY: ROOT_KEY,
  329. IS_PURE_SYMBOL: IS_PURE_SYMBOL,
  330. PARENT_KEY_SYMBOL: PARENT_KEY_SYMBOL,
  331. ATTRIBUTES_KEY_SYMBOL: ATTRIBUTES_KEY_SYMBOL,
  332. TEMPLATE_KEY_SYMBOL: TEMPLATE_KEY_SYMBOL
  333. });
  334. /**
  335. * Quick type checking
  336. * @param {*} element - anything
  337. * @param {string} type - type definition
  338. * @returns {boolean} true if the type corresponds
  339. */
  340. function checkType(element, type) {
  341. return typeof element === type;
  342. }
  343. /**
  344. * Check that will be passed if its argument is a function
  345. * @param {*} value - value to check
  346. * @returns {boolean} - true if the value is a function
  347. */
  348. function isFunction(value) {
  349. return checkType(value, 'function');
  350. }
  351. function noop() {
  352. return this;
  353. }
  354. /**
  355. * Autobind the methods of a source object to itself
  356. * @param {Object} source - probably a riot tag instance
  357. * @param {Array<string>} methods - list of the methods to autobind
  358. * @returns {Object} the original object received
  359. */
  360. function autobindMethods(source, methods) {
  361. methods.forEach(method => {
  362. source[method] = source[method].bind(source);
  363. });
  364. return source;
  365. }
  366. /**
  367. * Call the first argument received only if it's a function otherwise return it as it is
  368. * @param {*} source - anything
  369. * @returns {*} anything
  370. */
  371. function callOrAssign(source) {
  372. return isFunction(source) ? source.prototype && source.prototype.constructor ? new source() : source() : source;
  373. }
  374. /**
  375. * Convert a string from camel case to dash-case
  376. * @param {string} string - probably a component tag name
  377. * @returns {string} component name normalized
  378. */
  379. /**
  380. * Convert a string containing dashes to camel case
  381. * @param {string} string - input string
  382. * @returns {string} my-string -> myString
  383. */
  384. function dashToCamelCase(string) {
  385. return string.replace(/-(\w)/g, (_, c) => c.toUpperCase());
  386. }
  387. /**
  388. * Move all the child nodes from a source tag to another
  389. * @param {HTMLElement} source - source node
  390. * @param {HTMLElement} target - target node
  391. * @returns {undefined} it's a void method ¯\_()_/¯
  392. */
  393. // Ignore this helper because it's needed only for svg tags
  394. function moveChildren(source, target) {
  395. if (source.firstChild) {
  396. target.appendChild(source.firstChild);
  397. moveChildren(source, target);
  398. }
  399. }
  400. /**
  401. * Remove the child nodes from any DOM node
  402. * @param {HTMLElement} node - target node
  403. * @returns {undefined}
  404. */
  405. function cleanNode(node) {
  406. clearChildren(node.childNodes);
  407. }
  408. /**
  409. * Clear multiple children in a node
  410. * @param {HTMLElement[]} children - direct children nodes
  411. * @returns {undefined}
  412. */
  413. function clearChildren(children) {
  414. Array.from(children).forEach(removeNode);
  415. }
  416. /**
  417. * Remove a node from the DOM
  418. * @param {HTMLElement} node - target node
  419. * @returns {undefined}
  420. */
  421. function removeNode(node) {
  422. const {
  423. parentNode
  424. } = node;
  425. if (node.remove) node.remove();
  426. /* istanbul ignore else */
  427. else if (parentNode) parentNode.removeChild(node);
  428. }
  429. const EACH = 0;
  430. const IF = 1;
  431. const SIMPLE = 2;
  432. const TAG = 3;
  433. const SLOT = 4;
  434. var bindingTypes = {
  435. EACH,
  436. IF,
  437. SIMPLE,
  438. TAG,
  439. SLOT
  440. };
  441. const ATTRIBUTE = 0;
  442. const EVENT = 1;
  443. const TEXT = 2;
  444. const VALUE = 3;
  445. var expressionTypes = {
  446. ATTRIBUTE,
  447. EVENT,
  448. TEXT,
  449. VALUE
  450. };
  451. /**
  452. * Create the template meta object in case of <template> fragments
  453. * @param {TemplateChunk} componentTemplate - template chunk object
  454. * @returns {Object} the meta property that will be passed to the mount function of the TemplateChunk
  455. */
  456. function createTemplateMeta(componentTemplate) {
  457. const fragment = componentTemplate.dom.cloneNode(true);
  458. return {
  459. avoidDOMInjection: true,
  460. fragment,
  461. children: Array.from(fragment.childNodes)
  462. };
  463. }
  464. const {
  465. indexOf: iOF
  466. } = [];
  467. const append = (get, parent, children, start, end, before) => {
  468. const isSelect = 'selectedIndex' in parent;
  469. let noSelection = isSelect;
  470. while (start < end) {
  471. const child = get(children[start], 1);
  472. parent.insertBefore(child, before);
  473. if (isSelect && noSelection && child.selected) {
  474. noSelection = !noSelection;
  475. let {
  476. selectedIndex
  477. } = parent;
  478. parent.selectedIndex = selectedIndex < 0 ? start : iOF.call(parent.querySelectorAll('option'), child);
  479. }
  480. start++;
  481. }
  482. };
  483. const eqeq = (a, b) => a == b;
  484. const identity = O => O;
  485. const indexOf = (moreNodes, moreStart, moreEnd, lessNodes, lessStart, lessEnd, compare) => {
  486. const length = lessEnd - lessStart;
  487. /* istanbul ignore if */
  488. if (length < 1) return -1;
  489. while (moreEnd - moreStart >= length) {
  490. let m = moreStart;
  491. let l = lessStart;
  492. while (m < moreEnd && l < lessEnd && compare(moreNodes[m], lessNodes[l])) {
  493. m++;
  494. l++;
  495. }
  496. if (l === lessEnd) return moreStart;
  497. moreStart = m + 1;
  498. }
  499. return -1;
  500. };
  501. const isReversed = (futureNodes, futureEnd, currentNodes, currentStart, currentEnd, compare) => {
  502. while (currentStart < currentEnd && compare(currentNodes[currentStart], futureNodes[futureEnd - 1])) {
  503. currentStart++;
  504. futureEnd--;
  505. }
  506. return futureEnd === 0;
  507. };
  508. const next = (get, list, i, length, before) => i < length ? get(list[i], 0) : 0 < i ? get(list[i - 1], -0).nextSibling : before;
  509. const remove = (get, children, start, end) => {
  510. while (start < end) drop(get(children[start++], -1));
  511. }; // - - - - - - - - - - - - - - - - - - -
  512. // diff related constants and utilities
  513. // - - - - - - - - - - - - - - - - - - -
  514. const DELETION = -1;
  515. const INSERTION = 1;
  516. const SKIP = 0;
  517. const SKIP_OND = 50;
  518. const HS = (futureNodes, futureStart, futureEnd, futureChanges, currentNodes, currentStart, currentEnd, currentChanges) => {
  519. let k = 0;
  520. /* istanbul ignore next */
  521. let minLen = futureChanges < currentChanges ? futureChanges : currentChanges;
  522. const link = Array(minLen++);
  523. const tresh = Array(minLen);
  524. tresh[0] = -1;
  525. for (let i = 1; i < minLen; i++) tresh[i] = currentEnd;
  526. const nodes = currentNodes.slice(currentStart, currentEnd);
  527. for (let i = futureStart; i < futureEnd; i++) {
  528. const index = nodes.indexOf(futureNodes[i]);
  529. if (-1 < index) {
  530. const idxInOld = index + currentStart;
  531. k = findK(tresh, minLen, idxInOld);
  532. /* istanbul ignore else */
  533. if (-1 < k) {
  534. tresh[k] = idxInOld;
  535. link[k] = {
  536. newi: i,
  537. oldi: idxInOld,
  538. prev: link[k - 1]
  539. };
  540. }
  541. }
  542. }
  543. k = --minLen;
  544. --currentEnd;
  545. while (tresh[k] > currentEnd) --k;
  546. minLen = currentChanges + futureChanges - k;
  547. const diff = Array(minLen);
  548. let ptr = link[k];
  549. --futureEnd;
  550. while (ptr) {
  551. const {
  552. newi,
  553. oldi
  554. } = ptr;
  555. while (futureEnd > newi) {
  556. diff[--minLen] = INSERTION;
  557. --futureEnd;
  558. }
  559. while (currentEnd > oldi) {
  560. diff[--minLen] = DELETION;
  561. --currentEnd;
  562. }
  563. diff[--minLen] = SKIP;
  564. --futureEnd;
  565. --currentEnd;
  566. ptr = ptr.prev;
  567. }
  568. while (futureEnd >= futureStart) {
  569. diff[--minLen] = INSERTION;
  570. --futureEnd;
  571. }
  572. while (currentEnd >= currentStart) {
  573. diff[--minLen] = DELETION;
  574. --currentEnd;
  575. }
  576. return diff;
  577. }; // this is pretty much the same petit-dom code without the delete map part
  578. // https://github.com/yelouafi/petit-dom/blob/bd6f5c919b5ae5297be01612c524c40be45f14a7/src/vdom.js#L556-L561
  579. const OND = (futureNodes, futureStart, rows, currentNodes, currentStart, cols, compare) => {
  580. const length = rows + cols;
  581. const v = [];
  582. let d, k, r, c, pv, cv, pd;
  583. outer: for (d = 0; d <= length; d++) {
  584. /* istanbul ignore if */
  585. if (d > SKIP_OND) return null;
  586. pd = d - 1;
  587. /* istanbul ignore next */
  588. pv = d ? v[d - 1] : [0, 0];
  589. cv = v[d] = [];
  590. for (k = -d; k <= d; k += 2) {
  591. if (k === -d || k !== d && pv[pd + k - 1] < pv[pd + k + 1]) {
  592. c = pv[pd + k + 1];
  593. } else {
  594. c = pv[pd + k - 1] + 1;
  595. }
  596. r = c - k;
  597. while (c < cols && r < rows && compare(currentNodes[currentStart + c], futureNodes[futureStart + r])) {
  598. c++;
  599. r++;
  600. }
  601. if (c === cols && r === rows) {
  602. break outer;
  603. }
  604. cv[d + k] = c;
  605. }
  606. }
  607. const diff = Array(d / 2 + length / 2);
  608. let diffIdx = diff.length - 1;
  609. for (d = v.length - 1; d >= 0; d--) {
  610. while (c > 0 && r > 0 && compare(currentNodes[currentStart + c - 1], futureNodes[futureStart + r - 1])) {
  611. // diagonal edge = equality
  612. diff[diffIdx--] = SKIP;
  613. c--;
  614. r--;
  615. }
  616. if (!d) break;
  617. pd = d - 1;
  618. /* istanbul ignore next */
  619. pv = d ? v[d - 1] : [0, 0];
  620. k = c - r;
  621. if (k === -d || k !== d && pv[pd + k - 1] < pv[pd + k + 1]) {
  622. // vertical edge = insertion
  623. r--;
  624. diff[diffIdx--] = INSERTION;
  625. } else {
  626. // horizontal edge = deletion
  627. c--;
  628. diff[diffIdx--] = DELETION;
  629. }
  630. }
  631. return diff;
  632. };
  633. const applyDiff = (diff, get, parentNode, futureNodes, futureStart, currentNodes, currentStart, currentLength, before) => {
  634. const live = [];
  635. const length = diff.length;
  636. let currentIndex = currentStart;
  637. let i = 0;
  638. while (i < length) {
  639. switch (diff[i++]) {
  640. case SKIP:
  641. futureStart++;
  642. currentIndex++;
  643. break;
  644. case INSERTION:
  645. // TODO: bulk appends for sequential nodes
  646. live.push(futureNodes[futureStart]);
  647. append(get, parentNode, futureNodes, futureStart++, futureStart, currentIndex < currentLength ? get(currentNodes[currentIndex], 0) : before);
  648. break;
  649. case DELETION:
  650. currentIndex++;
  651. break;
  652. }
  653. }
  654. i = 0;
  655. while (i < length) {
  656. switch (diff[i++]) {
  657. case SKIP:
  658. currentStart++;
  659. break;
  660. case DELETION:
  661. // TODO: bulk removes for sequential nodes
  662. if (-1 < live.indexOf(currentNodes[currentStart])) currentStart++;else remove(get, currentNodes, currentStart++, currentStart);
  663. break;
  664. }
  665. }
  666. };
  667. const findK = (ktr, length, j) => {
  668. let lo = 1;
  669. let hi = length;
  670. while (lo < hi) {
  671. const mid = (lo + hi) / 2 >>> 0;
  672. if (j < ktr[mid]) hi = mid;else lo = mid + 1;
  673. }
  674. return lo;
  675. };
  676. const smartDiff = (get, parentNode, futureNodes, futureStart, futureEnd, futureChanges, currentNodes, currentStart, currentEnd, currentChanges, currentLength, compare, before) => {
  677. applyDiff(OND(futureNodes, futureStart, futureChanges, currentNodes, currentStart, currentChanges, compare) || HS(futureNodes, futureStart, futureEnd, futureChanges, currentNodes, currentStart, currentEnd, currentChanges), get, parentNode, futureNodes, futureStart, currentNodes, currentStart, currentLength, before);
  678. };
  679. const drop = node => (node.remove || dropChild).call(node);
  680. function dropChild() {
  681. const {
  682. parentNode
  683. } = this;
  684. /* istanbul ignore else */
  685. if (parentNode) parentNode.removeChild(this);
  686. }
  687. /*! (c) 2018 Andrea Giammarchi (ISC) */
  688. const domdiff = (parentNode, // where changes happen
  689. currentNodes, // Array of current items/nodes
  690. futureNodes, // Array of future items/nodes
  691. options // optional object with one of the following properties
  692. // before: domNode
  693. // compare(generic, generic) => true if same generic
  694. // node(generic) => Node
  695. ) => {
  696. if (!options) options = {};
  697. const compare = options.compare || eqeq;
  698. const get = options.node || identity;
  699. const before = options.before == null ? null : get(options.before, 0);
  700. const currentLength = currentNodes.length;
  701. let currentEnd = currentLength;
  702. let currentStart = 0;
  703. let futureEnd = futureNodes.length;
  704. let futureStart = 0; // common prefix
  705. while (currentStart < currentEnd && futureStart < futureEnd && compare(currentNodes[currentStart], futureNodes[futureStart])) {
  706. currentStart++;
  707. futureStart++;
  708. } // common suffix
  709. while (currentStart < currentEnd && futureStart < futureEnd && compare(currentNodes[currentEnd - 1], futureNodes[futureEnd - 1])) {
  710. currentEnd--;
  711. futureEnd--;
  712. }
  713. const currentSame = currentStart === currentEnd;
  714. const futureSame = futureStart === futureEnd; // same list
  715. if (currentSame && futureSame) return futureNodes; // only stuff to add
  716. if (currentSame && futureStart < futureEnd) {
  717. append(get, parentNode, futureNodes, futureStart, futureEnd, next(get, currentNodes, currentStart, currentLength, before));
  718. return futureNodes;
  719. } // only stuff to remove
  720. if (futureSame && currentStart < currentEnd) {
  721. remove(get, currentNodes, currentStart, currentEnd);
  722. return futureNodes;
  723. }
  724. const currentChanges = currentEnd - currentStart;
  725. const futureChanges = futureEnd - futureStart;
  726. let i = -1; // 2 simple indels: the shortest sequence is a subsequence of the longest
  727. if (currentChanges < futureChanges) {
  728. i = indexOf(futureNodes, futureStart, futureEnd, currentNodes, currentStart, currentEnd, compare); // inner diff
  729. if (-1 < i) {
  730. append(get, parentNode, futureNodes, futureStart, i, get(currentNodes[currentStart], 0));
  731. append(get, parentNode, futureNodes, i + currentChanges, futureEnd, next(get, currentNodes, currentEnd, currentLength, before));
  732. return futureNodes;
  733. }
  734. }
  735. /* istanbul ignore else */
  736. else if (futureChanges < currentChanges) {
  737. i = indexOf(currentNodes, currentStart, currentEnd, futureNodes, futureStart, futureEnd, compare); // outer diff
  738. if (-1 < i) {
  739. remove(get, currentNodes, currentStart, i);
  740. remove(get, currentNodes, i + futureChanges, currentEnd);
  741. return futureNodes;
  742. }
  743. } // common case with one replacement for many nodes
  744. // or many nodes replaced for a single one
  745. /* istanbul ignore else */
  746. if (currentChanges < 2 || futureChanges < 2) {
  747. append(get, parentNode, futureNodes, futureStart, futureEnd, get(currentNodes[currentStart], 0));
  748. remove(get, currentNodes, currentStart, currentEnd);
  749. return futureNodes;
  750. } // the half match diff part has been skipped in petit-dom
  751. // https://github.com/yelouafi/petit-dom/blob/bd6f5c919b5ae5297be01612c524c40be45f14a7/src/vdom.js#L391-L397
  752. // accordingly, I think it's safe to skip in here too
  753. // if one day it'll come out like the speediest thing ever to do
  754. // then I might add it in here too
  755. // Extra: before going too fancy, what about reversed lists ?
  756. // This should bail out pretty quickly if that's not the case.
  757. if (currentChanges === futureChanges && isReversed(futureNodes, futureEnd, currentNodes, currentStart, currentEnd, compare)) {
  758. append(get, parentNode, futureNodes, futureStart, futureEnd, next(get, currentNodes, currentEnd, currentLength, before));
  759. return futureNodes;
  760. } // last resort through a smart diff
  761. smartDiff(get, parentNode, futureNodes, futureStart, futureEnd, futureChanges, currentNodes, currentStart, currentEnd, currentChanges, currentLength, compare, before);
  762. return futureNodes;
  763. };
  764. /**
  765. * Quick type checking
  766. * @param {*} element - anything
  767. * @param {string} type - type definition
  768. * @returns {boolean} true if the type corresponds
  769. */
  770. function checkType$1(element, type) {
  771. return typeof element === type;
  772. }
  773. /**
  774. * Check if an element is part of an svg
  775. * @param {HTMLElement} el - element to check
  776. * @returns {boolean} true if we are in an svg context
  777. */
  778. function isSvg(el) {
  779. const owner = el.ownerSVGElement;
  780. return !!owner || owner === null;
  781. }
  782. /**
  783. * Check if an element is a template tag
  784. * @param {HTMLElement} el - element to check
  785. * @returns {boolean} true if it's a <template>
  786. */
  787. function isTemplate(el) {
  788. return !isNil(el.content);
  789. }
  790. /**
  791. * Check that will be passed if its argument is a function
  792. * @param {*} value - value to check
  793. * @returns {boolean} - true if the value is a function
  794. */
  795. function isFunction$1(value) {
  796. return checkType$1(value, 'function');
  797. }
  798. /**
  799. * Check if a value is a Boolean
  800. * @param {*} value - anything
  801. * @returns {boolean} true only for the value is a boolean
  802. */
  803. function isBoolean(value) {
  804. return checkType$1(value, 'boolean');
  805. }
  806. /**
  807. * Check if a value is an Object
  808. * @param {*} value - anything
  809. * @returns {boolean} true only for the value is an object
  810. */
  811. function isObject(value) {
  812. return !isNil(value) && checkType$1(value, 'object');
  813. }
  814. /**
  815. * Check if a value is null or undefined
  816. * @param {*} value - anything
  817. * @returns {boolean} true only for the 'undefined' and 'null' types
  818. */
  819. function isNil(value) {
  820. return value === null || value === undefined;
  821. }
  822. const UNMOUNT_SCOPE = Symbol('unmount');
  823. const EachBinding = Object.seal({
  824. // dynamic binding properties
  825. // childrenMap: null,
  826. // node: null,
  827. // root: null,
  828. // condition: null,
  829. // evaluate: null,
  830. // template: null,
  831. // isTemplateTag: false,
  832. nodes: [],
  833. // getKey: null,
  834. // indexName: null,
  835. // itemName: null,
  836. // afterPlaceholder: null,
  837. // placeholder: null,
  838. // API methods
  839. mount(scope, parentScope) {
  840. return this.update(scope, parentScope);
  841. },
  842. update(scope, parentScope) {
  843. const {
  844. placeholder,
  845. nodes,
  846. childrenMap
  847. } = this;
  848. const collection = scope === UNMOUNT_SCOPE ? null : this.evaluate(scope);
  849. const items = collection ? Array.from(collection) : [];
  850. const parent = placeholder.parentNode; // prepare the diffing
  851. const {
  852. newChildrenMap,
  853. batches,
  854. futureNodes
  855. } = createPatch(items, scope, parentScope, this); // patch the DOM only if there are new nodes
  856. domdiff(parent, nodes, futureNodes, {
  857. before: placeholder,
  858. node: patch(Array.from(childrenMap.values()), parentScope)
  859. }); // trigger the mounts and the updates
  860. batches.forEach(fn => fn()); // update the children map
  861. this.childrenMap = newChildrenMap;
  862. this.nodes = futureNodes;
  863. return this;
  864. },
  865. unmount(scope, parentScope) {
  866. this.update(UNMOUNT_SCOPE, parentScope);
  867. return this;
  868. }
  869. });
  870. /**
  871. * Patch the DOM while diffing
  872. * @param {TemplateChunk[]} redundant - redundant tepmplate chunks
  873. * @param {*} parentScope - scope of the parent template
  874. * @returns {Function} patch function used by domdiff
  875. */
  876. function patch(redundant, parentScope) {
  877. return (item, info) => {
  878. if (info < 0) {
  879. const element = redundant.pop();
  880. if (element) {
  881. const {
  882. template,
  883. context
  884. } = element; // notice that we pass null as last argument because
  885. // the root node and its children will be removed by domdiff
  886. template.unmount(context, parentScope, null);
  887. }
  888. }
  889. return item;
  890. };
  891. }
  892. /**
  893. * Check whether a template must be filtered from a loop
  894. * @param {Function} condition - filter function
  895. * @param {Object} context - argument passed to the filter function
  896. * @returns {boolean} true if this item should be skipped
  897. */
  898. function mustFilterItem(condition, context) {
  899. return condition ? Boolean(condition(context)) === false : false;
  900. }
  901. /**
  902. * Extend the scope of the looped template
  903. * @param {Object} scope - current template scope
  904. * @param {string} options.itemName - key to identify the looped item in the new context
  905. * @param {string} options.indexName - key to identify the index of the looped item
  906. * @param {number} options.index - current index
  907. * @param {*} options.item - collection item looped
  908. * @returns {Object} enhanced scope object
  909. */
  910. function extendScope(scope, _ref) {
  911. let {
  912. itemName,
  913. indexName,
  914. index,
  915. item
  916. } = _ref;
  917. scope[itemName] = item;
  918. if (indexName) scope[indexName] = index;
  919. return scope;
  920. }
  921. /**
  922. * Loop the current template items
  923. * @param {Array} items - expression collection value
  924. * @param {*} scope - template scope
  925. * @param {*} parentScope - scope of the parent template
  926. * @param {EeachBinding} binding - each binding object instance
  927. * @returns {Object} data
  928. * @returns {Map} data.newChildrenMap - a Map containing the new children template structure
  929. * @returns {Array} data.batches - array containing the template lifecycle functions to trigger
  930. * @returns {Array} data.futureNodes - array containing the nodes we need to diff
  931. */
  932. function createPatch(items, scope, parentScope, binding) {
  933. const {
  934. condition,
  935. template,
  936. childrenMap,
  937. itemName,
  938. getKey,
  939. indexName,
  940. root,
  941. isTemplateTag
  942. } = binding;
  943. const newChildrenMap = new Map();
  944. const batches = [];
  945. const futureNodes = [];
  946. items.forEach((item, index) => {
  947. const context = extendScope(Object.create(scope), {
  948. itemName,
  949. indexName,
  950. index,
  951. item
  952. });
  953. const key = getKey ? getKey(context) : index;
  954. const oldItem = childrenMap.get(key);
  955. if (mustFilterItem(condition, context)) {
  956. return;
  957. }
  958. const componentTemplate = oldItem ? oldItem.template : template.clone();
  959. const el = oldItem ? componentTemplate.el : root.cloneNode();
  960. const mustMount = !oldItem;
  961. const meta = isTemplateTag && mustMount ? createTemplateMeta(componentTemplate) : {};
  962. if (mustMount) {
  963. batches.push(() => componentTemplate.mount(el, context, parentScope, meta));
  964. } else {
  965. batches.push(() => componentTemplate.update(context, parentScope));
  966. } // create the collection of nodes to update or to add
  967. // in case of template tags we need to add all its children nodes
  968. if (isTemplateTag) {
  969. const children = meta.children || componentTemplate.children;
  970. futureNodes.push(...children); // add fake children into the childrenMap in order to preserve
  971. // the index in case of unmount calls
  972. children.forEach(child => newChildrenMap.set(child, null));
  973. } else {
  974. futureNodes.push(el);
  975. } // delete the old item from the children map
  976. childrenMap.delete(key); // update the children map
  977. newChildrenMap.set(key, {
  978. template: componentTemplate,
  979. context,
  980. index
  981. });
  982. });
  983. return {
  984. newChildrenMap,
  985. batches,
  986. futureNodes
  987. };
  988. }
  989. function create(node, _ref2) {
  990. let {
  991. evaluate,
  992. condition,
  993. itemName,
  994. indexName,
  995. getKey,
  996. template
  997. } = _ref2;
  998. const placeholder = document.createTextNode('');
  999. const parent = node.parentNode;
  1000. const root = node.cloneNode();
  1001. parent.insertBefore(placeholder, node);
  1002. removeNode(node);
  1003. return Object.assign({}, EachBinding, {
  1004. childrenMap: new Map(),
  1005. node,
  1006. root,
  1007. condition,
  1008. evaluate,
  1009. isTemplateTag: isTemplate(root),
  1010. template: template.createDOM(node),
  1011. getKey,
  1012. indexName,
  1013. itemName,
  1014. placeholder
  1015. });
  1016. }
  1017. /**
  1018. * Binding responsible for the `if` directive
  1019. */
  1020. const IfBinding = Object.seal({
  1021. // dynamic binding properties
  1022. // node: null,
  1023. // evaluate: null,
  1024. // isTemplateTag: false,
  1025. // placeholder: null,
  1026. // template: null,
  1027. // API methods
  1028. mount(scope, parentScope) {
  1029. return this.update(scope, parentScope);
  1030. },
  1031. update(scope, parentScope) {
  1032. const value = !!this.evaluate(scope);
  1033. const mustMount = !this.value && value;
  1034. const mustUnmount = this.value && !value;
  1035. const mount = () => {
  1036. const pristine = this.node.cloneNode();
  1037. this.placeholder.parentNode.insertBefore(pristine, this.placeholder);
  1038. this.template = this.template.clone();
  1039. this.template.mount(pristine, scope, parentScope);
  1040. };
  1041. switch (true) {
  1042. case mustMount:
  1043. mount();
  1044. break;
  1045. case mustUnmount:
  1046. this.unmount(scope);
  1047. break;
  1048. default:
  1049. if (value) this.template.update(scope, parentScope);
  1050. }
  1051. this.value = value;
  1052. return this;
  1053. },
  1054. unmount(scope, parentScope) {
  1055. this.template.unmount(scope, parentScope, true);
  1056. return this;
  1057. }
  1058. });
  1059. function create$1(node, _ref3) {
  1060. let {
  1061. evaluate,
  1062. template
  1063. } = _ref3;
  1064. const parent = node.parentNode;
  1065. const placeholder = document.createTextNode('');
  1066. parent.insertBefore(placeholder, node);
  1067. removeNode(node);
  1068. return Object.assign({}, IfBinding, {
  1069. node,
  1070. evaluate,
  1071. placeholder,
  1072. template: template.createDOM(node)
  1073. });
  1074. }
  1075. /**
  1076. * Returns the memoized (cached) function.
  1077. * // borrowed from https://www.30secondsofcode.org/js/s/memoize
  1078. * @param {Function} fn - function to memoize
  1079. * @returns {Function} memoize function
  1080. */
  1081. function memoize(fn) {
  1082. const cache = new Map();
  1083. const cached = val => {
  1084. return cache.has(val) ? cache.get(val) : cache.set(val, fn.call(this, val)) && cache.get(val);
  1085. };
  1086. cached.cache = cache;
  1087. return cached;
  1088. }
  1089. /**
  1090. * Evaluate a list of attribute expressions
  1091. * @param {Array} attributes - attribute expressions generated by the riot compiler
  1092. * @returns {Object} key value pairs with the result of the computation
  1093. */
  1094. function evaluateAttributeExpressions(attributes) {
  1095. return attributes.reduce((acc, attribute) => {
  1096. const {
  1097. value,
  1098. type
  1099. } = attribute;
  1100. switch (true) {
  1101. // spread attribute
  1102. case !attribute.name && type === ATTRIBUTE:
  1103. return Object.assign({}, acc, {}, value);
  1104. // value attribute
  1105. case type === VALUE:
  1106. acc.value = attribute.value;
  1107. break;
  1108. // normal attributes
  1109. default:
  1110. acc[dashToCamelCase(attribute.name)] = attribute.value;
  1111. }
  1112. return acc;
  1113. }, {});
  1114. }
  1115. const REMOVE_ATTRIBUTE = 'removeAttribute';
  1116. const SET_ATTIBUTE = 'setAttribute';
  1117. const ElementProto = typeof Element === 'undefined' ? {} : Element.prototype;
  1118. const isNativeHtmlProperty = memoize(name => ElementProto.hasOwnProperty(name)); // eslint-disable-line
  1119. /**
  1120. * Add all the attributes provided
  1121. * @param {HTMLElement} node - target node
  1122. * @param {Object} attributes - object containing the attributes names and values
  1123. * @returns {undefined} sorry it's a void function :(
  1124. */
  1125. function setAllAttributes(node, attributes) {
  1126. Object.entries(attributes).forEach((_ref4) => {
  1127. let [name, value] = _ref4;
  1128. return attributeExpression(node, {
  1129. name
  1130. }, value);
  1131. });
  1132. }
  1133. /**
  1134. * Remove all the attributes provided
  1135. * @param {HTMLElement} node - target node
  1136. * @param {Object} attributes - object containing all the attribute names
  1137. * @returns {undefined} sorry it's a void function :(
  1138. */
  1139. function removeAllAttributes(node, attributes) {
  1140. Object.keys(attributes).forEach(attribute => node.removeAttribute(attribute));
  1141. }
  1142. /**
  1143. * This methods handles the DOM attributes updates
  1144. * @param {HTMLElement} node - target node
  1145. * @param {Object} expression - expression object
  1146. * @param {string} expression.name - attribute name
  1147. * @param {*} value - new expression value
  1148. * @param {*} oldValue - the old expression cached value
  1149. * @returns {undefined}
  1150. */
  1151. function attributeExpression(node, _ref5, value, oldValue) {
  1152. let {
  1153. name
  1154. } = _ref5;
  1155. // is it a spread operator? {...attributes}
  1156. if (!name) {
  1157. // is the value still truthy?
  1158. if (value) {
  1159. setAllAttributes(node, value);
  1160. } else if (oldValue) {
  1161. // otherwise remove all the old attributes
  1162. removeAllAttributes(node, oldValue);
  1163. }
  1164. return;
  1165. } // handle boolean attributes
  1166. if (!isNativeHtmlProperty(name) && (isBoolean(value) || isObject(value) || isFunction$1(value))) {
  1167. node[name] = value;
  1168. }
  1169. node[getMethod(value)](name, normalizeValue(name, value));
  1170. }
  1171. /**
  1172. * Get the attribute modifier method
  1173. * @param {*} value - if truthy we return `setAttribute` othewise `removeAttribute`
  1174. * @returns {string} the node attribute modifier method name
  1175. */
  1176. function getMethod(value) {
  1177. return isNil(value) || value === false || value === '' || isObject(value) || isFunction$1(value) ? REMOVE_ATTRIBUTE : SET_ATTIBUTE;
  1178. }
  1179. /**
  1180. * Get the value as string
  1181. * @param {string} name - attribute name
  1182. * @param {*} value - user input value
  1183. * @returns {string} input value as string
  1184. */
  1185. function normalizeValue(name, value) {
  1186. // be sure that expressions like selected={ true } will be always rendered as selected='selected'
  1187. if (value === true) return name;
  1188. return value;
  1189. }
  1190. const RE_EVENTS_PREFIX = /^on/;
  1191. /**
  1192. * Set a new event listener
  1193. * @param {HTMLElement} node - target node
  1194. * @param {Object} expression - expression object
  1195. * @param {string} expression.name - event name
  1196. * @param {*} value - new expression value
  1197. * @param {*} oldValue - old expression value
  1198. * @returns {value} the callback just received
  1199. */
  1200. function eventExpression(node, _ref6, value, oldValue) {
  1201. let {
  1202. name
  1203. } = _ref6;
  1204. const normalizedEventName = name.replace(RE_EVENTS_PREFIX, '');
  1205. if (oldValue) {
  1206. node.removeEventListener(normalizedEventName, oldValue);
  1207. }
  1208. if (value) {
  1209. node.addEventListener(normalizedEventName, value, false);
  1210. }
  1211. }
  1212. /**
  1213. * Normalize the user value in order to render a empty string in case of falsy values
  1214. * @param {*} value - user input value
  1215. * @returns {string} hopefully a string
  1216. */
  1217. function normalizeStringValue(value) {
  1218. return isNil(value) ? '' : value;
  1219. }
  1220. /**
  1221. * Get the the target text node to update or create one from of a comment node
  1222. * @param {HTMLElement} node - any html element containing childNodes
  1223. * @param {number} childNodeIndex - index of the text node in the childNodes list
  1224. * @returns {HTMLTextNode} the text node to update
  1225. */
  1226. const getTextNode = (node, childNodeIndex) => {
  1227. const target = node.childNodes[childNodeIndex];
  1228. if (target.nodeType === Node.COMMENT_NODE) {
  1229. const textNode = document.createTextNode('');
  1230. node.replaceChild(textNode, target);
  1231. return textNode;
  1232. }
  1233. return target;
  1234. };
  1235. /**
  1236. * This methods handles a simple text expression update
  1237. * @param {HTMLElement} node - target node
  1238. * @param {Object} data - expression object
  1239. * @param {*} value - new expression value
  1240. * @returns {undefined}
  1241. */
  1242. function textExpression(node, data, value) {
  1243. node.data = normalizeStringValue(value);
  1244. }
  1245. /**
  1246. * This methods handles the input fileds value updates
  1247. * @param {HTMLElement} node - target node
  1248. * @param {Object} expression - expression object
  1249. * @param {*} value - new expression value
  1250. * @returns {undefined}
  1251. */
  1252. function valueExpression(node, expression, value) {
  1253. node.value = normalizeStringValue(value);
  1254. }
  1255. var expressions = {
  1256. [ATTRIBUTE]: attributeExpression,
  1257. [EVENT]: eventExpression,
  1258. [TEXT]: textExpression,
  1259. [VALUE]: valueExpression
  1260. };
  1261. const Expression = Object.seal({
  1262. // Static props
  1263. // node: null,
  1264. // value: null,
  1265. // API methods
  1266. /**
  1267. * Mount the expression evaluating its initial value
  1268. * @param {*} scope - argument passed to the expression to evaluate its current values
  1269. * @returns {Expression} self
  1270. */
  1271. mount(scope) {
  1272. // hopefully a pure function
  1273. this.value = this.evaluate(scope); // IO() DOM updates
  1274. apply(this, this.value);
  1275. return this;
  1276. },
  1277. /**
  1278. * Update the expression if its value changed
  1279. * @param {*} scope - argument passed to the expression to evaluate its current values
  1280. * @returns {Expression} self
  1281. */
  1282. update(scope) {
  1283. // pure function
  1284. const value = this.evaluate(scope);
  1285. if (this.value !== value) {
  1286. // IO() DOM updates
  1287. apply(this, value);
  1288. this.value = value;
  1289. }
  1290. return this;
  1291. },
  1292. /**
  1293. * Expression teardown method
  1294. * @returns {Expression} self
  1295. */
  1296. unmount() {
  1297. // unmount only the event handling expressions
  1298. if (this.type === EVENT) apply(this, null);
  1299. return this;
  1300. }
  1301. });
  1302. /**
  1303. * IO() function to handle the DOM updates
  1304. * @param {Expression} expression - expression object
  1305. * @param {*} value - current expression value
  1306. * @returns {undefined}
  1307. */
  1308. function apply(expression, value) {
  1309. return expressions[expression.type](expression.node, expression, value, expression.value);
  1310. }
  1311. function create$2(node, data) {
  1312. return Object.assign({}, Expression, {}, data, {
  1313. node: data.type === TEXT ? getTextNode(node, data.childNodeIndex) : node
  1314. });
  1315. }
  1316. /**
  1317. * Create a flat object having as keys a list of methods that if dispatched will propagate
  1318. * on the whole collection
  1319. * @param {Array} collection - collection to iterate
  1320. * @param {Array<string>} methods - methods to execute on each item of the collection
  1321. * @param {*} context - context returned by the new methods created
  1322. * @returns {Object} a new object to simplify the the nested methods dispatching
  1323. */
  1324. function flattenCollectionMethods(collection, methods, context) {
  1325. return methods.reduce((acc, method) => {
  1326. return Object.assign({}, acc, {
  1327. [method]: scope => {
  1328. return collection.map(item => item[method](scope)) && context;
  1329. }
  1330. });
  1331. }, {});
  1332. }
  1333. function create$3(node, _ref7) {
  1334. let {
  1335. expressions
  1336. } = _ref7;
  1337. return Object.assign({}, flattenCollectionMethods(expressions.map(expression => create$2(node, expression)), ['mount', 'update', 'unmount']));
  1338. }
  1339. function extendParentScope(attributes, scope, parentScope) {
  1340. if (!attributes || !attributes.length) return parentScope;
  1341. const expressions = attributes.map(attr => Object.assign({}, attr, {
  1342. value: attr.evaluate(scope)
  1343. }));
  1344. return Object.assign(Object.create(parentScope || null), evaluateAttributeExpressions(expressions));
  1345. }
  1346. const SlotBinding = Object.seal({
  1347. // dynamic binding properties
  1348. // node: null,
  1349. // name: null,
  1350. attributes: [],
  1351. // template: null,
  1352. getTemplateScope(scope, parentScope) {
  1353. return extendParentScope(this.attributes, scope, parentScope);
  1354. },
  1355. // API methods
  1356. mount(scope, parentScope) {
  1357. const templateData = scope.slots ? scope.slots.find((_ref8) => {
  1358. let {
  1359. id
  1360. } = _ref8;
  1361. return id === this.name;
  1362. }) : false;
  1363. const {
  1364. parentNode
  1365. } = this.node;
  1366. this.template = templateData && create$6(templateData.html, templateData.bindings).createDOM(parentNode);
  1367. if (this.template) {
  1368. this.template.mount(this.node, this.getTemplateScope(scope, parentScope));
  1369. this.template.children = moveSlotInnerContent(this.node);
  1370. }
  1371. removeNode(this.node);
  1372. return this;
  1373. },
  1374. update(scope, parentScope) {
  1375. if (this.template) {
  1376. this.template.update(this.getTemplateScope(scope, parentScope));
  1377. }
  1378. return this;
  1379. },
  1380. unmount(scope, parentScope, mustRemoveRoot) {
  1381. if (this.template) {
  1382. this.template.unmount(this.getTemplateScope(scope, parentScope), null, mustRemoveRoot);
  1383. }
  1384. return this;
  1385. }
  1386. });
  1387. /**
  1388. * Move the inner content of the slots outside of them
  1389. * @param {HTMLNode} slot - slot node
  1390. * @param {HTMLElement} children - array to fill with the child nodes detected
  1391. * @returns {HTMLElement[]} list of the node moved
  1392. */
  1393. function moveSlotInnerContent(slot, children) {
  1394. if (children === void 0) {
  1395. children = [];
  1396. }
  1397. const child = slot.firstChild;
  1398. if (child) {
  1399. slot.parentNode.insertBefore(child, slot);
  1400. return [child, ...moveSlotInnerContent(slot)];
  1401. }
  1402. return children;
  1403. }
  1404. /**
  1405. * Create a single slot binding
  1406. * @param {HTMLElement} node - slot node
  1407. * @param {string} options.name - slot id
  1408. * @returns {Object} Slot binding object
  1409. */
  1410. function createSlot(node, _ref9) {
  1411. let {
  1412. name,
  1413. attributes
  1414. } = _ref9;
  1415. return Object.assign({}, SlotBinding, {
  1416. attributes,
  1417. node,
  1418. name
  1419. });
  1420. }
  1421. /**
  1422. * Create a new tag object if it was registered before, otherwise fallback to the simple
  1423. * template chunk
  1424. * @param {Function} component - component factory function
  1425. * @param {Array<Object>} slots - array containing the slots markup
  1426. * @param {Array} attributes - dynamic attributes that will be received by the tag element
  1427. * @returns {TagImplementation|TemplateChunk} a tag implementation or a template chunk as fallback
  1428. */
  1429. function getTag(component, slots, attributes) {
  1430. if (slots === void 0) {
  1431. slots = [];
  1432. }
  1433. if (attributes === void 0) {
  1434. attributes = [];
  1435. }
  1436. // if this tag was registered before we will return its implementation
  1437. if (component) {
  1438. return component({
  1439. slots,
  1440. attributes
  1441. });
  1442. } // otherwise we return a template chunk
  1443. return create$6(slotsToMarkup(slots), [...slotBindings(slots), {
  1444. // the attributes should be registered as binding
  1445. // if we fallback to a normal template chunk
  1446. expressions: attributes.map(attr => {
  1447. return Object.assign({
  1448. type: ATTRIBUTE
  1449. }, attr);
  1450. })
  1451. }]);
  1452. }
  1453. /**
  1454. * Merge all the slots bindings into a single array
  1455. * @param {Array<Object>} slots - slots collection
  1456. * @returns {Array<Bindings>} flatten bindings array
  1457. */
  1458. function slotBindings(slots) {
  1459. return slots.reduce((acc, _ref10) => {
  1460. let {
  1461. bindings
  1462. } = _ref10;
  1463. return acc.concat(bindings);
  1464. }, []);
  1465. }
  1466. /**
  1467. * Merge all the slots together in a single markup string
  1468. * @param {Array<Object>} slots - slots collection
  1469. * @returns {string} markup of all the slots in a single string
  1470. */
  1471. function slotsToMarkup(slots) {
  1472. return slots.reduce((acc, slot) => {
  1473. return acc + slot.html;
  1474. }, '');
  1475. }
  1476. const TagBinding = Object.seal({
  1477. // dynamic binding properties
  1478. // node: null,
  1479. // evaluate: null,
  1480. // name: null,
  1481. // slots: null,
  1482. // tag: null,
  1483. // attributes: null,
  1484. // getComponent: null,
  1485. mount(scope) {
  1486. return this.update(scope);
  1487. },
  1488. update(scope, parentScope) {
  1489. const name = this.evaluate(scope); // simple update
  1490. if (name === this.name) {
  1491. this.tag.update(scope);
  1492. } else {
  1493. // unmount the old tag if it exists
  1494. this.unmount(scope, parentScope, true); // mount the new tag
  1495. this.name = name;
  1496. this.tag = getTag(this.getComponent(name), this.slots, this.attributes);
  1497. this.tag.mount(this.node, scope);
  1498. }
  1499. return this;
  1500. },
  1501. unmount(scope, parentScope, keepRootTag) {
  1502. if (this.tag) {
  1503. // keep the root tag
  1504. this.tag.unmount(keepRootTag);
  1505. }
  1506. return this;
  1507. }
  1508. });
  1509. function create$4(node, _ref11) {
  1510. let {
  1511. evaluate,
  1512. getComponent,
  1513. slots,
  1514. attributes
  1515. } = _ref11;
  1516. return Object.assign({}, TagBinding, {
  1517. node,
  1518. evaluate,
  1519. slots,
  1520. attributes,
  1521. getComponent
  1522. });
  1523. }
  1524. var bindings = {
  1525. [IF]: create$1,
  1526. [SIMPLE]: create$3,
  1527. [EACH]: create,
  1528. [TAG]: create$4,
  1529. [SLOT]: createSlot
  1530. };
  1531. /**
  1532. * Text expressions in a template tag will get childNodeIndex value normalized
  1533. * depending on the position of the <template> tag offset
  1534. * @param {Expression[]} expressions - riot expressions array
  1535. * @param {number} textExpressionsOffset - offset of the <template> tag
  1536. * @returns {Expression[]} expressions containing the text expressions normalized
  1537. */
  1538. function fixTextExpressionsOffset(expressions, textExpressionsOffset) {
  1539. return expressions.map(e => e.type === TEXT ? Object.assign({}, e, {
  1540. childNodeIndex: e.childNodeIndex + textExpressionsOffset
  1541. }) : e);
  1542. }
  1543. /**
  1544. * Bind a new expression object to a DOM node
  1545. * @param {HTMLElement} root - DOM node where to bind the expression
  1546. * @param {Object} binding - binding data
  1547. * @param {number|null} templateTagOffset - if it's defined we need to fix the text expressions childNodeIndex offset
  1548. * @returns {Binding} Binding object
  1549. */
  1550. function create$5(root, binding, templateTagOffset) {
  1551. const {
  1552. selector,
  1553. type,
  1554. redundantAttribute,
  1555. expressions
  1556. } = binding; // find the node to apply the bindings
  1557. const node = selector ? root.querySelector(selector) : root; // remove eventually additional attributes created only to select this node
  1558. if (redundantAttribute) node.removeAttribute(redundantAttribute);
  1559. const bindingExpressions = expressions || []; // init the binding
  1560. return (bindings[type] || bindings[SIMPLE])(node, Object.assign({}, binding, {
  1561. expressions: templateTagOffset && !selector ? fixTextExpressionsOffset(bindingExpressions, templateTagOffset) : bindingExpressions
  1562. }));
  1563. } // in this case a simple innerHTML is enough
  1564. function createHTMLTree(html, root) {
  1565. const template = isTemplate(root) ? root : document.createElement('template');
  1566. template.innerHTML = html;
  1567. return template.content;
  1568. } // for svg nodes we need a bit more work
  1569. function createSVGTree(html, container) {
  1570. // create the SVGNode
  1571. const svgNode = container.ownerDocument.importNode(new window.DOMParser().parseFromString(`<svg xmlns="http://www.w3.org/2000/svg">${html}</svg>`, 'application/xml').documentElement, true);
  1572. return svgNode;
  1573. }
  1574. /**
  1575. * Create the DOM that will be injected
  1576. * @param {Object} root - DOM node to find out the context where the fragment will be created
  1577. * @param {string} html - DOM to create as string
  1578. * @returns {HTMLDocumentFragment|HTMLElement} a new html fragment
  1579. */
  1580. function createDOMTree(root, html) {
  1581. if (isSvg(root)) return createSVGTree(html, root);
  1582. return createHTMLTree(html, root);
  1583. }
  1584. /**
  1585. * Inject the DOM tree into a target node
  1586. * @param {HTMLElement} el - target element
  1587. * @param {HTMLFragment|SVGElement} dom - dom tree to inject
  1588. * @returns {undefined}
  1589. */
  1590. function injectDOM(el, dom) {
  1591. switch (true) {
  1592. case isSvg(el):
  1593. moveChildren(dom, el);
  1594. break;
  1595. case isTemplate(el):
  1596. el.parentNode.replaceChild(dom, el);
  1597. break;
  1598. default:
  1599. el.appendChild(dom);
  1600. }
  1601. }
  1602. /**
  1603. * Create the Template DOM skeleton
  1604. * @param {HTMLElement} el - root node where the DOM will be injected
  1605. * @param {string} html - markup that will be injected into the root node
  1606. * @returns {HTMLFragment} fragment that will be injected into the root node
  1607. */
  1608. function createTemplateDOM(el, html) {
  1609. return html && (typeof html === 'string' ? createDOMTree(el, html) : html);
  1610. }
  1611. /**
  1612. * Template Chunk model
  1613. * @type {Object}
  1614. */
  1615. const TemplateChunk = Object.freeze({
  1616. // Static props
  1617. // bindings: null,
  1618. // bindingsData: null,
  1619. // html: null,
  1620. // isTemplateTag: false,
  1621. // fragment: null,
  1622. // children: null,
  1623. // dom: null,
  1624. // el: null,
  1625. /**
  1626. * Create the template DOM structure that will be cloned on each mount
  1627. * @param {HTMLElement} el - the root node
  1628. * @returns {TemplateChunk} self
  1629. */
  1630. createDOM(el) {
  1631. // make sure that the DOM gets created before cloning the template
  1632. this.dom = this.dom || createTemplateDOM(el, this.html);
  1633. return this;
  1634. },
  1635. // API methods
  1636. /**
  1637. * Attach the template to a DOM node
  1638. * @param {HTMLElement} el - target DOM node
  1639. * @param {*} scope - template data
  1640. * @param {*} parentScope - scope of the parent template tag
  1641. * @param {Object} meta - meta properties needed to handle the <template> tags in loops
  1642. * @returns {TemplateChunk} self
  1643. */
  1644. mount(el, scope, parentScope, meta) {
  1645. if (meta === void 0) {
  1646. meta = {};
  1647. }
  1648. if (!el) throw new Error('Please provide DOM node to mount properly your template');
  1649. if (this.el) this.unmount(scope); // <template> tags require a bit more work
  1650. // the template fragment might be already created via meta outside of this call
  1651. const {
  1652. fragment,
  1653. children,
  1654. avoidDOMInjection
  1655. } = meta; // <template> bindings of course can not have a root element
  1656. // so we check the parent node to set the query selector bindings
  1657. const {
  1658. parentNode
  1659. } = children ? children[0] : el;
  1660. const isTemplateTag = isTemplate(el);
  1661. const templateTagOffset = isTemplateTag ? Math.max(Array.from(parentNode.children).indexOf(el), 0) : null;
  1662. this.isTemplateTag = isTemplateTag; // create the DOM if it wasn't created before
  1663. this.createDOM(el);
  1664. if (this.dom) {
  1665. // create the new template dom fragment if it want already passed in via meta
  1666. this.fragment = fragment || this.dom.cloneNode(true);
  1667. } // store root node
  1668. // notice that for template tags the root note will be the parent tag
  1669. this.el = this.isTemplateTag ? parentNode : el; // create the children array only for the <template> fragments
  1670. this.children = this.isTemplateTag ? children || Array.from(this.fragment.childNodes) : null; // inject the DOM into the el only if a fragment is available
  1671. if (!avoidDOMInjection && this.fragment) injectDOM(el, this.fragment); // create the bindings
  1672. this.bindings = this.bindingsData.map(binding => create$5(this.el, binding, templateTagOffset));
  1673. this.bindings.forEach(b => b.mount(scope, parentScope));
  1674. return this;
  1675. },
  1676. /**
  1677. * Update the template with fresh data
  1678. * @param {*} scope - template data
  1679. * @param {*} parentScope - scope of the parent template tag
  1680. * @returns {TemplateChunk} self
  1681. */
  1682. update(scope, parentScope) {
  1683. this.bindings.forEach(b => b.update(scope, parentScope));
  1684. return this;
  1685. },
  1686. /**
  1687. * Remove the template from the node where it was initially mounted
  1688. * @param {*} scope - template data
  1689. * @param {*} parentScope - scope of the parent template tag
  1690. * @param {boolean|null} mustRemoveRoot - if true remove the root element,
  1691. * if false or undefined clean the root tag content, if null don't touch the DOM
  1692. * @returns {TemplateChunk} self
  1693. */
  1694. unmount(scope, parentScope, mustRemoveRoot) {
  1695. if (this.el) {
  1696. this.bindings.forEach(b => b.unmount(scope, parentScope, mustRemoveRoot));
  1697. switch (true) {
  1698. // <template> tags should be treated a bit differently
  1699. // we need to clear their children only if it's explicitly required by the caller
  1700. // via mustRemoveRoot !== null
  1701. case this.children && mustRemoveRoot !== null:
  1702. clearChildren(this.children);
  1703. break;
  1704. // remove the root node only if the mustRemoveRoot === true
  1705. case mustRemoveRoot === true:
  1706. removeNode(this.el);
  1707. break;
  1708. // otherwise we clean the node children
  1709. case mustRemoveRoot !== null:
  1710. cleanNode(this.el);
  1711. break;
  1712. }
  1713. this.el = null;
  1714. }
  1715. return this;
  1716. },
  1717. /**
  1718. * Clone the template chunk
  1719. * @returns {TemplateChunk} a clone of this object resetting the this.el property
  1720. */
  1721. clone() {
  1722. return Object.assign({}, this, {
  1723. el: null
  1724. });
  1725. }
  1726. });
  1727. /**
  1728. * Create a template chunk wiring also the bindings
  1729. * @param {string|HTMLElement} html - template string
  1730. * @param {Array} bindings - bindings collection
  1731. * @returns {TemplateChunk} a new TemplateChunk copy
  1732. */
  1733. function create$6(html, bindings) {
  1734. if (bindings === void 0) {
  1735. bindings = [];
  1736. }
  1737. return Object.assign({}, TemplateChunk, {
  1738. html,
  1739. bindingsData: bindings
  1740. });
  1741. }
  1742. /**
  1743. * Helper function to set an immutable property
  1744. * @param {Object} source - object where the new property will be set
  1745. * @param {string} key - object key where the new property will be stored
  1746. * @param {*} value - value of the new property
  1747. * @param {Object} options - set the propery overriding the default options
  1748. * @returns {Object} - the original object modified
  1749. */
  1750. function defineProperty(source, key, value, options) {
  1751. if (options === void 0) {
  1752. options = {};
  1753. }
  1754. /* eslint-disable fp/no-mutating-methods */
  1755. Object.defineProperty(source, key, Object.assign({
  1756. value,
  1757. enumerable: false,
  1758. writable: false,
  1759. configurable: true
  1760. }, options));
  1761. /* eslint-enable fp/no-mutating-methods */
  1762. return source;
  1763. }
  1764. /**
  1765. * Define multiple properties on a target object
  1766. * @param {Object} source - object where the new properties will be set
  1767. * @param {Object} properties - object containing as key pair the key + value properties
  1768. * @param {Object} options - set the propery overriding the default options
  1769. * @returns {Object} the original object modified
  1770. */
  1771. function defineProperties(source, properties, options) {
  1772. Object.entries(properties).forEach((_ref) => {
  1773. let [key, value] = _ref;
  1774. defineProperty(source, key, value, options);
  1775. });
  1776. return source;
  1777. }
  1778. /**
  1779. * Define default properties if they don't exist on the source object
  1780. * @param {Object} source - object that will receive the default properties
  1781. * @param {Object} defaults - object containing additional optional keys
  1782. * @returns {Object} the original object received enhanced
  1783. */
  1784. function defineDefaults(source, defaults) {
  1785. Object.entries(defaults).forEach((_ref2) => {
  1786. let [key, value] = _ref2;
  1787. if (!source[key]) source[key] = value;
  1788. });
  1789. return source;
  1790. }
  1791. const ATTRIBUTE$1 = 0;
  1792. const VALUE$1 = 3;
  1793. /**
  1794. * Convert a string from camel case to dash-case
  1795. * @param {string} string - probably a component tag name
  1796. * @returns {string} component name normalized
  1797. */
  1798. function camelToDashCase(string) {
  1799. return string.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
  1800. }
  1801. /**
  1802. * Convert a string containing dashes to camel case
  1803. * @param {string} string - input string
  1804. * @returns {string} my-string -> myString
  1805. */
  1806. function dashToCamelCase$1(string) {
  1807. return string.replace(/-(\w)/g, (_, c) => c.toUpperCase());
  1808. }
  1809. /**
  1810. * Throw an error with a descriptive message
  1811. * @param { string } message - error message
  1812. * @returns { undefined } hoppla.. at this point the program should stop working
  1813. */
  1814. function panic(message) {
  1815. throw new Error(message);
  1816. }
  1817. /**
  1818. * Evaluate a list of attribute expressions
  1819. * @param {Array} attributes - attribute expressions generated by the riot compiler
  1820. * @returns {Object} key value pairs with the result of the computation
  1821. */
  1822. function evaluateAttributeExpressions$1(attributes) {
  1823. return attributes.reduce((acc, attribute) => {
  1824. const {
  1825. value,
  1826. type
  1827. } = attribute;
  1828. switch (true) {
  1829. // spread attribute
  1830. case !attribute.name && type === ATTRIBUTE$1:
  1831. return Object.assign({}, acc, {}, value);
  1832. // value attribute
  1833. case type === VALUE$1:
  1834. acc.value = attribute.value;
  1835. break;
  1836. // normal attributes
  1837. default:
  1838. acc[dashToCamelCase$1(attribute.name)] = attribute.value;
  1839. }
  1840. return acc;
  1841. }, {});
  1842. }
  1843. /**
  1844. * Converts any DOM node/s to a loopable array
  1845. * @param { HTMLElement|NodeList } els - single html element or a node list
  1846. * @returns { Array } always a loopable object
  1847. */
  1848. function domToArray(els) {
  1849. // can this object be already looped?
  1850. if (!Array.isArray(els)) {
  1851. // is it a node list?
  1852. if (/^\[object (HTMLCollection|NodeList|Object)\]$/.test(Object.prototype.toString.call(els)) && typeof els.length === 'number') return Array.from(els);else // if it's a single node
  1853. // it will be returned as "array" with one single entry
  1854. return [els];
  1855. } // this object could be looped out of the box
  1856. return els;
  1857. }
  1858. /**
  1859. * Simple helper to find DOM nodes returning them as array like loopable object
  1860. * @param { string|DOMNodeList } selector - either the query or the DOM nodes to arraify
  1861. * @param { HTMLElement } ctx - context defining where the query will search for the DOM nodes
  1862. * @returns { Array } DOM nodes found as array
  1863. */
  1864. function $(selector, ctx) {
  1865. return domToArray(typeof selector === 'string' ? (ctx || document).querySelectorAll(selector) : selector);
  1866. }
  1867. /**
  1868. * Normalize the return values, in case of a single value we avoid to return an array
  1869. * @param { Array } values - list of values we want to return
  1870. * @returns { Array|string|boolean } either the whole list of values or the single one found
  1871. * @private
  1872. */
  1873. const normalize = values => values.length === 1 ? values[0] : values;
  1874. /**
  1875. * Parse all the nodes received to get/remove/check their attributes
  1876. * @param { HTMLElement|NodeList|Array } els - DOM node/s to parse
  1877. * @param { string|Array } name - name or list of attributes
  1878. * @param { string } method - method that will be used to parse the attributes
  1879. * @returns { Array|string } result of the parsing in a list or a single value
  1880. * @private
  1881. */
  1882. function parseNodes(els, name, method) {
  1883. const names = typeof name === 'string' ? [name] : name;
  1884. return normalize(domToArray(els).map(el => {
  1885. return normalize(names.map(n => el[method](n)));
  1886. }));
  1887. }
  1888. /**
  1889. * Set any attribute on a single or a list of DOM nodes
  1890. * @param { HTMLElement|NodeList|Array } els - DOM node/s to parse
  1891. * @param { string|Object } name - either the name of the attribute to set
  1892. * or a list of properties as object key - value
  1893. * @param { string } value - the new value of the attribute (optional)
  1894. * @returns { HTMLElement|NodeList|Array } the original array of elements passed to this function
  1895. *
  1896. * @example
  1897. *
  1898. * import { set } from 'bianco.attr'
  1899. *
  1900. * const img = document.createElement('img')
  1901. *
  1902. * set(img, 'width', 100)
  1903. *
  1904. * // or also
  1905. * set(img, {
  1906. * width: 300,
  1907. * height: 300
  1908. * })
  1909. *
  1910. */
  1911. function set(els, name, value) {
  1912. const attrs = typeof name === 'object' ? name : {
  1913. [name]: value
  1914. };
  1915. const props = Object.keys(attrs);
  1916. domToArray(els).forEach(el => {
  1917. props.forEach(prop => el.setAttribute(prop, attrs[prop]));
  1918. });
  1919. return els;
  1920. }
  1921. /**
  1922. * Get any attribute from a single or a list of DOM nodes
  1923. * @param { HTMLElement|NodeList|Array } els - DOM node/s to parse
  1924. * @param { string|Array } name - name or list of attributes to get
  1925. * @returns { Array|string } list of the attributes found
  1926. *
  1927. * @example
  1928. *
  1929. * import { get } from 'bianco.attr'
  1930. *
  1931. * const img = document.createElement('img')
  1932. *
  1933. * get(img, 'width') // => '200'
  1934. *
  1935. * // or also
  1936. * get(img, ['width', 'height']) // => ['200', '300']
  1937. *
  1938. * // or also
  1939. * get([img1, img2], ['width', 'height']) // => [['200', '300'], ['500', '200']]
  1940. */
  1941. function get(els, name) {
  1942. return parseNodes(els, name, 'getAttribute');
  1943. }
  1944. const CSS_BY_NAME = new Map();
  1945. const STYLE_NODE_SELECTOR = 'style[riot]'; // memoized curried function
  1946. const getStyleNode = (style => {
  1947. return () => {
  1948. // lazy evaluation:
  1949. // if this function was already called before
  1950. // we return its cached result
  1951. if (style) return style; // create a new style element or use an existing one
  1952. // and cache it internally
  1953. style = $(STYLE_NODE_SELECTOR)[0] || document.createElement('style');
  1954. set(style, 'type', 'text/css');
  1955. /* istanbul ignore next */
  1956. if (!style.parentNode) document.head.appendChild(style);
  1957. return style;
  1958. };
  1959. })();
  1960. /**
  1961. * Object that will be used to inject and manage the css of every tag instance
  1962. */
  1963. var cssManager = {
  1964. CSS_BY_NAME,
  1965. /**
  1966. * Save a tag style to be later injected into DOM
  1967. * @param { string } name - if it's passed we will map the css to a tagname
  1968. * @param { string } css - css string
  1969. * @returns {Object} self
  1970. */
  1971. add(name, css) {
  1972. if (!CSS_BY_NAME.has(name)) {
  1973. CSS_BY_NAME.set(name, css);
  1974. this.inject();
  1975. }
  1976. return this;
  1977. },
  1978. /**
  1979. * Inject all previously saved tag styles into DOM
  1980. * innerHTML seems slow: http://jsperf.com/riot-insert-style
  1981. * @returns {Object} self
  1982. */
  1983. inject() {
  1984. getStyleNode().innerHTML = [...CSS_BY_NAME.values()].join('\n');
  1985. return this;
  1986. },
  1987. /**
  1988. * Remove a tag style from the DOM
  1989. * @param {string} name a registered tagname
  1990. * @returns {Object} self
  1991. */
  1992. remove(name) {
  1993. if (CSS_BY_NAME.has(name)) {
  1994. CSS_BY_NAME.delete(name);
  1995. this.inject();
  1996. }
  1997. return this;
  1998. }
  1999. };
  2000. /**
  2001. * Function to curry any javascript method
  2002. * @param {Function} fn - the target function we want to curry
  2003. * @param {...[args]} acc - initial arguments
  2004. * @returns {Function|*} it will return a function until the target function
  2005. * will receive all of its arguments
  2006. */
  2007. function curry(fn) {
  2008. for (var _len = arguments.length, acc = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
  2009. acc[_key - 1] = arguments[_key];
  2010. }
  2011. return function () {
  2012. for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
  2013. args[_key2] = arguments[_key2];
  2014. }
  2015. args = [...acc, ...args];
  2016. return args.length < fn.length ? curry(fn, ...args) : fn(...args);
  2017. };
  2018. }
  2019. /**
  2020. * Get the tag name of any DOM node
  2021. * @param {HTMLElement} element - DOM node we want to inspect
  2022. * @returns {string} name to identify this dom node in riot
  2023. */
  2024. function getName(element) {
  2025. return get(element, IS_DIRECTIVE) || element.tagName.toLowerCase();
  2026. }
  2027. const COMPONENT_CORE_HELPERS = Object.freeze({
  2028. // component helpers
  2029. $(selector) {
  2030. return $(selector, this.root)[0];
  2031. },
  2032. $$(selector) {
  2033. return $(selector, this.root);
  2034. }
  2035. });
  2036. const PURE_COMPONENT_API = Object.freeze({
  2037. [MOUNT_METHOD_KEY]: noop,
  2038. [UPDATE_METHOD_KEY]: noop,
  2039. [UNMOUNT_METHOD_KEY]: noop
  2040. });
  2041. const COMPONENT_LIFECYCLE_METHODS = Object.freeze({
  2042. [SHOULD_UPDATE_KEY]: noop,
  2043. [ON_BEFORE_MOUNT_KEY]: noop,
  2044. [ON_MOUNTED_KEY]: noop,
  2045. [ON_BEFORE_UPDATE_KEY]: noop,
  2046. [ON_UPDATED_KEY]: noop,
  2047. [ON_BEFORE_UNMOUNT_KEY]: noop,
  2048. [ON_UNMOUNTED_KEY]: noop
  2049. });
  2050. const MOCKED_TEMPLATE_INTERFACE = Object.assign({}, PURE_COMPONENT_API, {
  2051. clone: noop,
  2052. createDOM: noop
  2053. });
  2054. /**
  2055. * Wrap the Riot.js core API methods using a mapping function
  2056. * @param {Function} mapFunction - lifting function
  2057. * @returns {Object} an object having the { mount, update, unmount } functions
  2058. */
  2059. function createCoreAPIMethods(mapFunction) {
  2060. return [MOUNT_METHOD_KEY, UPDATE_METHOD_KEY, UNMOUNT_METHOD_KEY].reduce((acc, method) => {
  2061. acc[method] = mapFunction(method);
  2062. return acc;
  2063. }, {});
  2064. }
  2065. /**
  2066. * Factory function to create the component templates only once
  2067. * @param {Function} template - component template creation function
  2068. * @param {Object} components - object containing the nested components
  2069. * @returns {TemplateChunk} template chunk object
  2070. */
  2071. function componentTemplateFactory(template, components) {
  2072. return template(create$6, expressionTypes, bindingTypes, name => {
  2073. return components[name] || COMPONENTS_IMPLEMENTATION_MAP.get(name);
  2074. });
  2075. }
  2076. /**
  2077. * Create a pure component
  2078. * @param {Function} pureFactoryFunction - pure component factory function
  2079. * @param {Array} options.slots - component slots
  2080. * @param {Array} options.attributes - component attributes
  2081. * @param {Array} options.template - template factory function
  2082. * @param {Array} options.template - template factory function
  2083. * @param {any} options.props - initial component properties
  2084. * @returns {Object} pure component object
  2085. */
  2086. function createPureComponent(pureFactoryFunction, _ref) {
  2087. let {
  2088. slots,
  2089. attributes,
  2090. props,
  2091. css,
  2092. template
  2093. } = _ref;
  2094. if (template) panic('Pure components can not have html');
  2095. if (css) panic('Pure components do not have css');
  2096. const component = defineDefaults(pureFactoryFunction({
  2097. slots,
  2098. attributes,
  2099. props
  2100. }), PURE_COMPONENT_API);
  2101. return createCoreAPIMethods(method => function () {
  2102. component[method](...arguments);
  2103. return component;
  2104. });
  2105. }
  2106. /**
  2107. * Create the component interface needed for the @riotjs/dom-bindings tag bindings
  2108. * @param {string} options.css - component css
  2109. * @param {Function} options.template - functon that will return the dom-bindings template function
  2110. * @param {Object} options.exports - component interface
  2111. * @param {string} options.name - component name
  2112. * @returns {Object} component like interface
  2113. */
  2114. function createComponent(_ref2) {
  2115. let {
  2116. css,
  2117. template,
  2118. exports,
  2119. name
  2120. } = _ref2;
  2121. const templateFn = template ? componentTemplateFactory(template, exports ? createSubcomponents(exports.components) : {}) : MOCKED_TEMPLATE_INTERFACE;
  2122. return (_ref3) => {
  2123. let {
  2124. slots,
  2125. attributes,
  2126. props
  2127. } = _ref3;
  2128. // pure components rendering will be managed by the end user
  2129. if (exports && exports[IS_PURE_SYMBOL]) return createPureComponent(exports, {
  2130. slots,
  2131. attributes,
  2132. props,
  2133. css,
  2134. template
  2135. });
  2136. const componentAPI = callOrAssign(exports) || {};
  2137. const component = defineComponent({
  2138. css,
  2139. template: templateFn,
  2140. componentAPI,
  2141. name
  2142. })({
  2143. slots,
  2144. attributes,
  2145. props
  2146. }); // notice that for the components create via tag binding
  2147. // we need to invert the mount (state/parentScope) arguments
  2148. // the template bindings will only forward the parentScope updates
  2149. // and never deal with the component state
  2150. return {
  2151. mount(element, parentScope, state) {
  2152. return component.mount(element, state, parentScope);
  2153. },
  2154. update(parentScope, state) {
  2155. return component.update(state, parentScope);
  2156. },
  2157. unmount(preserveRoot) {
  2158. return component.unmount(preserveRoot);
  2159. }
  2160. };
  2161. };
  2162. }
  2163. /**
  2164. * Component definition function
  2165. * @param {Object} implementation - the componen implementation will be generated via compiler
  2166. * @param {Object} component - the component initial properties
  2167. * @returns {Object} a new component implementation object
  2168. */
  2169. function defineComponent(_ref4) {
  2170. let {
  2171. css,
  2172. template,
  2173. componentAPI,
  2174. name
  2175. } = _ref4;
  2176. // add the component css into the DOM
  2177. if (css && name) cssManager.add(name, css);
  2178. return curry(enhanceComponentAPI)(defineProperties( // set the component defaults without overriding the original component API
  2179. defineDefaults(componentAPI, Object.assign({}, COMPONENT_LIFECYCLE_METHODS, {
  2180. [STATE_KEY]: {}
  2181. })), Object.assign({
  2182. // defined during the component creation
  2183. [SLOTS_KEY]: null,
  2184. [ROOT_KEY]: null
  2185. }, COMPONENT_CORE_HELPERS, {
  2186. name,
  2187. css,
  2188. template
  2189. })));
  2190. }
  2191. /**
  2192. * Create the bindings to update the component attributes
  2193. * @param {HTMLElement} node - node where we will bind the expressions
  2194. * @param {Array} attributes - list of attribute bindings
  2195. * @returns {TemplateChunk} - template bindings object
  2196. */
  2197. function createAttributeBindings(node, attributes) {
  2198. if (attributes === void 0) {
  2199. attributes = [];
  2200. }
  2201. const expressions = attributes.map(a => create$2(node, a));
  2202. const binding = {};
  2203. return Object.assign(binding, Object.assign({
  2204. expressions
  2205. }, createCoreAPIMethods(method => scope => {
  2206. expressions.forEach(e => e[method](scope));
  2207. return binding;
  2208. })));
  2209. }
  2210. /**
  2211. * Create the subcomponents that can be included inside a tag in runtime
  2212. * @param {Object} components - components imported in runtime
  2213. * @returns {Object} all the components transformed into Riot.Component factory functions
  2214. */
  2215. function createSubcomponents(components) {
  2216. if (components === void 0) {
  2217. components = {};
  2218. }
  2219. return Object.entries(callOrAssign(components)).reduce((acc, _ref5) => {
  2220. let [key, value] = _ref5;
  2221. acc[camelToDashCase(key)] = createComponent(value);
  2222. return acc;
  2223. }, {});
  2224. }
  2225. /**
  2226. * Run the component instance through all the plugins set by the user
  2227. * @param {Object} component - component instance
  2228. * @returns {Object} the component enhanced by the plugins
  2229. */
  2230. function runPlugins(component) {
  2231. return [...PLUGINS_SET].reduce((c, fn) => fn(c) || c, component);
  2232. }
  2233. /**
  2234. * Compute the component current state merging it with its previous state
  2235. * @param {Object} oldState - previous state object
  2236. * @param {Object} newState - new state givent to the `update` call
  2237. * @returns {Object} new object state
  2238. */
  2239. function computeState(oldState, newState) {
  2240. return Object.assign({}, oldState, {}, callOrAssign(newState));
  2241. }
  2242. /**
  2243. * Add eventually the "is" attribute to link this DOM node to its css
  2244. * @param {HTMLElement} element - target root node
  2245. * @param {string} name - name of the component mounted
  2246. * @returns {undefined} it's a void function
  2247. */
  2248. function addCssHook(element, name) {
  2249. if (getName(element) !== name) {
  2250. set(element, IS_DIRECTIVE, name);
  2251. }
  2252. }
  2253. /**
  2254. * Component creation factory function that will enhance the user provided API
  2255. * @param {Object} component - a component implementation previously defined
  2256. * @param {Array} options.slots - component slots generated via riot compiler
  2257. * @param {Array} options.attributes - attribute expressions generated via riot compiler
  2258. * @returns {Riot.Component} a riot component instance
  2259. */
  2260. function enhanceComponentAPI(component, _ref6) {
  2261. let {
  2262. slots,
  2263. attributes,
  2264. props
  2265. } = _ref6;
  2266. return autobindMethods(runPlugins(defineProperties(Object.create(component), {
  2267. mount(element, state, parentScope) {
  2268. if (state === void 0) {
  2269. state = {};
  2270. }
  2271. this[ATTRIBUTES_KEY_SYMBOL] = createAttributeBindings(element, attributes).mount(parentScope);
  2272. defineProperty(this, PROPS_KEY, Object.freeze(Object.assign({}, props, {}, evaluateAttributeExpressions$1(this[ATTRIBUTES_KEY_SYMBOL].expressions))));
  2273. this[STATE_KEY] = computeState(this[STATE_KEY], state);
  2274. this[TEMPLATE_KEY_SYMBOL] = this.template.createDOM(element).clone(); // link this object to the DOM node
  2275. element[DOM_COMPONENT_INSTANCE_PROPERTY] = this; // add eventually the 'is' attribute
  2276. component.name && addCssHook(element, component.name); // define the root element
  2277. defineProperty(this, ROOT_KEY, element); // define the slots array
  2278. defineProperty(this, SLOTS_KEY, slots); // before mount lifecycle event
  2279. this[ON_BEFORE_MOUNT_KEY](this[PROPS_KEY], this[STATE_KEY]); // mount the template
  2280. this[TEMPLATE_KEY_SYMBOL].mount(element, this, parentScope);
  2281. this[PARENT_KEY_SYMBOL] = parentScope;
  2282. this[ON_MOUNTED_KEY](this[PROPS_KEY], this[STATE_KEY]);
  2283. return this;
  2284. },
  2285. update(state, parentScope) {
  2286. if (state === void 0) {
  2287. state = {};
  2288. }
  2289. if (parentScope) {
  2290. this[ATTRIBUTES_KEY_SYMBOL].update(parentScope);
  2291. }
  2292. const newProps = evaluateAttributeExpressions$1(this[ATTRIBUTES_KEY_SYMBOL].expressions);
  2293. if (this[SHOULD_UPDATE_KEY](newProps, this[PROPS_KEY]) === false) return;
  2294. defineProperty(this, PROPS_KEY, Object.freeze(Object.assign({}, props, {}, newProps)));
  2295. this[STATE_KEY] = computeState(this[STATE_KEY], state);
  2296. this[ON_BEFORE_UPDATE_KEY](this[PROPS_KEY], this[STATE_KEY]);
  2297. this[TEMPLATE_KEY_SYMBOL].update(this, this[PARENT_KEY_SYMBOL]);
  2298. this[ON_UPDATED_KEY](this[PROPS_KEY], this[STATE_KEY]);
  2299. return this;
  2300. },
  2301. unmount(preserveRoot) {
  2302. this[ON_BEFORE_UNMOUNT_KEY](this[PROPS_KEY], this[STATE_KEY]);
  2303. this[ATTRIBUTES_KEY_SYMBOL].unmount(); // if the preserveRoot is null the template html will be left untouched
  2304. // in that case the DOM cleanup will happen differently from a parent node
  2305. this[TEMPLATE_KEY_SYMBOL].unmount(this, this[PARENT_KEY_SYMBOL], preserveRoot === null ? null : !preserveRoot);
  2306. this[ON_UNMOUNTED_KEY](this[PROPS_KEY], this[STATE_KEY]);
  2307. return this;
  2308. }
  2309. })), Object.keys(component).filter(prop => isFunction(component[prop])));
  2310. }
  2311. /**
  2312. * Component initialization function starting from a DOM node
  2313. * @param {HTMLElement} element - element to upgrade
  2314. * @param {Object} initialProps - initial component properties
  2315. * @param {string} componentName - component id
  2316. * @returns {Object} a new component instance bound to a DOM node
  2317. */
  2318. function mountComponent(element, initialProps, componentName) {
  2319. const name = componentName || getName(element);
  2320. if (!COMPONENTS_IMPLEMENTATION_MAP.has(name)) panic(`The component named "${name}" was never registered`);
  2321. const component = COMPONENTS_IMPLEMENTATION_MAP.get(name)({
  2322. props: initialProps
  2323. });
  2324. return component.mount(element);
  2325. }
  2326. /**
  2327. * Get all the element attributes as object
  2328. * @param {HTMLElement} element - DOM node we want to parse
  2329. * @returns {Object} all the attributes found as a key value pairs
  2330. */
  2331. function DOMattributesToObject(element) {
  2332. return Array.from(element.attributes).reduce((acc, attribute) => {
  2333. acc[dashToCamelCase$1(attribute.name)] = attribute.value;
  2334. return acc;
  2335. }, {});
  2336. }
  2337. /**
  2338. * Similar to compose but performs from left-to-right function composition.<br/>
  2339. * {@link https://30secondsofcode.org/function#composeright see also}
  2340. * @param {...[function]} fns) - list of unary function
  2341. * @returns {*} result of the computation
  2342. */
  2343. /**
  2344. * Performs right-to-left function composition.<br/>
  2345. * Use Array.prototype.reduce() to perform right-to-left function composition.<br/>
  2346. * The last (rightmost) function can accept one or more arguments; the remaining functions must be unary.<br/>
  2347. * {@link https://30secondsofcode.org/function#compose original source code}
  2348. * @param {...[function]} fns) - list of unary function
  2349. * @returns {*} result of the computation
  2350. */
  2351. function compose() {
  2352. for (var _len2 = arguments.length, fns = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
  2353. fns[_key2] = arguments[_key2];
  2354. }
  2355. return fns.reduce((f, g) => function () {
  2356. return f(g(...arguments));
  2357. });
  2358. }
  2359. const {
  2360. DOM_COMPONENT_INSTANCE_PROPERTY: DOM_COMPONENT_INSTANCE_PROPERTY$1,
  2361. COMPONENTS_IMPLEMENTATION_MAP: COMPONENTS_IMPLEMENTATION_MAP$1,
  2362. PLUGINS_SET: PLUGINS_SET$1
  2363. } = globals;
  2364. /**
  2365. * Evaluate the component properties either from its real attributes or from its initial user properties
  2366. * @param {HTMLElement} element - component root
  2367. * @param {Object} initialProps - initial props
  2368. * @returns {Object} component props key value pairs
  2369. */
  2370. function evaluateInitialProps(element, initialProps) {
  2371. if (initialProps === void 0) {
  2372. initialProps = [];
  2373. }
  2374. return Object.assign({}, DOMattributesToObject(element), {}, callOrAssign(initialProps));
  2375. }
  2376. /**
  2377. * Riot public api
  2378. */
  2379. /**
  2380. * Register a custom tag by name
  2381. * @param {string} name - component name
  2382. * @param {Object} implementation - tag implementation
  2383. * @returns {Map} map containing all the components implementations
  2384. */
  2385. function register(name, _ref) {
  2386. let {
  2387. css,
  2388. template,
  2389. exports
  2390. } = _ref;
  2391. if (COMPONENTS_IMPLEMENTATION_MAP$1.has(name)) panic(`The component "${name}" was already registered`);
  2392. COMPONENTS_IMPLEMENTATION_MAP$1.set(name, createComponent({
  2393. name,
  2394. css,
  2395. template,
  2396. exports
  2397. }));
  2398. return COMPONENTS_IMPLEMENTATION_MAP$1;
  2399. }
  2400. /**
  2401. * Unregister a riot web component
  2402. * @param {string} name - component name
  2403. * @returns {Map} map containing all the components implementations
  2404. */
  2405. function unregister(name) {
  2406. if (!COMPONENTS_IMPLEMENTATION_MAP$1.has(name)) panic(`The component "${name}" was never registered`);
  2407. COMPONENTS_IMPLEMENTATION_MAP$1.delete(name);
  2408. cssManager.remove(name);
  2409. return COMPONENTS_IMPLEMENTATION_MAP$1;
  2410. }
  2411. /**
  2412. * Mounting function that will work only for the components that were globally registered
  2413. * @param {string|HTMLElement} selector - query for the selection or a DOM element
  2414. * @param {Object} initialProps - the initial component properties
  2415. * @param {string} name - optional component name
  2416. * @returns {Array} list of nodes upgraded
  2417. */
  2418. function mount(selector, initialProps, name) {
  2419. return $(selector).map(element => mountComponent(element, evaluateInitialProps(element, initialProps), name));
  2420. }
  2421. /**
  2422. * Sweet unmounting helper function for the DOM node mounted manually by the user
  2423. * @param {string|HTMLElement} selector - query for the selection or a DOM element
  2424. * @param {boolean|null} keepRootElement - if true keep the root element
  2425. * @returns {Array} list of nodes unmounted
  2426. */
  2427. function unmount(selector, keepRootElement) {
  2428. return $(selector).map(element => {
  2429. if (element[DOM_COMPONENT_INSTANCE_PROPERTY$1]) {
  2430. element[DOM_COMPONENT_INSTANCE_PROPERTY$1].unmount(keepRootElement);
  2431. }
  2432. return element;
  2433. });
  2434. }
  2435. /**
  2436. * Define a riot plugin
  2437. * @param {Function} plugin - function that will receive all the components created
  2438. * @returns {Set} the set containing all the plugins installed
  2439. */
  2440. function install(plugin) {
  2441. if (!isFunction(plugin)) panic('Plugins must be of type function');
  2442. if (PLUGINS_SET$1.has(plugin)) panic('This plugin was already install');
  2443. PLUGINS_SET$1.add(plugin);
  2444. return PLUGINS_SET$1;
  2445. }
  2446. /**
  2447. * Uninstall a riot plugin
  2448. * @param {Function} plugin - plugin previously installed
  2449. * @returns {Set} the set containing all the plugins installed
  2450. */
  2451. function uninstall(plugin) {
  2452. if (!PLUGINS_SET$1.has(plugin)) panic('This plugin was never installed');
  2453. PLUGINS_SET$1.delete(plugin);
  2454. return PLUGINS_SET$1;
  2455. }
  2456. /**
  2457. * Helpter method to create component without relying on the registered ones
  2458. * @param {Object} implementation - component implementation
  2459. * @returns {Function} function that will allow you to mount a riot component on a DOM node
  2460. */
  2461. function component(implementation) {
  2462. return function (el, props, _temp) {
  2463. let {
  2464. slots,
  2465. attributes
  2466. } = _temp === void 0 ? {} : _temp;
  2467. return compose(c => c.mount(el), c => c({
  2468. props: evaluateInitialProps(el, props),
  2469. slots,
  2470. attributes
  2471. }), createComponent)(implementation);
  2472. };
  2473. }
  2474. /**
  2475. * Lift a riot component Interface into a pure riot object
  2476. * @param {Function} func - RiotPureComponent factory function
  2477. * @returns {Function} the lifted original function received as argument
  2478. */
  2479. function pure(func) {
  2480. if (!isFunction(func)) panic('riot.pure accepts only arguments of type "function"');
  2481. func[IS_PURE_SYMBOL] = true;
  2482. return func;
  2483. }
  2484. /** @type {string} current riot version */
  2485. const version = 'v4.8.6'; // expose some internal stuff that might be used from external tools
  2486. const __ = {
  2487. cssManager,
  2488. createComponent,
  2489. defineComponent,
  2490. globals
  2491. };
  2492. /***/ }),
  2493. /***/ "./src/TinyConsent.riot":
  2494. /*!******************************!*\
  2495. !*** ./src/TinyConsent.riot ***!
  2496. \******************************/
  2497. /*! exports provided: default */
  2498. /***/ (function(module, __webpack_exports__, __webpack_require__) {
  2499. "use strict";
  2500. __webpack_require__.r(__webpack_exports__);
  2501. /* harmony import */ var js_cookie__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! js-cookie */ "./node_modules/js-cookie/src/js.cookie.js");
  2502. /* harmony import */ var js_cookie__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(js_cookie__WEBPACK_IMPORTED_MODULE_0__);
  2503. /* harmony default export */ __webpack_exports__["default"] = ({
  2504. 'css': null,
  2505. 'exports': {
  2506. /**
  2507. *
  2508. *
  2509. */
  2510. state:
  2511. {
  2512. options: {
  2513. cookie_name: 'tiny_consent',
  2514. messages: {
  2515. 'content': 'TTATA',
  2516. 'yes': 'Yes',
  2517. 'no': 'No',
  2518. 'ok': 'Ok',
  2519. 'close': 'Close'
  2520. }
  2521. },
  2522. hasCookie: false
  2523. },
  2524. /**
  2525. *
  2526. * @return {[type]} [description]
  2527. */
  2528. getData()
  2529. {
  2530. let consent = js_cookie__WEBPACK_IMPORTED_MODULE_0___default.a.getJSON(this.state.options.cookie_name);
  2531. if (!consent) {
  2532. consent = {};
  2533. }
  2534. return consent;
  2535. },
  2536. isOk(cookie)
  2537. {
  2538. let data = this.getData();
  2539. let result = false;
  2540. if (data[cookie.id] === true) {
  2541. result = true;
  2542. }
  2543. return result;
  2544. },
  2545. getAgreeClasses(cookie)
  2546. {
  2547. let classes = [
  2548. 'button',
  2549. 'button--agree',
  2550. 'tiny-consent__button'
  2551. ];
  2552. let data = this.getData();
  2553. if (data[cookie.id] === true) {
  2554. classes.push('button--active');
  2555. }
  2556. return classes.join(' ');
  2557. },
  2558. getRejectClasses(cookie)
  2559. {
  2560. let classes = [
  2561. 'button',
  2562. 'button--reject',
  2563. 'tiny-consent__button'
  2564. ];
  2565. let data = this.getData();
  2566. if (data[cookie.id] === false) {
  2567. classes.push('button--active');
  2568. }
  2569. return classes.join(' ');
  2570. },
  2571. /**
  2572. *
  2573. *
  2574. *
  2575. *
  2576. */
  2577. onBeforeMount()
  2578. {
  2579. const data = this.getData();
  2580. if (this.props.options) {
  2581. this.state.options = Object.assign(this.state.options, this.props.options);
  2582. }
  2583. // check if consent already has set
  2584. if (data) {
  2585. this.state.hasCookie = true;
  2586. this.props.cookies.forEach((cookie) => {
  2587. if (data[cookie.id] === true || data[cookie.id] === false) {
  2588. if (data[cookie.id] === true && cookie.handleAgree) {
  2589. cookie.handleAgree();
  2590. } else if (data[cookie.id] === false && cookie.handleReject) {
  2591. cookie.handleReject();
  2592. }
  2593. }
  2594. });
  2595. }
  2596. },
  2597. /**
  2598. *
  2599. * @param {[type]} event [description]
  2600. * @return {[type]} [description]
  2601. */
  2602. handleAgree(event, cookie) {
  2603. event.preventDefault();
  2604. let data = this.getData();
  2605. if (cookie.handleAgree) {
  2606. cookie.handleAgree();
  2607. }
  2608. data[cookie.id] = true;
  2609. js_cookie__WEBPACK_IMPORTED_MODULE_0___default.a.set(this.state.options.cookie_name, data);
  2610. this.update();
  2611. },
  2612. /**
  2613. *
  2614. * @param {[type]} event [description]
  2615. * @return {[type]} [description]
  2616. */
  2617. handleReject(event, cookie) {
  2618. event.preventDefault();
  2619. let data = this.getData();
  2620. if (cookie.handleReject) {
  2621. cookie.handleReject();
  2622. }
  2623. data[cookie.id] = false;
  2624. js_cookie__WEBPACK_IMPORTED_MODULE_0___default.a.set(this.state.options.cookie_name, data);
  2625. this.update();
  2626. },
  2627. /**
  2628. *
  2629. * @param {[type]} event [description]
  2630. * @return {[type]} [description]
  2631. */
  2632. handleOk(event, cookie) {
  2633. event.preventDefault();
  2634. let data = this.getData();
  2635. data[cookie.id] = true;
  2636. js_cookie__WEBPACK_IMPORTED_MODULE_0___default.a.set(this.state.options.cookie_name, data);
  2637. this.update();
  2638. },
  2639. /**
  2640. *
  2641. * @param {[type]} event [description]
  2642. * @return {[type]} [description]
  2643. */
  2644. handleClose(event) {
  2645. event.preventDefault();
  2646. }
  2647. },
  2648. 'template': function(template, expressionTypes, bindingTypes, getComponent) {
  2649. return template(
  2650. '<div class="tiny-consent"><div class="tiny-consent__banner"><div expr0="expr0" class="tiny-consent__content"><p expr1="expr1"> </p><ul class="tiny-consent__cookies"><li expr2="expr2"></li></ul><div class="tiny-consent__close"><button expr8="expr8" class="button button--submit tiny-consent__button"> </button></div></div></div></div>',
  2651. [{
  2652. 'redundantAttribute': 'expr0',
  2653. 'selector': '[expr0]',
  2654. 'expressions': [{
  2655. 'type': expressionTypes.ATTRIBUTE,
  2656. 'name': 'show',
  2657. 'evaluate': function(scope) {
  2658. return scope.state.hasCookie === false;
  2659. }
  2660. }]
  2661. }, {
  2662. 'redundantAttribute': 'expr1',
  2663. 'selector': '[expr1]',
  2664. 'expressions': [{
  2665. 'type': expressionTypes.TEXT,
  2666. 'childNodeIndex': 0,
  2667. 'evaluate': function(scope) {
  2668. return [scope.state.options.messages.content].join('');
  2669. }
  2670. }]
  2671. }, {
  2672. 'type': bindingTypes.EACH,
  2673. 'getKey': null,
  2674. 'condition': null,
  2675. 'template': template(
  2676. '<div class="tiny-consent__cookie-content"><p expr3="expr3"> </p><p expr4="expr4" class="tiny-consent__cookie-small"></p></div><div class="tiny-consent__cookie-decision"><button expr5="expr5"></button><button expr6="expr6"></button><button expr7="expr7" class="button button--ok tiny-consent__button"></button></div>',
  2677. [{
  2678. 'redundantAttribute': 'expr3',
  2679. 'selector': '[expr3]',
  2680. 'expressions': [{
  2681. 'type': expressionTypes.TEXT,
  2682. 'childNodeIndex': 0,
  2683. 'evaluate': function(scope) {
  2684. return [scope.cookie.content].join('');
  2685. }
  2686. }]
  2687. }, {
  2688. 'type': bindingTypes.IF,
  2689. 'evaluate': function(scope) {
  2690. return scope.cookie.names;
  2691. },
  2692. 'redundantAttribute': 'expr4',
  2693. 'selector': '[expr4]',
  2694. 'template': template(null, [{
  2695. 'expressions': [{
  2696. 'type': expressionTypes.ATTRIBUTE,
  2697. 'name': 'class',
  2698. 'evaluate': function(scope) {
  2699. return 'tiny-consent__cookie-small';
  2700. }
  2701. }]
  2702. }])
  2703. }, {
  2704. 'type': bindingTypes.IF,
  2705. 'evaluate': function(scope) {
  2706. return !scope.cookie.essential;
  2707. },
  2708. 'redundantAttribute': 'expr5',
  2709. 'selector': '[expr5]',
  2710. 'template': template(' ', [{
  2711. 'expressions': [{
  2712. 'type': expressionTypes.TEXT,
  2713. 'childNodeIndex': 0,
  2714. 'evaluate': function(scope) {
  2715. return [scope.state.options.messages.yes].join('');
  2716. }
  2717. }, {
  2718. 'type': expressionTypes.ATTRIBUTE,
  2719. 'name': 'class',
  2720. 'evaluate': function(scope) {
  2721. return scope.getAgreeClasses(scope.cookie);
  2722. }
  2723. }, {
  2724. 'type': expressionTypes.EVENT,
  2725. 'name': 'onclick',
  2726. 'evaluate': function(scope) {
  2727. return (event) => { scope.handleAgree(event, scope.cookie) };
  2728. }
  2729. }]
  2730. }])
  2731. }, {
  2732. 'type': bindingTypes.IF,
  2733. 'evaluate': function(scope) {
  2734. return !scope.cookie.essential;
  2735. },
  2736. 'redundantAttribute': 'expr6',
  2737. 'selector': '[expr6]',
  2738. 'template': template(' ', [{
  2739. 'expressions': [{
  2740. 'type': expressionTypes.TEXT,
  2741. 'childNodeIndex': 0,
  2742. 'evaluate': function(scope) {
  2743. return [scope.state.options.messages.no].join('');
  2744. }
  2745. }, {
  2746. 'type': expressionTypes.ATTRIBUTE,
  2747. 'name': 'class',
  2748. 'evaluate': function(scope) {
  2749. return scope.getRejectClasses(scope.cookie);
  2750. }
  2751. }, {
  2752. 'type': expressionTypes.EVENT,
  2753. 'name': 'onclick',
  2754. 'evaluate': function(scope) {
  2755. return (event) => { scope.handleReject(event, scope.cookie) };
  2756. }
  2757. }]
  2758. }])
  2759. }, {
  2760. 'type': bindingTypes.IF,
  2761. 'evaluate': function(scope) {
  2762. return scope.cookie.essential;
  2763. },
  2764. 'redundantAttribute': 'expr7',
  2765. 'selector': '[expr7]',
  2766. 'template': template(' ', [{
  2767. 'expressions': [{
  2768. 'type': expressionTypes.TEXT,
  2769. 'childNodeIndex': 0,
  2770. 'evaluate': function(scope) {
  2771. return [scope.state.options.messages.ok].join('');
  2772. }
  2773. }, {
  2774. 'type': expressionTypes.ATTRIBUTE,
  2775. 'name': 'disabled',
  2776. 'evaluate': function(scope) {
  2777. return scope.isOk(scope.cookie) === true;
  2778. }
  2779. }, {
  2780. 'type': expressionTypes.ATTRIBUTE,
  2781. 'name': 'class',
  2782. 'evaluate': function(scope) {
  2783. return 'button button--ok tiny-consent__button';
  2784. }
  2785. }, {
  2786. 'type': expressionTypes.EVENT,
  2787. 'name': 'onclick',
  2788. 'evaluate': function(scope) {
  2789. return (event) => { scope.handleOk(event, scope.cookie) };
  2790. }
  2791. }]
  2792. }])
  2793. }]
  2794. ),
  2795. 'redundantAttribute': 'expr2',
  2796. 'selector': '[expr2]',
  2797. 'itemName': 'cookie',
  2798. 'indexName': null,
  2799. 'evaluate': function(scope) {
  2800. return scope.props.cookies;
  2801. }
  2802. }, {
  2803. 'redundantAttribute': 'expr8',
  2804. 'selector': '[expr8]',
  2805. 'expressions': [{
  2806. 'type': expressionTypes.TEXT,
  2807. 'childNodeIndex': 0,
  2808. 'evaluate': function(scope) {
  2809. return [scope.state.options.messages.close].join('');
  2810. }
  2811. }, {
  2812. 'type': expressionTypes.EVENT,
  2813. 'name': 'onclick',
  2814. 'evaluate': function(scope) {
  2815. return scope.handleClose;
  2816. }
  2817. }]
  2818. }]
  2819. );
  2820. },
  2821. 'name': 'tiny-consent'
  2822. });
  2823. /***/ }),
  2824. /***/ 0:
  2825. /*!***********************!*\
  2826. !*** multi ./demo.js ***!
  2827. \***********************/
  2828. /*! no static exports found */
  2829. /***/ (function(module, exports, __webpack_require__) {
  2830. module.exports = __webpack_require__(/*! /home/herrhase/Workspace/tentakelfabrik/tiny-components/tiny-consent/demo.js */"./demo.js");
  2831. /***/ })
  2832. /******/ });