{"tag":"js","articles":{"projects\/compass":{"key":"projects\/compass","type":"article","published":true,"meta":{"createdAt":"2021-09-21T18:39:26+02:00","publishedAt":"2021-09-21T18:39:26+02:00","group":null,"links":[{"icon":"globe-europe","colour":"primary","url":"https:\/\/compass.avris.it","displayUrl":null}],"category":"projects","subcategory":null,"slug":"compass"},"content":{"en":{"slug":"compass","title":"Compass","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/compass_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022240\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAASCAYAAAAzI3woAAAACXBIWXMAAA7EAAAOxAGVKw4bAAABjklEQVRIie2VsW7bMBRFD+lHUYo9xC4stHO3jjbQfwn6J\/mH\/EqQJb\/Q0VvXLu7mwraMwhQrhexgWHAMW2niFG6B3kWXlPh48Q5EqtFoFDmTlFLEGB95UUqdK08TZNdroEn5XL\/7fC0v+8VfGuol\/pD+bmSHWpkoRSoXoHSz8KzIPr1\/Q\/fjNfdfbgnLKc45QghovQnovWe5XLbWeFVkdxc\/ubq84a1NqPOcJEnI85zVakWv12M6nTKZTFprtGkfmRqPxzHG2Lz4HS8i1HXdzO2fJaf4J5ENh0OstWitKcsSEWm+ERG891hrERHW6zUigjGGoiiYz+ettQ\/5J5GFEDDGkKYpxpimOyEE6romTVOSJEFrTb\/fR0RwzjEYDMiyjKqqmM1mrXvsSrbpjmEyxmzYKkUIAWstMUayLMM5R7fbpSzLTTH9wId337n\/7DZjEUIIjzpwMrLFYkFRFHQ6Haqqajq0u9n2r1NK8e3rih+uc7QDJyPz3h8c789vtUY45az9f5f923fZc\/2fQPYLjswi+C4BgWwAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/compass_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022240\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EAnswer a bunch of very random questions, see where that puts you on the political compass, and share the results with friends \ud83d\ude09\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/compass_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022480\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAASCAYAAAAzI3woAAAACXBIWXMAAA7EAAAOxAGVKw4bAAABjklEQVRIie2VsW7bMBRFD+lHUYo9xC4stHO3jjbQfwn6J\/mH\/EqQJb\/Q0VvXLu7mwraMwhQrhexgWHAMW2niFG6B3kWXlPh48Q5EqtFoFDmTlFLEGB95UUqdK08TZNdroEn5XL\/7fC0v+8VfGuol\/pD+bmSHWpkoRSoXoHSz8KzIPr1\/Q\/fjNfdfbgnLKc45QghovQnovWe5XLbWeFVkdxc\/ubq84a1NqPOcJEnI85zVakWv12M6nTKZTFprtGkfmRqPxzHG2Lz4HS8i1HXdzO2fJaf4J5ENh0OstWitKcsSEWm+ERG891hrERHW6zUigjGGoiiYz+ettQ\/5J5GFEDDGkKYpxpimOyEE6romTVOSJEFrTb\/fR0RwzjEYDMiyjKqqmM1mrXvsSrbpjmEyxmzYKkUIAWstMUayLMM5R7fbpSzLTTH9wId337n\/7DZjEUIIjzpwMrLFYkFRFHQ6Haqqajq0u9n2r1NK8e3rih+uc7QDJyPz3h8c789vtUY45az9f5f923fZc\/2fQPYLjswi+C4BgWwAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/compass_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022480\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EAnswer a bunch of very random questions, see where that puts you on the political compass, and share the results with friends \ud83d\ude09\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["compass","political","politics","left","right","axis","js","vuejs"],"hasMore":false,"image":"https:\/\/avris.it\/image\/compass_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/compass_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/compass_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022120\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EAnswer a bunch of very random questions, see where that puts you on the political compass, and share the results with friends \ud83d\ude09\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/compass_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/compass_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022120\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EAnswer a bunch of very random questions, see where that puts you on the political compass, and share the results with friends \ud83d\ude09\u003C\/p\u003E","words":22,"readTime":null,"lang":"en"}}},"projects\/sumup":{"key":"projects\/sumup","type":"article","published":true,"meta":{"createdAt":"2020-06-16T14:48:41+02:00","publishedAt":"2020-06-16T14:48:41+02:00","links":[{"icon":"globe-europe","colour":"primary","url":"https:\/\/sumup.avris.it","displayUrl":null}],"category":"projects","subcategory":null,"slug":"sumup"},"content":{"en":{"slug":"sumup","title":"SumUp","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/sumup_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022330.36077705828\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAYCAYAAACSuF9OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAADgElEQVRIicWWzW4cRRDHf9UfM7O7idf22gE7ENsCiQtcIiEU5Rl4Aq48CScehMfgyAkJjpEiIQUJE8XGMpbxfk13V3OY3bWd7K690SL+0kgzrerpX3dVdZXkRogIb+vi9Rm+9HR6XW7aLHsHEJHZ+M2x+9i4dygmCqOaH779Hld6nn\/3DXVdoznjrKUOgaOjQx7t7i6a\/t5aCORKzxdfP6fqtDg4eIKqUlUtxuMx\/UGfrc3NtcMAyCKXqSonJyeIMRTek1Sp6xrnHCJCDBERwRgBEVJKWGshg2ZFk1IUBSKQUiLn5p\/OOYqiYHOzO9dlZhFpVmV00SePI+ev\/0JDoixKqrJEk1JVJWVZIGJw1iKAEYP3jqyZVqsCAURQzRgjbHa7dGxBt7ux+gnlnAnjcG1oBOPsezhhvqwxqwV1zpmgifF4TAgR5yzGGGKMgGCMQTVRFAVlWZFSZDAYYK0lhNC4byJjDIgggPce5xy2LOauuxDoprx3qOokFprjh2Z3zTO1bHbrnJttyhqD5owBQozkzC3YlYCstXQ3rv191b+i3x\/iHLTbLVpVC2iCGKCsSgrv8ROgq36fB53ObH6IgfE4kFQXrrk0y676Ay4vL\/HiMEExzqJJySlhvEOTYr2l1X2A8Q5yBpoTu44PgMzsGCfxUpXFajEEUBQFOzs7pBDRkEAgJ0VsExNoBgExC5N1ZS0FqvtDXv74CyJgnKW99ZB\/Tv9m4+ARnY96XLw4pvfJY7YeP1ob0FKX1TFClqkl5NvuIEOejCP89y4bD0dAxntPHQLWNNkRU7wV7OvUUqBpCRAxkDOqTdpnvU756S5jjJydnTEcjdjf25uUjcXVfmUgYwzHP72gu9\/jydPPFrYcsx85x+nPv9E73KM8LO9ceGUgaNye0+I746ZSSmw\/PcI6x\/Hxn4gI+\/t76wXKOXP+xykPP9hm6+PlmWSt5fzXV2hMIIKvCq5evsFXnqNnn68HaKp53eTbSimx++Wn1HVNu91mNBrRarXo9bbvDXMnkLEW65tW5C5Za2m9+p0Pn301tz29rxbeQwAaJ8V0cjP\/rz01gFiDuWe6rktL+6G6rhERbKhRbxBpepg8yT4jgvHuHdjpd4qxqX3GoDFgvZ9e1Dg\/f+mlQIPhEEFoS6ZfK5WHqAnNmcI6YlKqJV2kqqKT3lvTiBR0VjrsRmfunH8Bdwwal0oloW0AAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/sumup_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022330.36077705828\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003ESumUp is a simple tool that shows all possible combinations of numbers that add up to a given sum.\nIt\u0027s useful for certain types of puzzles, like for example\n\u003Ca href=\u0022https:\/\/www.youtube.com\/watch?v=hOAB65KFl6I\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E this killer sudoku\u003C\/a\u003E.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/sumup_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022660.72155411656\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAYCAYAAACSuF9OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAADgElEQVRIicWWzW4cRRDHf9UfM7O7idf22gE7ENsCiQtcIiEU5Rl4Aq48CScehMfgyAkJjpEiIQUJE8XGMpbxfk13V3OY3bWd7K690SL+0kgzrerpX3dVdZXkRogIb+vi9Rm+9HR6XW7aLHsHEJHZ+M2x+9i4dygmCqOaH779Hld6nn\/3DXVdoznjrKUOgaOjQx7t7i6a\/t5aCORKzxdfP6fqtDg4eIKqUlUtxuMx\/UGfrc3NtcMAyCKXqSonJyeIMRTek1Sp6xrnHCJCDBERwRgBEVJKWGshg2ZFk1IUBSKQUiLn5p\/OOYqiYHOzO9dlZhFpVmV00SePI+ev\/0JDoixKqrJEk1JVJWVZIGJw1iKAEYP3jqyZVqsCAURQzRgjbHa7dGxBt7ux+gnlnAnjcG1oBOPsezhhvqwxqwV1zpmgifF4TAgR5yzGGGKMgGCMQTVRFAVlWZFSZDAYYK0lhNC4byJjDIgggPce5xy2LOauuxDoprx3qOokFprjh2Z3zTO1bHbrnJttyhqD5owBQozkzC3YlYCstXQ3rv191b+i3x\/iHLTbLVpVC2iCGKCsSgrv8ROgq36fB53ObH6IgfE4kFQXrrk0y676Ay4vL\/HiMEExzqJJySlhvEOTYr2l1X2A8Q5yBpoTu44PgMzsGCfxUpXFajEEUBQFOzs7pBDRkEAgJ0VsExNoBgExC5N1ZS0FqvtDXv74CyJgnKW99ZB\/Tv9m4+ARnY96XLw4pvfJY7YeP1ob0FKX1TFClqkl5NvuIEOejCP89y4bD0dAxntPHQLWNNkRU7wV7OvUUqBpCRAxkDOqTdpnvU756S5jjJydnTEcjdjf25uUjcXVfmUgYwzHP72gu9\/jydPPFrYcsx85x+nPv9E73KM8LO9ceGUgaNye0+I746ZSSmw\/PcI6x\/Hxn4gI+\/t76wXKOXP+xykPP9hm6+PlmWSt5fzXV2hMIIKvCq5evsFXnqNnn68HaKp53eTbSimx++Wn1HVNu91mNBrRarXo9bbvDXMnkLEW65tW5C5Za2m9+p0Pn301tz29rxbeQwAaJ8V0cjP\/rz01gFiDuWe6rktL+6G6rhERbKhRbxBpepg8yT4jgvHuHdjpd4qxqX3GoDFgvZ9e1Dg\/f+mlQIPhEEFoS6ZfK5WHqAnNmcI6YlKqJV2kqqKT3lvTiBR0VjrsRmfunH8Bdwwal0oloW0AAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/sumup_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022660.72155411656\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003ESumUp is a simple tool that shows all possible combinations of numbers that add up to a given sum.\nIt\u0027s useful for certain types of puzzles, like for example\n\u003Ca href=\u0022https:\/\/www.youtube.com\/watch?v=hOAB65KFl6I\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E this killer sudoku\u003C\/a\u003E.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["sudoku","numbers","puzzle","logic","svelte","javascript","js","nodejs"],"hasMore":false,"image":"https:\/\/avris.it\/image\/sumup_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/sumup_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/sumup_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022165.18038852914\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003ESumUp is a simple tool that shows all possible combinations of numbers that add up to a given sum.\nIt\u0027s useful for certain types of puzzles, like for example\n\u003Ca href=\u0022https:\/\/www.youtube.com\/watch?v=hOAB65KFl6I\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E this killer sudoku\u003C\/a\u003E.\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/sumup_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/sumup_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022165.18038852914\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003ESumUp is a simple tool that shows all possible combinations of numbers that add up to a given sum.\nIt\u0027s useful for certain types of puzzles, like for example\n\u003Ca href=\u0022https:\/\/www.youtube.com\/watch?v=hOAB65KFl6I\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E this killer sudoku\u003C\/a\u003E.\u003C\/p\u003E","words":32,"readTime":null,"lang":"en"}}},"projects\/sexuality-spectrum":{"key":"projects\/sexuality-spectrum","type":"article","published":true,"meta":{"createdAt":"2020-01-16T23:48:41+01:00","publishedAt":"2020-01-16T23:48:41+01:00","group":"gender-apps","links":[{"icon":"globe-europe","colour":"primary","url":"https:\/\/spectrum.avris.it","displayUrl":null}],"category":"projects","subcategory":null,"slug":"sexuality-spectrum"},"content":{"en":{"slug":"sexuality-spectrum","title":"Sexuality Spectrum","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/spectrum_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022234.07874015748\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAARCAYAAAC1tw6GAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACVElEQVRIic2VTW8TQQyGH8\/MfiQhacKBGxKovfD\/fwdXoAcE3FAhqZRkk+5mPOaQhOZjU22BA+\/JI2vmtf3aHqm+zGzqlyQzvPcMBgP6vT7PQUzGerUkz3I8kWgOLLGJCScB8YaEnNQ84H3As6FJDu8csVpDkSEiOOeQ+XxuKaVnBXAKe1AwAxGk9H\/8joggZmZdLyRVPt3eMhqNiDES44Zer89qtSLPc2LcEGMCjLIsqeua6+sbvHfsaUTkSVtSSp0Cmk6nADjnmEwmFzPsSvzXATWf7\/Eqrb7FZg0Cw9A785kZ6qG4aU\/iFEGkneQMrweEomh1lesS7wMhz858KSViXdOVJ5hZp5LOv\/2EZFgyRlcjNIMeOQDbMCOJ2EpSeMHKbpIFgMO+vmQXg5IUE71eScgyotaY22ZdVUtSSgyHo+PqqLKsKnwWGNJe3VN0nrLZbIaqYmaMJxPy7Fyef4FwybGXco\/yTgnmcM7B\/fJIHNWEaiTPtxLep4or18exva\/OyHdN\/e+mrGnIsqy1Oc0MTYngH5fiIZlqxPvQKaDOU7b48J34sGEyHhPCuVwO2O\/7yjf0U47sUpXMIW+GR8Fesi9Kdori+iVXZYn351\/DYrGg3+\/\/9hWbDRICIkJVLQHjxUELHFZlf74o2WEZDzGdTrHdB\/xfbOrq4x1Ohfxk+akqdV1TluW24Xls6qZusJSQ3DN496oLTfexV1UQwe9I9zAzVBXv\/VnD79eEiLRK3YbOm\/rH+69Yo9tLIWMyGR+Ttzy+8DVDLbDMYW9HT76\/t38BvPqThYnDi\/QAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/spectrum_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022234.07874015748\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EWhere are you on the Sexuality Spectrum?\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/spectrum_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022468.15748031496\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAARCAYAAAC1tw6GAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACVElEQVRIic2VTW8TQQyGH8\/MfiQhacKBGxKovfD\/fwdXoAcE3FAhqZRkk+5mPOaQhOZjU22BA+\/JI2vmtf3aHqm+zGzqlyQzvPcMBgP6vT7PQUzGerUkz3I8kWgOLLGJCScB8YaEnNQ84H3As6FJDu8csVpDkSEiOOeQ+XxuKaVnBXAKe1AwAxGk9H\/8joggZmZdLyRVPt3eMhqNiDES44Zer89qtSLPc2LcEGMCjLIsqeua6+sbvHfsaUTkSVtSSp0Cmk6nADjnmEwmFzPsSvzXATWf7\/Eqrb7FZg0Cw9A785kZ6qG4aU\/iFEGkneQMrweEomh1lesS7wMhz858KSViXdOVJ5hZp5LOv\/2EZFgyRlcjNIMeOQDbMCOJ2EpSeMHKbpIFgMO+vmQXg5IUE71eScgyotaY22ZdVUtSSgyHo+PqqLKsKnwWGNJe3VN0nrLZbIaqYmaMJxPy7Fyef4FwybGXco\/yTgnmcM7B\/fJIHNWEaiTPtxLep4or18exva\/OyHdN\/e+mrGnIsqy1Oc0MTYngH5fiIZlqxPvQKaDOU7b48J34sGEyHhPCuVwO2O\/7yjf0U47sUpXMIW+GR8Fesi9Kdori+iVXZYn351\/DYrGg3+\/\/9hWbDRICIkJVLQHjxUELHFZlf74o2WEZDzGdTrHdB\/xfbOrq4x1Ohfxk+akqdV1TluW24Xls6qZusJSQ3DN496oLTfexV1UQwe9I9zAzVBXv\/VnD79eEiLRK3YbOm\/rH+69Yo9tLIWMyGR+Ttzy+8DVDLbDMYW9HT76\/t38BvPqThYnDi\/QAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/spectrum_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022468.15748031496\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EWhere are you on the Sexuality Spectrum?\u003C\/p\u003E\n\u003Cp\u003E\u003Ca href=\u0022https:\/\/spectrum.avris.it\/mz0v\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E (mine here)\u003C\/a\u003E\u003C\/p\u003E\n\u003Cp\u003E\u003Cstrong\u003EDisclaimer:\u003C\/strong\u003E\u003C\/p\u003E\n\u003Cp\u003EI\u0027m not the author of the original concept of those axes.\nThey were circulating online in form of a picture without a watermark\n\u2013 making it practically impossible to find the author.\nI just made an interactive version of it, with a few adjustments.\u003C\/p\u003E\n\u003Cp\u003EI\u0027m aware that this representation of gender \u0026amp; sexuality is not perfect \u2013 but none is!\nHumans are more complex than just a few axes!\u003C\/p\u003E\n\u003Cp\u003EYes, us nonbinary folx aren\u0027t necessarily in between \u201cmale\u201d and \u201cfemale\u201d,\nyes, lumping bisexuality and pansexuality together is not ideal, etc. etc. etc.\nBut it\u0027s an approximation. If you come up with a better one, I\u0027d gladly make an app for it \ud83d\ude09\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["gender","identity","expression","sexual","orientation","drive","romantic","desire","relationship","male","nonbinary","female","masculine","feminine","straight","bi","pan","gay","asexual","ace","aromantic","romantic","monogamy","polyamory","vanilla","bdsm","svelte","javascript","js","nodejs"],"hasMore":true,"image":"https:\/\/avris.it\/image\/spectrum_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/spectrum_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/spectrum_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022117.03937007874\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EWhere are you on the Sexuality Spectrum?\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/spectrum_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/spectrum_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022117.03937007874\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EWhere are you on the Sexuality Spectrum?\u003C\/p\u003E\n\u003Cp\u003E\u003Ca href=\u0022https:\/\/spectrum.avris.it\/mz0v\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E (mine here)\u003C\/a\u003E\u003C\/p\u003E\n\u003Cp\u003E\u003Cstrong\u003EDisclaimer:\u003C\/strong\u003E\u003C\/p\u003E\n\u003Cp\u003EI\u0027m not the author of the original concept of those axes.\nThey were circulating online in form of a picture without a watermark\n\u2013 making it practically impossible to find the author.\nI just made an interactive version of it, with a few adjustments.\u003C\/p\u003E\n\u003Cp\u003EI\u0027m aware that this representation of gender \u0026amp; sexuality is not perfect \u2013 but none is!\nHumans are more complex than just a few axes!\u003C\/p\u003E\n\u003Cp\u003EYes, us nonbinary folx aren\u0027t necessarily in between \u201cmale\u201d and \u201cfemale\u201d,\nyes, lumping bisexuality and pansexuality together is not ideal, etc. etc. etc.\nBut it\u0027s an approximation. If you come up with a better one, I\u0027d gladly make an app for it \ud83d\ude09\u003C\/p\u003E","words":119,"readTime":null,"lang":"en"}}},"projects\/avris-fontawesomeoptimiser":{"key":"projects\/avris-fontawesomeoptimiser","type":"article","published":true,"meta":{"createdAt":"2020-01-09T23:04:10+01:00","publishedAt":"2020-01-09T23:04:10+01:00","group":null,"links":[{"icon":"globe-europe","colour":"primary","url":"https:\/\/packagist.org\/packages\/avris\/fontawesome-optimiser","displayUrl":"avris\/fontawesome-optimiser"},{"icon":"brands gitlab","colour":"secondary","url":"https:\/\/gitlab.com\/Avris\/FontAwesomeOptimiser","displayUrl":null}],"category":"projects","subcategory":null,"slug":"avris-fontawesomeoptimiser"},"content":{"en":{"slug":"avris-fontawesomeoptimiser","title":"Avris FontAwesomeOptimiser","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/fontawesomeoptimiser_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022320\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAYCAYAAACSuF9OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAHvElEQVRIiX2X249lx1XGf+tStfc53eecnpnunhmPPZM4IRDZxEqUCEsWionkXARGuSiJAlKAB3gIykP+BN554wGBeIaniJdcpKBEJJESCQIi4DjOKA4ztmdsy\/b07fTpPnvvqsXDPjNGEKW0b9Ku2vXV99Va69ty\/R2PRZSKEEStEBVzp5ZCEKgIroapktzpujW1VoiACAQQEYSxiQgiAgT3W0RszvrgTlREQEUwd0yEppngEUJEUGpBAgQopSCMH1bVEago1EpSZdhMgMimHw\/6iwAIqvL25HL\/WYhaEDUi3h5nCEkNrQW\/P0BQgkoEaAii42SEoOqAMJSKIShCiGKqGzbGhSDju82xuRjuRtf1iEDEuEARRTdjTRU3I6niIQq1bAgeGSECCUHVcFNMBBPFTZGo1FqptYwfcB9XXyuq9kAqFSFqJQgWOzsc3jsAKoQgDlELqgIBZkoyI\/l9QAKoQN2wJSCiGxkMRTEzsiWmTQMxsDo7o3GnSU72RK2VUgaGUkAY90utAFy9vM\/6ZAnUkbQIVPMGlGI6SpxNcdFERI+EgVT0wSYV1Gyk1hIqioqh4mw1W1yYLDhYHqGhRAkaT6hniEKIMAz9yJDAjevXee3WS4gEEmAqCAEkRGIjmZJMcU2ZIdhEjN2PFVAd2VHD1MjuZEsohkiiyYl37m1zulqy7nsuX9mnO1uxPD7BRMiu1Kg89dEP8+LzLzDPDUGMkQWojqKogggkU7IbHpqQtJELoQaYKKqGiuLmuBrZMy5CMidJImnDxYsLPv3Hn+XihR3++avf5OXbL2PNNsnHaJottnnqIx\/mJ9\/9ATvtBChExAhGBRUwE0xH1twFJzfI4NQaG30BFFFDzREx3BzVhJttzsTTn\/htvvDnn+fmj37K1\/7qH0gU3nP1IaJWTk6XeDb+8C++wo\/+8Rs8PJ\/TlZ4aAxFllE430ZXGPZSTYgou7Ra1L0itYx4KQAwRRy2RzFE1kjltykzd+ZMvfYaPfepplgcnfONvvkbWCRemLe9690OcHr3J0eqcj3z5D0gq1Nuv8BtX91merTgfOkodKLUHrSQ3zAR3JbmQkuEynSPdAKUSMO4RFJGEiiGeyOq0KTFNiS988Rk+9qmnAfjP7z9HomG2PWN72nBy74wbH3wfH332Kbxt+OFf\/h37uws0eo6Og2FIlBgBhVRUg5QddyElxbPgMplBHqCAhEIogoI4aMLUSebklHjiiXfy+5\/7nQcl4fj1JZcu73Htxj43HnuERz7wKFu7cyKCl7\/1PbYmmVK3aZuB3FSQSo2eYeiI2qMGqoG5kRvHk+DMFjAUImQEE2N0GY5rQnFkkwC\/+GefeJCZAT7+p8\/wf1tEcOd7\/0b3xpvsveMS66NMf3rIXHvEKmJBrT11WCMMqAnmSsoZbxpcZzNSYawzKB5Kwsji5DCyGhnlA09c59q1i\/8PwP9utRRe\/Kd\/5eTmi7RbSruYsvfehxmOtjh+VVDpEHqQTJSESB0jLDmWM9ZM8NnOjFKADUOG4OG0YrQoLUZThSd\/692\/EszyjSOe\/\/oP6N56g0kDKPRnK1Zv9bh0TBcNtS9j7jFQSchGLnXHcos2E\/zKxQnDENQCNRQNRTFSCAmjDaUpwnse3f2lQM6OV\/zs+89x599fIEvPpK1j6agQPdS1QaPkiRJJMYmNTAk1xVJGc4OkBvIEf3y\/YXXe060L3VAppVJqRUKQqFgRTITdC9MHIE6XZ9y+eYdbP\/4Fd37y3zTRM\/VCpIJTyVoJDbCAbqyVkoLkgZtgJmhKSG4hGeQMuQFv8Wcv3OX0vLJc9hyfVpZDcLKGVQfnPXSDUAb427\/+e85Ozzh885jTe8fkUkgUEpVWKxMb2ErBvK100wqzIIXQ2mgzpPSoB5YNq0HfG8aMfm1omzg6mNLTIk8\/thvzNnF+Plql3Uv71FAOjleEJPCWviqeW87WHagjoriOWXuscUY2oVHYynB1d5tJOeHqhcKV\/cSF3Sk3f36HLoJOV8z2r\/Ddb\/8Lt15dM28r+\/sz1n3ww+dPke2di6EpI2pYSnzy2d\/j3r0DtGnZ2p6xf+kSP\/vFLd73+OPcvfMKbs6VvV3WXeVkeU6TWy4t5rSeSVJZbE1YvnbA9Ucu0h2+xbVrl2i1RxkwGdhuKw8\/Ehy+2XF6tMQOb+IysPfkM6z+6zvIh\/7oS9FszxkqtFszbly9wlBhb2fB6XrgoYs7rLseN6OUSpSKRXB0suLKYpvV8ozSD0xTgmGgW51zeb7F3nxKPVkyb53FvKWeHrI1nzC1jkd\/fY\/EAS\/99FUmwwGND0wuXybPF3jBWK7OwBLdyQnPLU8B5aYZEsJz7hsvBFIqlIrUSj0\/58e1kM2QEkgEVguJ0Rtv54YtN2buLJrENAmuhWmGN+7e5UO\/OefWS4fUKMwnMDu8y699\/P34we2f0\/U96plaKt5M4O1\/CATwlFBVJIKogcYIQGtFhuGBwa\/9Ghfj8PWXaHOLi7DYnnNpvoNHZbU65sJ8xn+84Lx2e8LrR+fceuucSQ4a7fjd4RVk913vjVoKQ9dR+zVpa4aEULpzNDVjOagDnluA0XMDWgNFkLjvoUcvrhEIFRPBVXABpZLNUA2GoUco7M+cRWvcOxttbuPw5A34HwP7VySOoz7KAAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/fontawesomeoptimiser_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022320\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EFontAwesome provides thousands of icons, but you probably only use a few dozen on your website. Instead of loading all of them as a webfont, you could use SVG sprites.\u003C\/p\u003E\n\u003Cp\u003EThis library is a simple helper that:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003Eregisters the icons you use in the place you use it,\u003C\/li\u003E\n\u003Cli\u003Edumps a refined set of SVG symbols at the end of your page.\u003C\/li\u003E\n\u003C\/ul\u003E\n\u003Cp\u003EYou can check out \u003Ca href=\u0022\/blog\/reducing-website-size-by-a-half-by-optimising-bootstrap-and-fontawesome\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-computer-speaker\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E a blog post\u003C\/a\u003E about possible gains.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/fontawesomeoptimiser_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022900\u0022 height=\u0022600\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAYCAYAAACSuF9OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAHvElEQVRIiX2X249lx1XGf+tStfc53eecnpnunhmPPZM4IRDZxEqUCEsWionkXARGuSiJAlKAB3gIykP+BN554wGBeIaniJdcpKBEJJESCQIi4DjOKA4ztmdsy\/b07fTpPnvvqsXDPjNGEKW0b9Ku2vXV99Va69ty\/R2PRZSKEEStEBVzp5ZCEKgIroapktzpujW1VoiACAQQEYSxiQgiAgT3W0RszvrgTlREQEUwd0yEppngEUJEUGpBAgQopSCMH1bVEago1EpSZdhMgMimHw\/6iwAIqvL25HL\/WYhaEDUi3h5nCEkNrQW\/P0BQgkoEaAii42SEoOqAMJSKIShCiGKqGzbGhSDju82xuRjuRtf1iEDEuEARRTdjTRU3I6niIQq1bAgeGSECCUHVcFNMBBPFTZGo1FqptYwfcB9XXyuq9kAqFSFqJQgWOzsc3jsAKoQgDlELqgIBZkoyI\/l9QAKoQN2wJSCiGxkMRTEzsiWmTQMxsDo7o3GnSU72RK2VUgaGUkAY90utAFy9vM\/6ZAnUkbQIVPMGlGI6SpxNcdFERI+EgVT0wSYV1Gyk1hIqioqh4mw1W1yYLDhYHqGhRAkaT6hniEKIMAz9yJDAjevXee3WS4gEEmAqCAEkRGIjmZJMcU2ZIdhEjN2PFVAd2VHD1MjuZEsohkiiyYl37m1zulqy7nsuX9mnO1uxPD7BRMiu1Kg89dEP8+LzLzDPDUGMkQWojqKogggkU7IbHpqQtJELoQaYKKqGiuLmuBrZMy5CMidJImnDxYsLPv3Hn+XihR3++avf5OXbL2PNNsnHaJottnnqIx\/mJ9\/9ATvtBChExAhGBRUwE0xH1twFJzfI4NQaG30BFFFDzREx3BzVhJttzsTTn\/htvvDnn+fmj37K1\/7qH0gU3nP1IaJWTk6XeDb+8C++wo\/+8Rs8PJ\/TlZ4aAxFllE430ZXGPZSTYgou7Ra1L0itYx4KQAwRRy2RzFE1kjltykzd+ZMvfYaPfepplgcnfONvvkbWCRemLe9690OcHr3J0eqcj3z5D0gq1Nuv8BtX91merTgfOkodKLUHrSQ3zAR3JbmQkuEynSPdAKUSMO4RFJGEiiGeyOq0KTFNiS988Rk+9qmnAfjP7z9HomG2PWN72nBy74wbH3wfH332Kbxt+OFf\/h37uws0eo6Og2FIlBgBhVRUg5QddyElxbPgMplBHqCAhEIogoI4aMLUSebklHjiiXfy+5\/7nQcl4fj1JZcu73Htxj43HnuERz7wKFu7cyKCl7\/1PbYmmVK3aZuB3FSQSo2eYeiI2qMGqoG5kRvHk+DMFjAUImQEE2N0GY5rQnFkkwC\/+GefeJCZAT7+p8\/wf1tEcOd7\/0b3xpvsveMS66NMf3rIXHvEKmJBrT11WCMMqAnmSsoZbxpcZzNSYawzKB5Kwsji5DCyGhnlA09c59q1i\/8PwP9utRRe\/Kd\/5eTmi7RbSruYsvfehxmOtjh+VVDpEHqQTJSESB0jLDmWM9ZM8NnOjFKADUOG4OG0YrQoLUZThSd\/692\/EszyjSOe\/\/oP6N56g0kDKPRnK1Zv9bh0TBcNtS9j7jFQSchGLnXHcos2E\/zKxQnDENQCNRQNRTFSCAmjDaUpwnse3f2lQM6OV\/zs+89x599fIEvPpK1j6agQPdS1QaPkiRJJMYmNTAk1xVJGc4OkBvIEf3y\/YXXe060L3VAppVJqRUKQqFgRTITdC9MHIE6XZ9y+eYdbP\/4Fd37y3zTRM\/VCpIJTyVoJDbCAbqyVkoLkgZtgJmhKSG4hGeQMuQFv8Wcv3OX0vLJc9hyfVpZDcLKGVQfnPXSDUAb427\/+e85Ozzh885jTe8fkUkgUEpVWKxMb2ErBvK100wqzIIXQ2mgzpPSoB5YNq0HfG8aMfm1omzg6mNLTIk8\/thvzNnF+Plql3Uv71FAOjleEJPCWviqeW87WHagjoriOWXuscUY2oVHYynB1d5tJOeHqhcKV\/cSF3Sk3f36HLoJOV8z2r\/Ddb\/8Lt15dM28r+\/sz1n3ww+dPke2di6EpI2pYSnzy2d\/j3r0DtGnZ2p6xf+kSP\/vFLd73+OPcvfMKbs6VvV3WXeVkeU6TWy4t5rSeSVJZbE1YvnbA9Ucu0h2+xbVrl2i1RxkwGdhuKw8\/Ehy+2XF6tMQOb+IysPfkM6z+6zvIh\/7oS9FszxkqtFszbly9wlBhb2fB6XrgoYs7rLseN6OUSpSKRXB0suLKYpvV8ozSD0xTgmGgW51zeb7F3nxKPVkyb53FvKWeHrI1nzC1jkd\/fY\/EAS\/99FUmwwGND0wuXybPF3jBWK7OwBLdyQnPLU8B5aYZEsJz7hsvBFIqlIrUSj0\/58e1kM2QEkgEVguJ0Rtv54YtN2buLJrENAmuhWmGN+7e5UO\/OefWS4fUKMwnMDu8y699\/P34we2f0\/U96plaKt5M4O1\/CATwlFBVJIKogcYIQGtFhuGBwa\/9Ghfj8PWXaHOLi7DYnnNpvoNHZbU65sJ8xn+84Lx2e8LrR+fceuucSQ4a7fjd4RVk913vjVoKQ9dR+zVpa4aEULpzNDVjOagDnluA0XMDWgNFkLjvoUcvrhEIFRPBVXABpZLNUA2GoUco7M+cRWvcOxttbuPw5A34HwP7VySOoz7KAAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/fontawesomeoptimiser_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022900\u0022 height=\u0022600\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EFontAwesome provides thousands of icons, but you probably only use a few dozen on your website. Instead of loading all of them as a webfont, you could use SVG sprites.\u003C\/p\u003E\n\u003Cp\u003EThis library is a simple helper that:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003Eregisters the icons you use in the place you use it,\u003C\/li\u003E\n\u003Cli\u003Edumps a refined set of SVG symbols at the end of your page.\u003C\/li\u003E\n\u003C\/ul\u003E\n\u003Cp\u003EYou can check out \u003Ca href=\u0022\/blog\/reducing-website-size-by-a-half-by-optimising-bootstrap-and-fontawesome\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-computer-speaker\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E a blog post\u003C\/a\u003E about possible gains.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["fontawesome","optimise","font","webfont","icons","symfony","twig","php","js"],"hasMore":false,"image":"https:\/\/avris.it\/image\/fontawesomeoptimiser_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/fontawesomeoptimiser_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/fontawesomeoptimiser_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022160\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EFontAwesome provides thousands of icons, but you probably only use a few dozen on your website. Instead of loading all of them as a webfont, you could use SVG sprites.\u003C\/p\u003E\n\u003Cp\u003EThis library is a simple helper that:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003Eregisters the icons you use in the place you use it,\u003C\/li\u003E\n\u003Cli\u003Edumps a refined set of SVG symbols at the end of your page.\u003C\/li\u003E\n\u003C\/ul\u003E\n\u003Cp\u003EYou can check out \u003Ca href=\u0022\/blog\/reducing-website-size-by-a-half-by-optimising-bootstrap-and-fontawesome.lite\u0022\u003E a blog post\u003C\/a\u003E about possible gains.\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/fontawesomeoptimiser_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/fontawesomeoptimiser_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022160\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EFontAwesome provides thousands of icons, but you probably only use a few dozen on your website. Instead of loading all of them as a webfont, you could use SVG sprites.\u003C\/p\u003E\n\u003Cp\u003EThis library is a simple helper that:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003Eregisters the icons you use in the place you use it,\u003C\/li\u003E\n\u003Cli\u003Edumps a refined set of SVG symbols at the end of your page.\u003C\/li\u003E\n\u003C\/ul\u003E\n\u003Cp\u003EYou can check out \u003Ca href=\u0022\/blog\/reducing-website-size-by-a-half-by-optimising-bootstrap-and-fontawesome.lite\u0022\u003E a blog post\u003C\/a\u003E about possible gains.\u003C\/p\u003E","words":71,"readTime":null,"lang":"en"}}},"blog\/society\/ocz-just-some-googly-eyes":{"key":"blog\/society\/ocz-just-some-googly-eyes","type":"article","published":true,"meta":{"createdAt":"2019-10-16T17:27:18+02:00","publishedAt":"2019-10-16T20:23:00+02:00","group":null,"links":[{"icon":"globe-europe","colour":"primary","url":"https:\/\/ocz.avris.it\/","displayUrl":"Demo"},{"icon":"brands gitlab","colour":"secondary","url":"https:\/\/gitlab.com\/Avris\/Ocz","displayUrl":null},{"icon":"globe-europe","colour":"secondary","url":"https:\/\/www.npmjs.com\/package\/avris-ocz","displayUrl":null}],"category":"blog","subcategory":"society","slug":"ocz-just-some-googly-eyes"},"content":{"en":{"slug":"ocz-just-some-googly-eyes","title":"Ocz \u2013 Just some googly eyes.","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-ocz_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022320\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAYCAYAAACSuF9OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAHhUlEQVRIiX2Xy69lRRXGf+tRtfc595776tsXmoZu3gqoHYhGEmJoSRCIQYPGB5oQHehA48A\/wbkzB0bjWEfGCRKj0QgkkCgaH4AtEexuHg1p+nHvPfd19q5aDvbpxqixsl\/Jrtr11ffVWuvbcuzGuyJKRQiiVoiKuVNLIQhUBFfDVEnuzGYH1FohAiIQQEQQhiYiiAgQXGkRMT\/r1TtREQEVwdwxEZpmhEcIEUGpBQkQoJSCMHxYVQegolArSZV+PgEi835c7S8CIKjKe5PLlWchakHUiHhvnCEkNbQW\/MoAQQkqEaAhiA6TEYKqA0JfKoagCCGKqc7ZGBaCDO\/mx\/xiuBuzWYcIRAwLFFF0PtZUcTOSKh6iUMuc4IERIpAQVA03xUQwUdwUiUqtlVrL8AH3YfW1ompXpVIRolaCYHllhcsXLwEVQhCHqAVVgQAzJZmR\/AogAVSgztkSENG5DIaimBnZEuOmgejZ3dujcadJTvZErZVSevpSQBj2S60AHLlmg4PtKVAH0iJQzXNQiukgcTbFRRMRHRIGUtGrm1RQs4FaS6goKoaKs9AssDpa5tJ0Ew0lStB4Qj1DFEKEvu8GhgRuPHaMt0+fRSSQAFNBCCAhEnPJlGSKa8r0wTxi7EqsgOrAjhqmRnYnW0IxRBJNTtx0eJGd3SkHXcc1124w29tlurWNiZBdqVG57xP38+rLp1jKDUEMkQWoDqKogggkU7IbHpqQNJcLoQaYKKqGiuLmuBrZMy5CMidJImnD2toyn\/nK51hbXeG3P\/0Fr585izWLJB+iabK8yH0P3M9LTz\/HSjsCChExgFFBBcwE04E1d8HJDdI7tcZcXwBF1FBzRAw3RzXhZvMzcfKRj\/H4N7\/AKy\/8jSe\/9xMShduPXEfUyvbOFM\/Gl7\/zbV742VNcv7TErHTU6Ikog3Q6j6407KGcFFNwaReoXUFqHfJQAGKIOGqJZI6qkcxpU2bszle\/8Vkeeuwk00vbPPWDJ8k6YnXccsut17Gz+S6bu\/s88K0vkVSoZ97g\/Uc2mO7tst\/PKLWn1A60ktwwE9yV5EJKhst4CZn1UCoBwx5BEUmoGOKJrE6bEuOUePyJB3nosZMA\/OXZF0k0TBYnLI4bti\/ucfzDH+ITj96Htw3Pf\/dHbKwvo9GxuRX0faLEACikohqk7LgLKSmeBZfRBHIPBSQUQhEUxEETpk4yJ6fEiRM38anPf\/xqSdh6Z8qhaw5z9PgGx++6gRvuuZmF9SUigtd\/+QwLo0ypi7RNT24qSKVGR9\/PiNqhBqqBuZEbx5PgTJahL0TIACaG6DIc14TiyDwBPvH1R65mZoCHv\/Yg\/9kigjef+QOz8+9y+MZDHGxmup3LLGmHWEUsqLWj9gcIPWqCuZJyxpsG18mEVBjqDIqHkjCyODmMrEZGuefEMY4eXfsvAP\/eaim8+qvfs\/3Kq7QLSrs85vAd19NvLrB1TlCZIXQgmSgJkTpEWHIsZ6wZ4ZOVCaUAc4YMwcNpxWhRWoymCvd+9Nb\/C2Z6fpOXf\/4cswvnGTWAQre3y+6FDpcZ4+WG2pUh9xioJGQul7pjuUWbEX7t2oi+D2qBGoqGohgphITRhtIU4fab1\/8nkL2tXf7+7Iu8+cdTZOkYtXUoHRWig3pg0Ch5pERSTGIuU0JNsZTR3CCpgTzCP7DRsLvfMTsozPpKKZVSKxKCRMWKYCKsr46vgtiZ7nHmlTc5\/efXePOlf9JEx9gLkQpOJWslNMACZkOtlBQkD9wEM0FTQnILySBnyA14iz+6+hY7+5XptGNrpzLtg+0D2J3BfgezXig9\/PD7P2ZvZ4\/L726xc3GLXAqJQqLSamVkPQspWGors3GFSZBCaG2wGVI61APLhtWg6wxjQndgaJvYvDSmo0VO3rUeS21if3+wSm6ZEKfihCQKTtVMXyFEQR0RxXXI2kONM7IJjcJChkmGwwvBkdXCxrqxsCCcPXeZ6d4eJXesXHeUp3\/9O06fO2CprWxsTDjogudf3kEWV9ZCU0bUsJTwpkXU8NzgKWOpQdXITYt5InnGLQ12U4y777yN1p29nZ5DSyPOnnqN5WSstspKC4cWldUFSNqTrGdloef2E2Mun5ty\/twWkxG49By+90F2\/\/ob\/I5Pf5FmcYm+QrswwVODqiPmJE+IGMJQdyQEKRVKQWqgpTI+so4DaS3ouh42enqBA1MOXNhJSk5GmyrVKvtNpbMV1t4Hl6evkUZC4z39pV0W73wILxjT3T2wxGx7G5EdQAcvFIMBH7wQczAVqZW6vw+1cOHtM0gJJAKrhcTgjccpM0nOxJ3lJjFOgmthnGG63\/GRDy7xxiWlXuxZGsHk8lvc9vDd+KUz\/2DWdahnaql4M4L3\/iEQwFNCVZEIogYaAwCtFen7qwa\/dge4GJffOUubW1yE5cUlDi2t4FHZ3d1idWnCn045b58Z8c7mPqcv7DPKQaMzPtm\/gazfckfUUuhnM2p3QFqYICGU2T6amqEc1B7PLcDguQGtgSJIXPHQgxfXCISKieAquIBSyWaoBn3fIRQ2Js5ya1zcG2xu43DvcfgXoycudg\/N7GgAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris-ocz_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022320\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EFair warning: this library is pretty useless. And only moderately fun... \ud83e\udd37\u200d\u003C\/p\u003E\n\u003Cp\u003EBut it seemed like a cool way to learn a bit about web components, so here it is: a component that creates googly eyes that follow your mouse.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-ocz_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022900\u0022 height=\u0022600\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAYCAYAAACSuF9OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAHhUlEQVRIiX2Xy69lRRXGf+tRtfc595776tsXmoZu3gqoHYhGEmJoSRCIQYPGB5oQHehA48A\/wbkzB0bjWEfGCRKj0QgkkCgaH4AtEexuHg1p+nHvPfd19q5aDvbpxqixsl\/Jrtr11ffVWuvbcuzGuyJKRQiiVoiKuVNLIQhUBFfDVEnuzGYH1FohAiIQQEQQhiYiiAgQXGkRMT\/r1TtREQEVwdwxEZpmhEcIEUGpBQkQoJSCMHxYVQegolArSZV+PgEi835c7S8CIKjKe5PLlWchakHUiHhvnCEkNbQW\/MoAQQkqEaAhiA6TEYKqA0JfKoagCCGKqc7ZGBaCDO\/mx\/xiuBuzWYcIRAwLFFF0PtZUcTOSKh6iUMuc4IERIpAQVA03xUQwUdwUiUqtlVrL8AH3YfW1ompXpVIRolaCYHllhcsXLwEVQhCHqAVVgQAzJZmR\/AogAVSgztkSENG5DIaimBnZEuOmgejZ3dujcadJTvZErZVSevpSQBj2S60AHLlmg4PtKVAH0iJQzXNQiukgcTbFRRMRHRIGUtGrm1RQs4FaS6goKoaKs9AssDpa5tJ0Ew0lStB4Qj1DFEKEvu8GhgRuPHaMt0+fRSSQAFNBCCAhEnPJlGSKa8r0wTxi7EqsgOrAjhqmRnYnW0IxRBJNTtx0eJGd3SkHXcc1124w29tlurWNiZBdqVG57xP38+rLp1jKDUEMkQWoDqKogggkU7IbHpqQNJcLoQaYKKqGiuLmuBrZMy5CMidJImnD2toyn\/nK51hbXeG3P\/0Fr585izWLJB+iabK8yH0P3M9LTz\/HSjsCChExgFFBBcwE04E1d8HJDdI7tcZcXwBF1FBzRAw3RzXhZvMzcfKRj\/H4N7\/AKy\/8jSe\/9xMShduPXEfUyvbOFM\/Gl7\/zbV742VNcv7TErHTU6Ikog3Q6j6407KGcFFNwaReoXUFqHfJQAGKIOGqJZI6qkcxpU2bszle\/8Vkeeuwk00vbPPWDJ8k6YnXccsut17Gz+S6bu\/s88K0vkVSoZ97g\/Uc2mO7tst\/PKLWn1A60ktwwE9yV5EJKhst4CZn1UCoBwx5BEUmoGOKJrE6bEuOUePyJB3nosZMA\/OXZF0k0TBYnLI4bti\/ucfzDH+ITj96Htw3Pf\/dHbKwvo9GxuRX0faLEACikohqk7LgLKSmeBZfRBHIPBSQUQhEUxEETpk4yJ6fEiRM38anPf\/xqSdh6Z8qhaw5z9PgGx++6gRvuuZmF9SUigtd\/+QwLo0ypi7RNT24qSKVGR9\/PiNqhBqqBuZEbx5PgTJahL0TIACaG6DIc14TiyDwBPvH1R65mZoCHv\/Yg\/9kigjef+QOz8+9y+MZDHGxmup3LLGmHWEUsqLWj9gcIPWqCuZJyxpsG18mEVBjqDIqHkjCyODmMrEZGuefEMY4eXfsvAP\/eaim8+qvfs\/3Kq7QLSrs85vAd19NvLrB1TlCZIXQgmSgJkTpEWHIsZ6wZ4ZOVCaUAc4YMwcNpxWhRWoymCvd+9Nb\/C2Z6fpOXf\/4cswvnGTWAQre3y+6FDpcZ4+WG2pUh9xioJGQul7pjuUWbEX7t2oi+D2qBGoqGohgphITRhtIU4fab1\/8nkL2tXf7+7Iu8+cdTZOkYtXUoHRWig3pg0Ch5pERSTGIuU0JNsZTR3CCpgTzCP7DRsLvfMTsozPpKKZVSKxKCRMWKYCKsr46vgtiZ7nHmlTc5\/efXePOlf9JEx9gLkQpOJWslNMACZkOtlBQkD9wEM0FTQnILySBnyA14iz+6+hY7+5XptGNrpzLtg+0D2J3BfgezXig9\/PD7P2ZvZ4\/L726xc3GLXAqJQqLSamVkPQspWGors3GFSZBCaG2wGVI61APLhtWg6wxjQndgaJvYvDSmo0VO3rUeS21if3+wSm6ZEKfihCQKTtVMXyFEQR0RxXXI2kONM7IJjcJChkmGwwvBkdXCxrqxsCCcPXeZ6d4eJXesXHeUp3\/9O06fO2CprWxsTDjogudf3kEWV9ZCU0bUsJTwpkXU8NzgKWOpQdXITYt5InnGLQ12U4y777yN1p29nZ5DSyPOnnqN5WSstspKC4cWldUFSNqTrGdloef2E2Mun5ty\/twWkxG49By+90F2\/\/ob\/I5Pf5FmcYm+QrswwVODqiPmJE+IGMJQdyQEKRVKQWqgpTI+so4DaS3ouh42enqBA1MOXNhJSk5GmyrVKvtNpbMV1t4Hl6evkUZC4z39pV0W73wILxjT3T2wxGx7G5EdQAcvFIMBH7wQczAVqZW6vw+1cOHtM0gJJAKrhcTgjccpM0nOxJ3lJjFOgmthnGG63\/GRDy7xxiWlXuxZGsHk8lvc9vDd+KUz\/2DWdahnaql4M4L3\/iEQwFNCVZEIogYaAwCtFen7qwa\/dge4GJffOUubW1yE5cUlDi2t4FHZ3d1idWnCn045b58Z8c7mPqcv7DPKQaMzPtm\/gazfckfUUuhnM2p3QFqYICGU2T6amqEc1B7PLcDguQGtgSJIXPHQgxfXCISKieAquIBSyWaoBn3fIRQ2Js5ya1zcG2xu43DvcfgXoycudg\/N7GgAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris-ocz_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022900\u0022 height=\u0022600\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EFair warning: this library is pretty useless. And only moderately fun... \ud83e\udd37\u200d\u003C\/p\u003E\n\u003Cp\u003EBut it seemed like a cool way to learn a bit about web components, so here it is: a component that creates googly eyes that follow your mouse.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["css variables","googly eyes","javascript","js","library","web components"],"hasMore":false,"image":"https:\/\/avris.it\/image\/avris-ocz_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris-ocz_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-ocz_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022160\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EFair warning: this library is pretty useless. And only moderately fun... \ud83e\udd37\u200d\u003C\/p\u003E\n\u003Cp\u003EBut it seemed like a cool way to learn a bit about web components, so here it is: a component that creates googly eyes that follow your mouse.\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris-ocz_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-ocz_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022160\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EFair warning: this library is pretty useless. And only moderately fun... \ud83e\udd37\u200d\u003C\/p\u003E\n\u003Cp\u003EBut it seemed like a cool way to learn a bit about web components, so here it is: a component that creates googly eyes that follow your mouse.\u003C\/p\u003E","words":39,"readTime":null,"lang":"en"}}},"projects\/avris-sorter":{"key":"projects\/avris-sorter","type":"article","published":true,"meta":{"createdAt":"2019-10-13T14:09:02+02:00","publishedAt":"2019-10-13T14:06:00+02:00","group":null,"links":[{"icon":"globe-europe","colour":"primary","url":"https:\/\/sorter.avris.it\/","displayUrl":"Demo"},{"icon":"brands gitlab","colour":"secondary","url":"https:\/\/gitlab.com\/Avris\/Sorter","displayUrl":null},{"icon":"globe-europe","colour":"secondary","url":"https:\/\/www.npmjs.com\/package\/avris-sorter","displayUrl":null}],"category":"projects","subcategory":null,"slug":"avris-sorter"},"content":{"en":{"slug":"avris-sorter","title":"Avris Sorter","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-sorter_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022320\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAYCAYAAACSuF9OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAHkElEQVRIiX2XyY8kRxXGf2+JyKyqrl5m6cEe8HgBgzEwwjLCkoU8WDK2hQwCxC4hOMABxIE\/gTs3DgjEGU6ICxgJBMK2ZEtsYjHGWNh4xstgxp7ppbq7qjIjHoesGSNAhDIyU8pYvvi+ePG+lBtuvD2iVIQgaoWomDu1FIJARXA1TJXkznK5oNYKERCBACKCMBQRQUSA4GqJiFWt155ERQRUBHPHRGiaER4hRASlFiRAgFIKwjCwqg5ARaFWkir9agJEVu241l4EQFCV1yeXq+9C1IKoEfF6P0NIamgt+NUOghJUIkBDEB0mIwRVB4S+VAxBEUIUU12xMSwEGb6trtXNcDeWyw4RiBgWKKLoqq+p4mYkVTxEoZYVwQMjRCAhqBpuiolgorgpEpVaK7WWYQD3YfW1omrXpFIRolaCYGNzk53LV4AKIYhD1IKqQICZksxIfhWQACpQV2wJiOhKBkNRzIxsiXHTQPQcHh3RuNMkJ3ui1kopPX0pIAz7pVYArju1zWJ\/BtSBtAhU8wqUYjpInE1x0UREh4SBVPTaJhXUbKDWEiqKiqHiTJoJW6MNrsx20VCiBI0n1DNEIUTo+25gSODMDTfwj+cvIBJIgKkgBJAQiZVkSjLFNWX6YBUxdjVWQHVgRw1TI7uTLaEYIokmJ246ucbB4YxF13HqDdssjw6Z7e1jImRXalTu\/sA9PPvU06znhiCGyAJUB1FUQQSSKdkND01IWsmFUANMFFVDRXFzXI3sGRchmZMkkbTh2LENPvr5j3Nsa5Nf\/uAnvHD+BaxZI\/kQTdONNe6+9x7+\/MjjbLYjoBARAxgVVMBMMB1Ycxec3CC9U2us9AVQRA01R8Rwc1QTbraqiXMPvo9Pf+WTPPObv\/Cjb36fROHW664namX\/YIZn47Nf\/xq\/+eHDvHF9nWXpqNETUQbpdBVdadhDOSmm4NJOqF1Bah3OoQDEEHHUEskcVSOZ06bM2J0vfPlj3P+Rc8yu7PPwt39E1hFb45Zb3nw9B7uvsns4596vfoakQj3\/Im+7bpvZ0SHzfkmpPaV2oJXkhpngriQXUjJcxuvIsodSCRj2CIpIQsUQT2R12pQYp8SnP3cf93\/kHAB\/fOxJEg3TtSlr44b9y0ecufNdfOChu\/G24YlvfJftExtodOzuBX2fKDEACqmoBik77kJKimfBZTSF3EMBCYVQBAVx0ISpk8zJKXH27E186BPvv5YS9l6ZcfzUSU6f2ebM7W\/iTXfczOTEOhHBCz99lMkoU+oabdOTmwpSqdHR90uidqiBamBu5MbxJDjTDegLETKAiSG6DMc1oTiyOgA\/96UHr53MAA988T7+s0QELz36W5aXXuXkjcdZ7Ga6gx3WtUOsIhbU2lH7BUKPmmCupJzxpsF1OiUVhjyD4qEkjCxODiOrkVHuOHsDp08f+y8A\/15qKTz7s1+z\/8yztBOl3Rhz8rY30u9O2LsoqCwROpBMlIRIHSIsOZYz1ozw6eaUUoAVQ4bg4bRitCgtRlOFu9775v8LZnZpl6d+\/DjL1y4xagCF7uiQw9c6XJaMNxpqV4azx0AlISu51B3LLdqM8DccG9H3QS1QQ9FQFCOFkDDaUJoi3Hrzif8J5GjvkL8+9iQv\/e5psnSM2jqkjgrRQV0YNEoeKZEUk1jJlFBTLGU0N0hqII\/wd2w3HM47lovCsq+UUim1IiFIVKwIJsKJrfE1EAezI84\/8xLP\/+E5Xvrz32miY+yFSAWnkrUSGmAByyFXSgqSB26CmaApIbmFZJAz5Aa8xR\/aepmDeWU269g7qMz6YH8Bh0uYd7DshdLDd771PY4Ojth5dY+Dy3vkUkgUEpVWKyPrmaRgva0sxxWmQQqhtcFmSOlQDywbVoOuM4wp3cLQNrF7ZUxHi5y7\/USst4n5fLBKbpkQp+KEJApO1UxfIURBHRFlMh4zalqW8znZjFEynMokwzTDyUlw3VZh+4QxmQgXLu4wOzqi5I7N60\/zyM9\/xfMXF6y3le3tKYsueOKpA2Rt81hoyogalhLetIganhs8ZSw1qBq5aTFPJM+4Jd575x2kCEZNw2LecfrUNrJcYLXw2vmXyf2czRaOrylbE0jak6xnc9Jz69kxOxdnXLq4x3QELj0n77qPwz\/9Ar\/tw5+iWVunr9BOpnhqUHXEnOQJEUMY8o6EIKVCKSzWxmxtrNGocPDqDldKJlmi1p7dvMX6SFm4cJCUnIw2VapV5k2ls02OvRV2Zs+RRkLjPf2VQ9befj9eMGaHR2CJ5f4+IgeADl4oBgM+eCFWYCpSK\/+8MOcvtZDNkBJIBFYLicEbj1NmmpypOxtNYpwE18I4w2ze8Z53rvPiFaVe7lkfwXTnZd7ywLvxK+f\/xrLrUM\/UUvFmBK\/\/QyCAp4SqIhFEDTQGAFor0vfXDH7tFrgYO69coM0tLsLG2jrH1zfxqBwe7rG1PuX3Tzv\/OD\/ild05z782Z5SDRpd8sH8ROXHLbVFLoV8uqd2CNJkiIZTlHE3NkA5qj+cWYPDcgNZAESSueujBi2sEQsVEcBVcQKlkM1SDvu8QCttTZ6M1Lh8NNrdxuOsM\/AtA9jdb2ZxdiwAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris-sorter_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022320\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003ELightweight sorting of tables.\u003C\/p\u003E\n\u003Cp\u003EJust add \u003Ccode\u003E[data-sort]\u003C\/code\u003E attributes to the \u003Ccode\u003Eth\u003C\/code\u003E elements in columns you\u2019d like to sort a table by, include ~1kB of JS \u0026amp; CSS, and initialise with \u003Ccode\u003Esorter()\u003C\/code\u003E \u2013 and that\u2019s it!\u003C\/p\u003E\n\u003Cp\u003EFor installation instructions and more customisation options, you can check out the \u003Ca href=\u0022https:\/\/gitlab.com\/Avris\/Sorter\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E readme file\u003C\/a\u003E.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-sorter_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022900\u0022 height=\u0022600\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAYCAYAAACSuF9OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAHkElEQVRIiX2XyY8kRxXGf2+JyKyqrl5m6cEe8HgBgzEwwjLCkoU8WDK2hQwCxC4hOMABxIE\/gTs3DgjEGU6ICxgJBMK2ZEtsYjHGWNh4xstgxp7ppbq7qjIjHoesGSNAhDIyU8pYvvi+ePG+lBtuvD2iVIQgaoWomDu1FIJARXA1TJXkznK5oNYKERCBACKCMBQRQUSA4GqJiFWt155ERQRUBHPHRGiaER4hRASlFiRAgFIKwjCwqg5ARaFWkir9agJEVu241l4EQFCV1yeXq+9C1IKoEfF6P0NIamgt+NUOghJUIkBDEB0mIwRVB4S+VAxBEUIUU12xMSwEGb6trtXNcDeWyw4RiBgWKKLoqq+p4mYkVTxEoZYVwQMjRCAhqBpuiolgorgpEpVaK7WWYQD3YfW1omrXpFIRolaCYGNzk53LV4AKIYhD1IKqQICZksxIfhWQACpQV2wJiOhKBkNRzIxsiXHTQPQcHh3RuNMkJ3ui1kopPX0pIAz7pVYArju1zWJ\/BtSBtAhU8wqUYjpInE1x0UREh4SBVPTaJhXUbKDWEiqKiqHiTJoJW6MNrsx20VCiBI0n1DNEIUTo+25gSODMDTfwj+cvIBJIgKkgBJAQiZVkSjLFNWX6YBUxdjVWQHVgRw1TI7uTLaEYIokmJ246ucbB4YxF13HqDdssjw6Z7e1jImRXalTu\/sA9PPvU06znhiCGyAJUB1FUQQSSKdkND01IWsmFUANMFFVDRXFzXI3sGRchmZMkkbTh2LENPvr5j3Nsa5Nf\/uAnvHD+BaxZI\/kQTdONNe6+9x7+\/MjjbLYjoBARAxgVVMBMMB1Ycxec3CC9U2us9AVQRA01R8Rwc1QTbraqiXMPvo9Pf+WTPPObv\/Cjb36fROHW664namX\/YIZn47Nf\/xq\/+eHDvHF9nWXpqNETUQbpdBVdadhDOSmm4NJOqF1Bah3OoQDEEHHUEskcVSOZ06bM2J0vfPlj3P+Rc8yu7PPwt39E1hFb45Zb3nw9B7uvsns4596vfoakQj3\/Im+7bpvZ0SHzfkmpPaV2oJXkhpngriQXUjJcxuvIsodSCRj2CIpIQsUQT2R12pQYp8SnP3cf93\/kHAB\/fOxJEg3TtSlr44b9y0ecufNdfOChu\/G24YlvfJftExtodOzuBX2fKDEACqmoBik77kJKimfBZTSF3EMBCYVQBAVx0ISpk8zJKXH27E186BPvv5YS9l6ZcfzUSU6f2ebM7W\/iTXfczOTEOhHBCz99lMkoU+oabdOTmwpSqdHR90uidqiBamBu5MbxJDjTDegLETKAiSG6DMc1oTiyOgA\/96UHr53MAA988T7+s0QELz36W5aXXuXkjcdZ7Ga6gx3WtUOsIhbU2lH7BUKPmmCupJzxpsF1OiUVhjyD4qEkjCxODiOrkVHuOHsDp08f+y8A\/15qKTz7s1+z\/8yztBOl3Rhz8rY30u9O2LsoqCwROpBMlIRIHSIsOZYz1ozw6eaUUoAVQ4bg4bRitCgtRlOFu9775v8LZnZpl6d+\/DjL1y4xagCF7uiQw9c6XJaMNxpqV4azx0AlISu51B3LLdqM8DccG9H3QS1QQ9FQFCOFkDDaUJoi3Hrzif8J5GjvkL8+9iQv\/e5psnSM2jqkjgrRQV0YNEoeKZEUk1jJlFBTLGU0N0hqII\/wd2w3HM47lovCsq+UUim1IiFIVKwIJsKJrfE1EAezI84\/8xLP\/+E5Xvrz32miY+yFSAWnkrUSGmAByyFXSgqSB26CmaApIbmFZJAz5Aa8xR\/aepmDeWU269g7qMz6YH8Bh0uYd7DshdLDd771PY4Ojth5dY+Dy3vkUkgUEpVWKyPrmaRgva0sxxWmQQqhtcFmSOlQDywbVoOuM4wp3cLQNrF7ZUxHi5y7\/USst4n5fLBKbpkQp+KEJApO1UxfIURBHRFlMh4zalqW8znZjFEynMokwzTDyUlw3VZh+4QxmQgXLu4wOzqi5I7N60\/zyM9\/xfMXF6y3le3tKYsueOKpA2Rt81hoyogalhLetIganhs8ZSw1qBq5aTFPJM+4Jd575x2kCEZNw2LecfrUNrJcYLXw2vmXyf2czRaOrylbE0jak6xnc9Jz69kxOxdnXLq4x3QELj0n77qPwz\/9Ar\/tw5+iWVunr9BOpnhqUHXEnOQJEUMY8o6EIKVCKSzWxmxtrNGocPDqDldKJlmi1p7dvMX6SFm4cJCUnIw2VapV5k2ls02OvRV2Zs+RRkLjPf2VQ9befj9eMGaHR2CJ5f4+IgeADl4oBgM+eCFWYCpSK\/+8MOcvtZDNkBJIBFYLicEbj1NmmpypOxtNYpwE18I4w2ze8Z53rvPiFaVe7lkfwXTnZd7ywLvxK+f\/xrLrUM\/UUvFmBK\/\/QyCAp4SqIhFEDTQGAFor0vfXDH7tFrgYO69coM0tLsLG2jrH1zfxqBwe7rG1PuX3Tzv\/OD\/ild05z782Z5SDRpd8sH8ROXHLbVFLoV8uqd2CNJkiIZTlHE3NkA5qj+cWYPDcgNZAESSueujBi2sEQsVEcBVcQKlkM1SDvu8QCttTZ6M1Lh8NNrdxuOsM\/AtA9jdb2ZxdiwAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris-sorter_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022900\u0022 height=\u0022600\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003ELightweight sorting of tables.\u003C\/p\u003E\n\u003Cp\u003EJust add \u003Ccode\u003E[data-sort]\u003C\/code\u003E attributes to the \u003Ccode\u003Eth\u003C\/code\u003E elements in columns you\u2019d like to sort a table by, include ~1kB of JS \u0026amp; CSS, and initialise with \u003Ccode\u003Esorter()\u003C\/code\u003E \u2013 and that\u2019s it!\u003C\/p\u003E\n\u003Cp\u003EFor installation instructions and more customisation options, you can check out the \u003Ca href=\u0022https:\/\/gitlab.com\/Avris\/Sorter\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E readme file\u003C\/a\u003E.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["html","javascript","js","library","lightweight","sort","sorting","table"],"hasMore":false,"image":"https:\/\/avris.it\/image\/avris-sorter_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris-sorter_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-sorter_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022160\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003ELightweight sorting of tables.\u003C\/p\u003E\n\u003Cp\u003EJust add \u003Ccode\u003E[data-sort]\u003C\/code\u003E attributes to the \u003Ccode\u003Eth\u003C\/code\u003E elements in columns you\u2019d like to sort a table by, include ~1kB of JS \u0026amp; CSS, and initialise with \u003Ccode\u003Esorter()\u003C\/code\u003E \u2013 and that\u2019s it!\u003C\/p\u003E\n\u003Cp\u003EFor installation instructions and more customisation options, you can check out the \u003Ca href=\u0022https:\/\/gitlab.com\/Avris\/Sorter\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E readme file\u003C\/a\u003E.\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris-sorter_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-sorter_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022160\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003ELightweight sorting of tables.\u003C\/p\u003E\n\u003Cp\u003EJust add \u003Ccode\u003E[data-sort]\u003C\/code\u003E attributes to the \u003Ccode\u003Eth\u003C\/code\u003E elements in columns you\u2019d like to sort a table by, include ~1kB of JS \u0026amp; CSS, and initialise with \u003Ccode\u003Esorter()\u003C\/code\u003E \u2013 and that\u2019s it!\u003C\/p\u003E\n\u003Cp\u003EFor installation instructions and more customisation options, you can check out the \u003Ca href=\u0022https:\/\/gitlab.com\/Avris\/Sorter\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E readme file\u003C\/a\u003E.\u003C\/p\u003E","words":50,"readTime":null,"lang":"en"}}},"projects\/daemonise":{"key":"projects\/daemonise","type":"article","published":true,"meta":{"createdAt":"2018-08-11T11:49:57+02:00","publishedAt":"2018-08-11T11:48:00+02:00","group":null,"links":[{"icon":"globe-europe","colour":"primary","url":"https:\/\/www.npmjs.com\/package\/avris-daemonise","displayUrl":"npm: avris-daemonise"},{"icon":"brands gitlab","colour":"secondary","url":"https:\/\/gitlab.com\/Avris\/Daemonise","displayUrl":null}],"category":"projects","subcategory":null,"slug":"daemonise"},"content":{"en":{"slug":"daemonise","title":"Daemonise","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-daemonise_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022256\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAATCAYAAAD4f6+NAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACVUlEQVRIie2VS4\/TMBSFv2s7ryZNSzswIAYk2A\/\/\/1+wQfwAQIBmaOkrTeIkviw6rZgFQuIhuuBsrGvJ9vG5x8fyKnupnBGc6lnxwQnyrzncg1POTCHOTSE5Lz64Y8fGzxzx2CIO6IXmxmGzOWIdoWsJCtYYxEUM3oMRrLEkw55sXLBeLLEuotps8L4HBWOFEALGmNOoqqjqoRaDomgIaDgSulOoMJdE3jEpZjR1xXa0Y34xBuuo1gGMpSxz2qZht\/XU+z2Pn15SV1A+mJLEMdYZ1mmCixxplqFhIARFREAMeZGxuF3Q7Gvmj+b4tqecjnn7+g2+9QDIdXrIoYvLC6yziBhAcdHhtnE2wlmDbz1hGOj7gXI2pd3vcVGEquLbjihyuNihQem6jiiO2e8qjLV0bUvfD+Tj\/G7fLQpMHkwBZfN1zWa1PSgkcuhZCIEiL+i7QDpKWH1ZkpclWT7i87sP5JMSEWFUFvTes1quEOOYzUuaugZSFGXoe+IkYbX4Suc909mMwRosQpql3H66oW0aAHbrzck7Ry\/LdfpCAZ48v0JDT5yO8HXFerVFgBAUUJq6+RsePpE55rM7TlbckEwsbbRGE8G1DjeagY3QriUK4NydqduDqY0xxF1FPilZL5bEScKn9x9\/i9yJ0Cy5Yjqe4NuBwXrmV5ZquyMrEgwRdd3gnMMYQYqc5Zcljy8fsrz1VJsdwxBY3i5+iwyAXGeHlglgjEUBDQF+kOAiBj2+UQQR+a7+dRxPO+WQAsMw\/HzhvcMPmfIn4c7s5\/j\/2\/8UZ6fQN+aNGGDFN9nmAAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris-daemonise_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022256\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EUse this library to run any process in the background without blocking the console. It will start a child process, detach it, and save its PID to a file in order to be able to stop it later.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-daemonise_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022900\u0022 height=\u0022480\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAATCAYAAAD4f6+NAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACVUlEQVRIie2VS4\/TMBSFv2s7ryZNSzswIAYk2A\/\/\/1+wQfwAQIBmaOkrTeIkviw6rZgFQuIhuuBsrGvJ9vG5x8fyKnupnBGc6lnxwQnyrzncg1POTCHOTSE5Lz64Y8fGzxzx2CIO6IXmxmGzOWIdoWsJCtYYxEUM3oMRrLEkw55sXLBeLLEuotps8L4HBWOFEALGmNOoqqjqoRaDomgIaDgSulOoMJdE3jEpZjR1xXa0Y34xBuuo1gGMpSxz2qZht\/XU+z2Pn15SV1A+mJLEMdYZ1mmCixxplqFhIARFREAMeZGxuF3Q7Gvmj+b4tqecjnn7+g2+9QDIdXrIoYvLC6yziBhAcdHhtnE2wlmDbz1hGOj7gXI2pd3vcVGEquLbjihyuNihQem6jiiO2e8qjLV0bUvfD+Tj\/G7fLQpMHkwBZfN1zWa1PSgkcuhZCIEiL+i7QDpKWH1ZkpclWT7i87sP5JMSEWFUFvTes1quEOOYzUuaugZSFGXoe+IkYbX4Suc909mMwRosQpql3H66oW0aAHbrzck7Ry\/LdfpCAZ48v0JDT5yO8HXFerVFgBAUUJq6+RsePpE55rM7TlbckEwsbbRGE8G1DjeagY3QriUK4NydqduDqY0xxF1FPilZL5bEScKn9x9\/i9yJ0Cy5Yjqe4NuBwXrmV5ZquyMrEgwRdd3gnMMYQYqc5Zcljy8fsrz1VJsdwxBY3i5+iwyAXGeHlglgjEUBDQF+kOAiBj2+UQQR+a7+dRxPO+WQAsMw\/HzhvcMPmfIn4c7s5\/j\/2\/8UZ6fQN+aNGGDFN9nmAAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris-daemonise_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022900\u0022 height=\u0022480\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EUse this library to run any process in the background without blocking the console. It will start a child process, detach it, and save its PID to a file in order to be able to stop it later.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["background","daemon","detach","javascript","js","nodejs","process","server"],"hasMore":false,"image":"https:\/\/avris.it\/image\/avris-daemonise_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris-daemonise_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-daemonise_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022128\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EUse this library to run any process in the background without blocking the console. It will start a child process, detach it, and save its PID to a file in order to be able to stop it later.\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris-daemonise_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-daemonise_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022128\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EUse this library to run any process in the background without blocking the console. It will start a child process, detach it, and save its PID to a file in order to be able to stop it later.\u003C\/p\u003E","words":38,"readTime":null,"lang":"en"}}},"projects\/vanillin":{"key":"projects\/vanillin","type":"article","published":true,"meta":{"createdAt":"2018-02-10T22:05:06+01:00","publishedAt":"2018-02-10T22:03:00+01:00","group":"vanillin","links":[{"icon":"globe-europe","colour":"primary","url":"https:\/\/www.npmjs.com\/package\/avris-vanillin","displayUrl":"npm: avris-vanillin"},{"icon":"brands gitlab","colour":"secondary","url":"https:\/\/gitlab.com\/Avris\/Vanillin","displayUrl":null}],"category":"projects","subcategory":null,"slug":"vanillin"},"content":{"en":{"slug":"vanillin","title":"Vanillin \u2013 Almost like vanilla JavaScript","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/vanillin_small.png\u0022 alt=\u0022Vanillin.js\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022269.94727592267\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAUCAYAAADlep81AAAACXBIWXMAAA7EAAAOxAGVKw4bAAADvElEQVRIie2VXUxbZRjHf+05W6nAYGXyjXQQBwlpJpQLGwxZIioGF73QeGMiMSaGRA3BmV15YbhYxAuucLvQxCySJYZENgwKk5oomYUOSIflK5J+WAqF5qwttKctpz1eWBAZSxZDvdo\/eXPe\/J8n7\/N7P877wmP9B83Pzz8zPT39bnt7+4vOmpp+f23t+qzRaL9WVtac7driYWN2dva5qqqqn3t7e0WDwUCiuJhSQaBQkkpXUqnvns\/NPTsRjSrZAtIeNhRFeXloaEjc3t6mtbWVqYYG0GpJqioyVAqiaMgWzJFANpvt5vj4eDKVSiHLMo4TJ\/g+HOY3Wcaxu3tXCoc3\/xeg1dXVdo\/HY19cXPw8Ho\/vCILAxsYGoVCIr8vKKLp6lS6rNe\/D69efzSaQCNDd3S0WFBTcGBgYKEylUpSXl1NcXExlZSWRSARtURHeWIzXzp2rX1he\/gpoeISxtUCaf85pOtOOyvk3UCwWY2JiQlxYWKClpYWcnBwmJydxu900NTWRm5vL6OgoJpMJt9t9cLBPgSvA+8A3wCaQl4m3AaeACPACsAhcAwqBDaAUuACMA3EgBiAAzMzMpGVZTgiC8FIymWR9fZ1AIICiKMiyjN\/vJxAI8NPt27GNQOBNp9PpBVTgdeAs4AI+AFqBtzP+\/cyEt4Fa4EnAnImFgJ1M\/hXADqztA42MjDyh0+k+iUQiNRaLhWQySTQaRa\/X09jYiCiKvOJw0Ol2a8rcbvG0VvuDPR5PAT6gDxgA3gCimUL3MyASYATqM34UuMvfW14C5APhTP+X\/S2rrq5+p7m5ua2np4elpSUkScJiseDz+YhEItT6fHSk01BUJMrBYGeJXm8nFPoCuAeYgCTwauZ7UGke\/JP3vE7ABsxmVox9IJfLRUVFBWazGavVisFgYHd3F0VRsNvt5IfDfHvmDClVJZFIIMXjTx8osAcR42gdPsh73pdHJQsAer3+XiAQMMZisbzTd+7IHwWD+TUuF6LXy1MdHbzV10eivh5rMMif5eVcvHw52WQ2\/zg2NrbzEIjj04zR+Gvq\/Hk13damBk0mVdraUtPptCrLstrf369OTU2p8XhcHRwcvJGN+g\/c1CuKsuLZ2WHL62UhGuX3uTlCoRDLy8s4HA7q6uqQJAm\/35+VJ0Q4bJScPGnzqGqjQ1GM2y0tGoxGbt66xfDwMC6XC41Gg81m887NzXU5nc614wbSPCzw8aVLF04VFHT5fD6nTqebXFtbe8\/j8fzh9Xo\/29zcjBw3yGM9qv4CsPqrHrao4OAAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/vanillin_small.png\u0022 alt=\u0022Vanillin.js\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022269.94727592267\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EjQuery used to be virtually indispensable,\nif you wanted to develop a cross-browser website without getting a headache.\u003C\/p\u003E\n\u003Cp\u003EToday, however, you might not need jQuery,\nespecially, if you\u2019re developing a library and want to avoid unnecessary dependencies.\u003C\/p\u003E\n\u003Cp\u003EStill, some helpers could be useful...\nVanillin is an opinionated set of helpers\nthat I find most useful, a bare minimum to make life easier.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/vanillin_big.png\u0022 alt=\u0022Vanillin.js\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022539.89455184534\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAUCAYAAADlep81AAAACXBIWXMAAA7EAAAOxAGVKw4bAAADvElEQVRIie2VXUxbZRjHf+05W6nAYGXyjXQQBwlpJpQLGwxZIioGF73QeGMiMSaGRA3BmV15YbhYxAuucLvQxCySJYZENgwKk5oomYUOSIflK5J+WAqF5qwttKctpz1eWBAZSxZDvdo\/eXPe\/J8n7\/N7P877wmP9B83Pzz8zPT39bnt7+4vOmpp+f23t+qzRaL9WVtac7driYWN2dva5qqqqn3t7e0WDwUCiuJhSQaBQkkpXUqnvns\/NPTsRjSrZAtIeNhRFeXloaEjc3t6mtbWVqYYG0GpJqioyVAqiaMgWzJFANpvt5vj4eDKVSiHLMo4TJ\/g+HOY3Wcaxu3tXCoc3\/xeg1dXVdo\/HY19cXPw8Ho\/vCILAxsYGoVCIr8vKKLp6lS6rNe\/D69efzSaQCNDd3S0WFBTcGBgYKEylUpSXl1NcXExlZSWRSARtURHeWIzXzp2rX1he\/gpoeISxtUCaf85pOtOOyvk3UCwWY2JiQlxYWKClpYWcnBwmJydxu900NTWRm5vL6OgoJpMJt9t9cLBPgSvA+8A3wCaQl4m3AaeACPACsAhcAwqBDaAUuACMA3EgBiAAzMzMpGVZTgiC8FIymWR9fZ1AIICiKMiyjN\/vJxAI8NPt27GNQOBNp9PpBVTgdeAs4AI+AFqBtzP+\/cyEt4Fa4EnAnImFgJ1M\/hXADqztA42MjDyh0+k+iUQiNRaLhWQySTQaRa\/X09jYiCiKvOJw0Ol2a8rcbvG0VvuDPR5PAT6gDxgA3gCimUL3MyASYATqM34UuMvfW14C5APhTP+X\/S2rrq5+p7m5ua2np4elpSUkScJiseDz+YhEItT6fHSk01BUJMrBYGeJXm8nFPoCuAeYgCTwauZ7UGke\/JP3vE7ABsxmVox9IJfLRUVFBWazGavVisFgYHd3F0VRsNvt5IfDfHvmDClVJZFIIMXjTx8osAcR42gdPsh73pdHJQsAer3+XiAQMMZisbzTd+7IHwWD+TUuF6LXy1MdHbzV10eivh5rMMif5eVcvHw52WQ2\/zg2NrbzEIjj04zR+Gvq\/Hk13damBk0mVdraUtPptCrLstrf369OTU2p8XhcHRwcvJGN+g\/c1CuKsuLZ2WHL62UhGuX3uTlCoRDLy8s4HA7q6uqQJAm\/35+VJ0Q4bJScPGnzqGqjQ1GM2y0tGoxGbt66xfDwMC6XC41Gg81m887NzXU5nc614wbSPCzw8aVLF04VFHT5fD6nTqebXFtbe8\/j8fzh9Xo\/29zcjBw3yGM9qv4CsPqrHrao4OAAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/vanillin_big.png\u0022 alt=\u0022Vanillin.js\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022539.89455184534\u0022\u003E\u003C\/span\u003E\n                \u003Cfigcaption\u003E\n                    \u003Ca href=\u0022https:\/\/en.wikipedia.org\/wiki\/Vanillin#\/media\/File:Vanillin-3d.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\n                        \u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E\n                        en.wikipedia.org\/wiki\/Vanillin#\/media\/File:Vanillin-3d.png\n                    \u003C\/a\u003E\n                \u003C\/figcaption\u003E\n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EjQuery used to be virtually indispensable,\nif you wanted to develop a cross-browser website without getting a headache.\u003C\/p\u003E\n\u003Cp\u003EToday, however, you might not need jQuery,\nespecially, if you\u2019re developing a library and want to avoid unnecessary dependencies.\u003C\/p\u003E\n\u003Cp\u003EStill, some helpers could be useful...\nVanillin is an opinionated set of helpers\nthat I find most useful, a bare minimum to make life easier.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["helper","javascript","js","library","programming","vanilla"],"hasMore":false,"image":"https:\/\/avris.it\/image\/vanillin_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/vanillin_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/vanillin_mini.png\u0022 alt=\u0022Vanillin.js\u0022 width=\u0022240\u0022 height=\u0022134.97363796134\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EjQuery used to be virtually indispensable,\nif you wanted to develop a cross-browser website without getting a headache.\u003C\/p\u003E\n\u003Cp\u003EToday, however, you might not need jQuery,\nespecially, if you\u2019re developing a library and want to avoid unnecessary dependencies.\u003C\/p\u003E\n\u003Cp\u003EStill, some helpers could be useful...\nVanillin is an opinionated set of helpers\nthat I find most useful, a bare minimum to make life easier.\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/vanillin_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/vanillin_mini.png\u0022 alt=\u0022Vanillin.js\u0022 width=\u0022240\u0022 height=\u0022134.97363796134\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003Cfigcaption\u003E\n                    \u003Ca href=\u0022https:\/\/en.wikipedia.org\/wiki\/Vanillin#\/media\/File:Vanillin-3d.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csmall\u003Een.wikipedia.org\/wiki\/Vanillin#\/media\/File:Vanillin-3d.png\u003C\/small\u003E\u003C\/a\u003E\n                \u003C\/figcaption\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EjQuery used to be virtually indispensable,\nif you wanted to develop a cross-browser website without getting a headache.\u003C\/p\u003E\n\u003Cp\u003EToday, however, you might not need jQuery,\nespecially, if you\u2019re developing a library and want to avoid unnecessary dependencies.\u003C\/p\u003E\n\u003Cp\u003EStill, some helpers could be useful...\nVanillin is an opinionated set of helpers\nthat I find most useful, a bare minimum to make life easier.\u003C\/p\u003E","words":73,"readTime":null,"lang":"en"}}},"blog\/technology\/moving-to-vanilla-js":{"key":"blog\/technology\/moving-to-vanilla-js","type":"article","published":true,"meta":{"createdAt":"2018-01-19T19:02:20+01:00","publishedAt":"2018-01-31T19:01:00+01:00","group":"vanillin","category":"blog","subcategory":"technology","slug":"moving-to-vanilla-js"},"content":{"en":{"slug":"moving-to-vanilla-js","title":"Moving to vanilla JS","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-forms-multiple_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022201.10091743119\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAPCAYAAACMa21tAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAB5klEQVRIib2VTW4TQRCFv+rpiRMyDnISLyEcACkhXAEuAVsuxQk4AogFSNkgWLIFkVVAiW1kouD58XQXi\/H4D409YxHeZko93VWvq15VS5ymygrI5KsKIov2yoMbwgrCoD8gsIY8dwTWgiqdTmcSXFHVKZESegtsjDFYADFCnueIGARwqihFdkSEb1+\/cH1zw\/5Bl6P799Y67l1d8uPyijwbc\/r4tBEpiZPVJQOmGWqK8lK1yYhgq4\/M3JXaMcasdeq9R4Gg5l738RPu7Axz8gj79AlWKq8w+2HE0B\/0iKI92tFuZYDcOdJ0TBiGDIdDRAzdw\/3K\/Wk2Ri++Q6+PPz9HBCQpu6xMSFkdma1536RkUnRgnTKLIKMROvyFtCOk3UbiNFs4KUw6aEpON9ZQU4gY7HL\/6l8GGCMkSUJrq4W1ttKh844sG2PDkDRJCIKAne3tyv25c+Sv3+DevcecHBM+f7asobk6LVGM4wRrLVaqCQUmILCTm6jHe1nfZqrgHKiWGsr+Tz1qwtbRh\/P+1giMfMrP8W92gxaHW22q8z+HOjNlU7y6+MDbwWcObMTLhy+wayfp0oO6YP+DYj\/Y6XLX3uF476h4quKk0NAsmCIUYtSJ0Ip1QUQX7IKYTMdCM3t+Xs3sP+dY5dEk0L+pAAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris-forms-multiple_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022201.10091743119\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EWhile working on \u003Ca href=\u0022https:\/\/gitlab.com\/Avris\/Forms\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Avris Forms v4.0\u003C\/a\u003E, I\u2019ve decided to migrate some code from \u003Ca href=\u0022http:\/\/coffeescript.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E CoffeScript\u003C\/a\u003E with \u003Ca href=\u0022https:\/\/jquery.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E jQuery\u003C\/a\u003E to \u003Ca href=\u0022http:\/\/vanilla-js.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Vanilla JS\u003C\/a\u003E. And I guess it might be a good idea to share this transition \ud83d\ude09\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-forms-multiple_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022654\u0022 height=\u0022274\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAPCAYAAACMa21tAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAB5klEQVRIib2VTW4TQRCFv+rpiRMyDnISLyEcACkhXAEuAVsuxQk4AogFSNkgWLIFkVVAiW1kouD58XQXi\/H4D409YxHeZko93VWvq15VS5ymygrI5KsKIov2yoMbwgrCoD8gsIY8dwTWgiqdTmcSXFHVKZESegtsjDFYADFCnueIGARwqihFdkSEb1+\/cH1zw\/5Bl6P799Y67l1d8uPyijwbc\/r4tBEpiZPVJQOmGWqK8lK1yYhgq4\/M3JXaMcasdeq9R4Gg5l738RPu7Axz8gj79AlWKq8w+2HE0B\/0iKI92tFuZYDcOdJ0TBiGDIdDRAzdw\/3K\/Wk2Ri++Q6+PPz9HBCQpu6xMSFkdma1536RkUnRgnTKLIKMROvyFtCOk3UbiNFs4KUw6aEpON9ZQU4gY7HL\/6l8GGCMkSUJrq4W1ttKh844sG2PDkDRJCIKAne3tyv25c+Sv3+DevcecHBM+f7asobk6LVGM4wRrLVaqCQUmILCTm6jHe1nfZqrgHKiWGsr+Tz1qwtbRh\/P+1giMfMrP8W92gxaHW22q8z+HOjNlU7y6+MDbwWcObMTLhy+wayfp0oO6YP+DYj\/Y6XLX3uF476h4quKk0NAsmCIUYtSJ0Ip1QUQX7IKYTMdCM3t+Xs3sP+dY5dEk0L+pAAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris-forms-multiple_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022654\u0022 height=\u0022274\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EWhile working on \u003Ca href=\u0022https:\/\/gitlab.com\/Avris\/Forms\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Avris Forms v4.0\u003C\/a\u003E, I\u2019ve decided to migrate some code from \u003Ca href=\u0022http:\/\/coffeescript.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E CoffeScript\u003C\/a\u003E with \u003Ca href=\u0022https:\/\/jquery.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E jQuery\u003C\/a\u003E to \u003Ca href=\u0022http:\/\/vanilla-js.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Vanilla JS\u003C\/a\u003E. And I guess it might be a good idea to share this transition \ud83d\ude09\u003C\/p\u003E\n\u003Cp\u003EThe code handles the form widget visible in the screenshot above. More specifically: those buttons in the right column. Clicking on the green one adds a new element\/row based on a template hidden inside a \u003Ccode\u003E\u0026lt;script\u0026gt;\u003C\/code\u003E tag. Clicking on a red button results in removal of the current row (after asking for a confirmation).\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs javascript border\u0022\u003E$(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027body\u0027\u003C\/span\u003E).on \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027click\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027.form-multiple-add\u0027\u003C\/span\u003E, -\u0026gt;\n  $form = $(\u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E).parents(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027.form-multiple\u0027\u003C\/span\u003E)\n  newIndices = $form.find(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027[data-index^=new]\u0027\u003C\/span\u003E).map((i, el) -\u0026gt; el.dataset[\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027index\u0027\u003C\/span\u003E].substr(\u003Cspan class=\u0022hljs-number\u0022\u003E3\u003C\/span\u003E)).get()\n  newIndex = \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E newIndices.length then \u003Cspan class=\u0022hljs-built_in\u0022\u003EMath\u003C\/span\u003E.max.apply(\u003Cspan class=\u0022hljs-literal\u0022\u003Enull\u003C\/span\u003E, newIndices) + \u003Cspan class=\u0022hljs-number\u0022\u003E1\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003Eelse\u003C\/span\u003E \u003Cspan class=\u0022hljs-number\u0022\u003E0\u003C\/span\u003E\n  $template = $($form.find(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027.form-multiple-add-template\u0027\u003C\/span\u003E).html().replace(\u003Cspan class=\u0022hljs-regexp\u0022\u003E\/%i%\/g\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027new\u0027\u003C\/span\u003E + newIndex))\n  $(\u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E).parents(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027tr\u0027\u003C\/span\u003E).before $template\n  $template.find(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027:input:enabled:visible:first\u0027\u003C\/span\u003E).focus()\n\n$(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027body\u0027\u003C\/span\u003E).on \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027click\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027.form-multiple-remove\u0027\u003C\/span\u003E, -\u0026gt;\n  \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E \u003Cspan class=\u0022hljs-literal\u0022\u003Efalse\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E !confirm(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027Are you sure?\u0027\u003C\/span\u003E))\n  $(\u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E).parents(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027tr\u0027\u003C\/span\u003E).remove()\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EIt was not a part of the library (as the library was supposed to only provide PHP), instead each project included this part on its own. Which led to code duplication (and the worst kind: between projects) and also kinda prevented me from abandoning CoffeeScript in newer projects, even if I wanted to. \u003C\/p\u003E\n\u003Cp\u003EAnd I did want to, because JavaScript has matured as a language over the last years. An additional level of complexity in my projects simply wasn\u2019t necessary anymore. CoffeeScript did a great job of making fontend scripting bearable, but now it\u2019s slowly time for it to get a deserved retirement.\u003C\/p\u003E\n\u003Cp\u003ESo I\u2019ve decided to integrate the frontend part into the library. Except I shouldn\u2019t be forcing users to use CoffeeScript or jQuery, it should just work out of the box in any project.\u003C\/p\u003E\n\u003Cp\u003ESince CoffeeScript compiles into JS (although usually with from some unnecessary returns and similar features), getting rid of it is really simple. After using \u003Ca href=\u0022http:\/\/js2.coffee\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E js2coffee\u003C\/a\u003E or \u003Ca href=\u0022http:\/\/decaffeinate-project.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E decaffeinate\u003C\/a\u003E we would end up with something like this:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs javascript border\u0022\u003E$(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027body\u0027\u003C\/span\u003E).on(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027click\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027.form-multiple-add\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E(\u003Cspan class=\u0022hljs-params\u0022\u003E\u003C\/span\u003E) \u003C\/span\u003E{\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Evar\u003C\/span\u003E $form, $template, newIndex, newIndices;\n    $form = $(\u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E).parents(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027.form-multiple\u0027\u003C\/span\u003E);\n    newIndices = $form.find(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027[data-index^=new]\u0027\u003C\/span\u003E).map(\u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E(\u003Cspan class=\u0022hljs-params\u0022\u003Ei, el\u003C\/span\u003E) \u003C\/span\u003E{\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E el.dataset[\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027index\u0027\u003C\/span\u003E].substr(\u003Cspan class=\u0022hljs-number\u0022\u003E3\u003C\/span\u003E);\n    }).get();\n    newIndex = newIndices.length ? \u003Cspan class=\u0022hljs-built_in\u0022\u003EMath\u003C\/span\u003E.max.apply(\u003Cspan class=\u0022hljs-literal\u0022\u003Enull\u003C\/span\u003E, newIndices) + \u003Cspan class=\u0022hljs-number\u0022\u003E1\u003C\/span\u003E : \u003Cspan class=\u0022hljs-number\u0022\u003E0\u003C\/span\u003E;\n    $template = $($form.find(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027.form-multiple-add-template\u0027\u003C\/span\u003E).html().replace(\u003Cspan class=\u0022hljs-regexp\u0022\u003E\/%i%\/g\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027new\u0027\u003C\/span\u003E + newIndex));\n    $(\u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E).parents(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027tr\u0027\u003C\/span\u003E).before($template);\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E $template.find(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027:input:enabled:visible:first\u0027\u003C\/span\u003E).focus();\n});\n\n$(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027body\u0027\u003C\/span\u003E).on(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027click\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027.form-multiple-remove\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E(\u003Cspan class=\u0022hljs-params\u0022\u003E\u003C\/span\u003E) \u003C\/span\u003E{\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E (!confirm(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027Are you sure?\u0027\u003C\/span\u003E)) {\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E \u003Cspan class=\u0022hljs-literal\u0022\u003Efalse\u003C\/span\u003E;\n    }\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E $(\u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E).parents(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027tr\u0027\u003C\/span\u003E).remove();\n});\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003ERemoving the dependency on jQuery is more tricky.\u003C\/p\u003E\n\u003Cp\u003EThere are some \u003Ca href=\u0022http:\/\/youmightnotneedjquery.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E nice lists\u003C\/a\u003E that show you how to replace some jQuery usage with plain JS. Those Javascript versions used to be longer, more complicated and require some browser-specific checks and adjustments. Those times are almost over though (as you can see from the list), so the need for jQuery gets smaller and smaller.\u003C\/p\u003E\n\u003Cp\u003EReplacing those calls from the list with Vanilla JS\u2019s counterparts was not enough in my case. I needed two functionalities more: finding an element\u2019s parent by a selector (\u003Ccode\u003E$el.parents(\u0027.foo\u0027)\u003C\/code\u003E) and binding an event listener to elements matching a selector, even if those elements don\u2019t exist yet at the moment of binding (\u003Ccode\u003E$(\u0027body\u0027).on(\u0027click\u0027, \u0027.foo\u0027, =\u0026gt; ... )\u003C\/code\u003E).\u003C\/p\u003E\n\u003Cp\u003EThey were surprisingly easy to implement:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs javascript border\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Evar\u003C\/span\u003E findParent = \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E(\u003Cspan class=\u0022hljs-params\u0022\u003Eel, selector\u003C\/span\u003E) \u003C\/span\u003E{\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Edo\u003C\/span\u003E {\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E (el.matches(selector)) {\n            \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E el;\n        }\n        el = el.parentNode;\n    } \u003Cspan class=\u0022hljs-keyword\u0022\u003Ewhile\u003C\/span\u003E (el \u0026amp;\u0026amp; el.matches);\n};\n\n\u003Cspan class=\u0022hljs-keyword\u0022\u003Evar\u003C\/span\u003E on = \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E (\u003Cspan class=\u0022hljs-params\u0022\u003Eselector, event, handler\u003C\/span\u003E) \u003C\/span\u003E{\n    \u003Cspan class=\u0022hljs-built_in\u0022\u003Edocument\u003C\/span\u003E.addEventListener(event, \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E (\u003Cspan class=\u0022hljs-params\u0022\u003Ee\u003C\/span\u003E) \u003C\/span\u003E{\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Evar\u003C\/span\u003E match = findParent(e.target, selector);\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E (match) {\n            \u003Cspan class=\u0022hljs-keyword\u0022\u003Evar\u003C\/span\u003E result = handler.apply(match, [e]);\n            \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E (result === \u003Cspan class=\u0022hljs-literal\u0022\u003Efalse\u003C\/span\u003E) {\n                e.preventDefault();\n                e.stopPropagation();\n            }\n        }\n    });\n};\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EWith those two helpers I could transform my code to this vanilla JavaScript:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs javascript border\u0022\u003Eon(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027.form-multiple-add\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027click\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E (\u003Cspan class=\u0022hljs-params\u0022\u003E\u003C\/span\u003E) \u003C\/span\u003E{\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Evar\u003C\/span\u003E form = findParent(\u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027.form-multiple\u0027\u003C\/span\u003E);\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E (!form) {\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E;\n    }\n\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Evar\u003C\/span\u003E newIndices = \u003Cspan class=\u0022hljs-built_in\u0022\u003EArray\u003C\/span\u003E.from(form.querySelectorAll(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027[data-index^=new]\u0027\u003C\/span\u003E)).map(\u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E (\u003Cspan class=\u0022hljs-params\u0022\u003Eel\u003C\/span\u003E) \u003C\/span\u003E{\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E el.dataset[\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027index\u0027\u003C\/span\u003E].substr(\u003Cspan class=\u0022hljs-number\u0022\u003E3\u003C\/span\u003E);\n    });\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Evar\u003C\/span\u003E newIndex = newIndices.length ? \u003Cspan class=\u0022hljs-built_in\u0022\u003EMath\u003C\/span\u003E.max.apply(\u003Cspan class=\u0022hljs-literal\u0022\u003Enull\u003C\/span\u003E, newIndices) + \u003Cspan class=\u0022hljs-number\u0022\u003E1\u003C\/span\u003E : \u003Cspan class=\u0022hljs-number\u0022\u003E0\u003C\/span\u003E;\n\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Evar\u003C\/span\u003E template = form.querySelector(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027.form-multiple-add-template\u0027\u003C\/span\u003E).innerHTML.replace(\u003Cspan class=\u0022hljs-regexp\u0022\u003E\/%i%\/g\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027new\u0027\u003C\/span\u003E + newIndex);\n\n    findParent(\u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027tr\u0027\u003C\/span\u003E).insertAdjacentHTML(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027beforebegin\u0027\u003C\/span\u003E, template);\n\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Evar\u003C\/span\u003E firstInput = form.querySelector(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027[data-index=new\u0027\u003C\/span\u003E+newIndex+\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027] :enabled\u0027\u003C\/span\u003E);\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E (firstInput) {\n        firstInput.focus();\n    }\n});\n\non(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027.form-multiple-remove\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027click\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E (\u003Cspan class=\u0022hljs-params\u0022\u003E\u003C\/span\u003E) \u003C\/span\u003E{\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E (!confirm(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027Are you sure?\u0027\u003C\/span\u003E)) {\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E \u003Cspan class=\u0022hljs-literal\u0022\u003Efalse\u003C\/span\u003E;\n    }\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Evar\u003C\/span\u003E row = findParent(\u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027tr\u0027\u003C\/span\u003E);\n    row.parentNode.removeChild(row);\n});\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003ENot bad, is it? \ud83d\ude09\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["coffeescript","javascript","jquery","js","programming","vanilla"],"hasMore":true,"image":"https:\/\/avris.it\/image\/avris-forms-multiple_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris-forms-multiple_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-forms-multiple_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022100.5504587156\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EWhile working on \u003Ca href=\u0022https:\/\/gitlab.com\/Avris\/Forms\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Avris Forms v4.0\u003C\/a\u003E, I\u2019ve decided to migrate some code from \u003Ca href=\u0022http:\/\/coffeescript.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E CoffeScript\u003C\/a\u003E with \u003Ca href=\u0022https:\/\/jquery.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E jQuery\u003C\/a\u003E to \u003Ca href=\u0022http:\/\/vanilla-js.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Vanilla JS\u003C\/a\u003E. And I guess it might be a good idea to share this transition \ud83d\ude09\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris-forms-multiple_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-forms-multiple_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022100.5504587156\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EWhile working on \u003Ca href=\u0022https:\/\/gitlab.com\/Avris\/Forms\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Avris Forms v4.0\u003C\/a\u003E, I\u2019ve decided to migrate some code from \u003Ca href=\u0022http:\/\/coffeescript.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E CoffeScript\u003C\/a\u003E with \u003Ca href=\u0022https:\/\/jquery.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E jQuery\u003C\/a\u003E to \u003Ca href=\u0022http:\/\/vanilla-js.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Vanilla JS\u003C\/a\u003E. And I guess it might be a good idea to share this transition \ud83d\ude09\u003C\/p\u003E\n\u003Cp\u003EThe code handles the form widget visible in the screenshot above. More specifically: those buttons in the right column. Clicking on the green one adds a new element\/row based on a template hidden inside a \u003Ccode\u003E\u0026lt;script\u0026gt;\u003C\/code\u003E tag. Clicking on a red button results in removal of the current row (after asking for a confirmation).\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-js\u0022\u003E$(\u0027body\u0027).on \u0027click\u0027, \u0027.form-multiple-add\u0027, -\u0026gt;\n  $form = $(this).parents(\u0027.form-multiple\u0027)\n  newIndices = $form.find(\u0027[data-index^=new]\u0027).map((i, el) -\u0026gt; el.dataset[\u0027index\u0027].substr(3)).get()\n  newIndex = if newIndices.length then Math.max.apply(null, newIndices) + 1 else 0\n  $template = $($form.find(\u0027.form-multiple-add-template\u0027).html().replace(\/%i%\/g, \u0027new\u0027 + newIndex))\n  $(this).parents(\u0027tr\u0027).before $template\n  $template.find(\u0027:input:enabled:visible:first\u0027).focus()\n\n$(\u0027body\u0027).on \u0027click\u0027, \u0027.form-multiple-remove\u0027, -\u0026gt;\n  return false if !confirm(\u0027Are you sure?\u0027))\n  $(this).parents(\u0027tr\u0027).remove()\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EIt was not a part of the library (as the library was supposed to only provide PHP), instead each project included this part on its own. Which led to code duplication (and the worst kind: between projects) and also kinda prevented me from abandoning CoffeeScript in newer projects, even if I wanted to. \u003C\/p\u003E\n\u003Cp\u003EAnd I did want to, because JavaScript has matured as a language over the last years. An additional level of complexity in my projects simply wasn\u2019t necessary anymore. CoffeeScript did a great job of making fontend scripting bearable, but now it\u2019s slowly time for it to get a deserved retirement.\u003C\/p\u003E\n\u003Cp\u003ESo I\u2019ve decided to integrate the frontend part into the library. Except I shouldn\u2019t be forcing users to use CoffeeScript or jQuery, it should just work out of the box in any project.\u003C\/p\u003E\n\u003Cp\u003ESince CoffeeScript compiles into JS (although usually with from some unnecessary returns and similar features), getting rid of it is really simple. After using \u003Ca href=\u0022http:\/\/js2.coffee\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E js2coffee\u003C\/a\u003E or \u003Ca href=\u0022http:\/\/decaffeinate-project.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E decaffeinate\u003C\/a\u003E we would end up with something like this:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-js\u0022\u003E$(\u0027body\u0027).on(\u0027click\u0027, \u0027.form-multiple-add\u0027, function() {\n    var $form, $template, newIndex, newIndices;\n    $form = $(this).parents(\u0027.form-multiple\u0027);\n    newIndices = $form.find(\u0027[data-index^=new]\u0027).map(function(i, el) {\n        return el.dataset[\u0027index\u0027].substr(3);\n    }).get();\n    newIndex = newIndices.length ? Math.max.apply(null, newIndices) + 1 : 0;\n    $template = $($form.find(\u0027.form-multiple-add-template\u0027).html().replace(\/%i%\/g, \u0027new\u0027 + newIndex));\n    $(this).parents(\u0027tr\u0027).before($template);\n    return $template.find(\u0027:input:enabled:visible:first\u0027).focus();\n});\n\n$(\u0027body\u0027).on(\u0027click\u0027, \u0027.form-multiple-remove\u0027, function() {\n    if (!confirm(\u0027Are you sure?\u0027)) {\n        return false;\n    }\n    return $(this).parents(\u0027tr\u0027).remove();\n});\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003ERemoving the dependency on jQuery is more tricky.\u003C\/p\u003E\n\u003Cp\u003EThere are some \u003Ca href=\u0022http:\/\/youmightnotneedjquery.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E nice lists\u003C\/a\u003E that show you how to replace some jQuery usage with plain JS. Those Javascript versions used to be longer, more complicated and require some browser-specific checks and adjustments. Those times are almost over though (as you can see from the list), so the need for jQuery gets smaller and smaller.\u003C\/p\u003E\n\u003Cp\u003EReplacing those calls from the list with Vanilla JS\u2019s counterparts was not enough in my case. I needed two functionalities more: finding an element\u2019s parent by a selector (\u003Ccode\u003E$el.parents(\u0027.foo\u0027)\u003C\/code\u003E) and binding an event listener to elements matching a selector, even if those elements don\u2019t exist yet at the moment of binding (\u003Ccode\u003E$(\u0027body\u0027).on(\u0027click\u0027, \u0027.foo\u0027, =\u0026gt; ... )\u003C\/code\u003E).\u003C\/p\u003E\n\u003Cp\u003EThey were surprisingly easy to implement:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-js\u0022\u003Evar findParent = function(el, selector) {\n    do {\n        if (el.matches(selector)) {\n            return el;\n        }\n        el = el.parentNode;\n    } while (el \u0026amp;\u0026amp; el.matches);\n};\n\nvar on = function (selector, event, handler) {\n    document.addEventListener(event, function (e) {\n        var match = findParent(e.target, selector);\n        if (match) {\n            var result = handler.apply(match, [e]);\n            if (result === false) {\n                e.preventDefault();\n                e.stopPropagation();\n            }\n        }\n    });\n};\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EWith those two helpers I could transform my code to this vanilla JavaScript:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-js\u0022\u003Eon(\u0027.form-multiple-add\u0027, \u0027click\u0027, function () {\n    var form = findParent(this, \u0027.form-multiple\u0027);\n    if (!form) {\n        return;\n    }\n\n    var newIndices = Array.from(form.querySelectorAll(\u0027[data-index^=new]\u0027)).map(function (el) {\n        return el.dataset[\u0027index\u0027].substr(3);\n    });\n    var newIndex = newIndices.length ? Math.max.apply(null, newIndices) + 1 : 0;\n\n    var template = form.querySelector(\u0027.form-multiple-add-template\u0027).innerHTML.replace(\/%i%\/g, \u0027new\u0027 + newIndex);\n\n    findParent(this, \u0027tr\u0027).insertAdjacentHTML(\u0027beforebegin\u0027, template);\n\n    var firstInput = form.querySelector(\u0027[data-index=new\u0027+newIndex+\u0027] :enabled\u0027);\n    if (firstInput) {\n        firstInput.focus();\n    }\n});\n\non(\u0027.form-multiple-remove\u0027, \u0027click\u0027, function () {\n    if (!confirm(\u0027Are you sure?\u0027)) {\n        return false;\n    }\n    var row = findParent(this, \u0027tr\u0027);\n    row.parentNode.removeChild(row);\n});\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003ENot bad, is it? \ud83d\ude09\u003C\/p\u003E","words":731,"readTime":3,"lang":"en"}}},"projects\/can-i-go-home-now":{"key":"projects\/can-i-go-home-now","type":"article","published":true,"meta":{"createdAt":"2017-04-28T19:43:45+02:00","publishedAt":"2015-12-10T13:39:00+01:00","group":null,"links":[{"icon":"globe-europe","colour":"primary","url":"https:\/\/canigohome.avris.it\/","displayUrl":null},{"icon":"brands gitlab","colour":"secondary","url":"https:\/\/gitlab.com\/Avris\/GoHome","displayUrl":null}],"category":"projects","subcategory":null,"slug":"can-i-go-home-now"},"content":{"en":{"slug":"can-i-go-home-now","title":"Can I go home now?","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/can-i-go-home-now_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022239.24882629108\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAARCAYAAAC1tw6GAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAGbklEQVRIiV2WuW4TXxuHn5kzS+xxbMd2Fi8xTkgiBAWhAAmFCCgiKGhYGi6Aq6DJTXADFAiJkooOmoQKCMIgpKBAEi\/xJHa8jGc861cgRvp\/U56RzvZ7zvO+0rt37yLXdWk0Guzv73N4eEij0aBQKHDr1i10XefLly\/UajWCIKBcLjM\/P08ymcQwDCRJwjAMyuUyAJ1Oh0KhgBACgDAMiaIIWZYxDIMgCBgMBkiSxGQy4cePH+RyOXzfp9VqoaiqyqtXr+j3+xwdHXFycsLdu3fJZrO8fv2alZUV7t27R7PZxLIsjo6OODs7QwhBpVJhbm4Ox3EIw5B8Po9hGLiui6qqSJJEGIaEYUgmkwHAcZx4g0EQMB6PEUIghCAIApSPHz9Sr9dxXZd8Ps\/t27f59OkT79+\/J5\/Ps7y8jO\/7rK+vc3BwQBAEHB8fA1AsFomiCMdxME0zvi0ASZKQZZkoikgmkwghcF0Xx3Hicd\/3MQyDZDJJo9HAcRxEtVrd\/vz5M2tra2xsbPDy5Uva7TbXrl1jeXmZhYUFgiBgOBxSKpUAEEKgqipCCMIwpFQqMT09jaIoWJaFrusAFAoFoigiCAISiQTn5+eYpkkikUBRFPr9Pp1OJ57PdV2UbrfLs2fPaLVavHnzBs\/zWFpaIpfLsbu7C8DMzAySJHF2dkalUsFxHEajEZIkoaoq37594+rVqwCUSiXS6XQcSSqVQpIk\/v8bDAZ4nkcQBERRRLPZpFgsIjRN2378+DEvXrxACMFoNCKZTLK3t4dpmqytraGqKr7v4zgOtm2ztLREJpNBURT+\/PnD6ekppVIJWZYxTRMAXddRFIUgCPB9nyAIcF2XbreLpmlkMhnG4zG9Xg\/f97EsCwB5amqKTqdDLpej0+lgWRYHBwckEgkymQypVCqGLpvNIoTAtm2EEDFL09PT9Pt9PM\/D933a7Tau68ZRRFGEaZpYloUQgkwmQxiGDIdDbNtmMpkgyzKj0QhlcXGR58+f8\/TpU6Iool6vI4RgOBySy+XQdR3DMBBCkMvlkGWZbDaLJEmkUimCIIg3ValU4n+apiFJElEUoaoqxWKRTqeDruuEYYjv+zFfsiyjqiqmaSL29\/e3wzDk69ev3Lx5k3Q6TavVIpVK0e12WVlZIZ1Ok06nmZ2dpVKp\/Of1HB8fx4tOJhMGgwG9Xg9FUUgmk0wmE2zbJgxDxuMxh4eHNJtNRqMRg8EA3\/dJpVJEUfQ3CVVVt\/\/Jq16vU6vVWFlZod1uk0wmWV9fJ5PJkMlkYrgVRUFVVTzPo1QqMZlMGA6HDAYD2u02p6endLtdhBBEUYRlWfi+j+u61Ot1wjDEdV1s22ZqaoowDJmbm\/ubhKqq257nxQAeHR2haRqbm5t0Oh0uX77MhQsXmJ6exrZtHMchCAJmZmZQFOVv7opCuzuicXhAr9fDNE0cx0FRFDzPw7btWBPtdpswDAHQNC3G4t+YAqCqKqqqIssyruvy8+dPPM\/jwYMHzM\/P47oug8EAXdfxfT+ePJ\/PM5lMODw8pFKugjvC933m5uYoFAo0m02GwyGLi4sIIZBlGUVRSCQSWJaFpmn0ej263S6GYZDP51GEEExNTREEQfwioiji169f\/P79O2YhDEMKhQKzs7NIkkS328W2bTzP4\/z8HNd1WV1djQ28uroKwM7ODslkkmKxCMDe3h7VapVisYiu6\/R6PRKJBLlc7q8Yx+MxhmHgeR7pdBrf95FlmStXrnBwcMDi4iKqqsZ2\/ReX67qcnp7G9cuyLFRV5eTkBNM0GY\/HhGGI4zh0Oh16vR75fJ5yuYymaWiahq7rJJNJbNvm\/PycQqGABESqqsYykySJra0tTk5OODk5wbZtxuMxiUQCx3HQNI3JZEK5XMayLC5dukS9XscwDGq1GsPhkO\/fv8cHK5fLTE9Ps76+zo0bN5BlmX6\/T6lUiotyo9GgVqthGAayLMux0BYWFnjy5Ak7Ozvs7Ozgui6SJBEEAaPRCF3XUVWVfD4fl490Os2jR4+4ePEiHz58QJIkNjY2CMMQWZapVqtsbW3x8OFDNjc3Y5Zc1yWbzcbdwXg8\/lv579y5s22aJvfv30dRFN6+fctkMolbhX9Q+74fC83zPBzHYW5ujoWFBSqVCru7u\/T7fVqtFrlcjuvXr+N5HsvLy1SrVVZXVxmNRjHM\/3opx3GoVquxy\/4H69Nv42Fs0AsAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/can-i-go-home-now_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022239.24882629108\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EMissing your cosy home? Come in to find out, if you can stop working already and head back home!\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/can-i-go-home-now_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022478.49765258216\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAARCAYAAAC1tw6GAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAGbklEQVRIiV2WuW4TXxuHn5kzS+xxbMd2Fi8xTkgiBAWhAAmFCCgiKGhYGi6Aq6DJTXADFAiJkooOmoQKCMIgpKBAEi\/xJHa8jGc861cgRvp\/U56RzvZ7zvO+0rt37yLXdWk0Guzv73N4eEij0aBQKHDr1i10XefLly\/UajWCIKBcLjM\/P08ymcQwDCRJwjAMyuUyAJ1Oh0KhgBACgDAMiaIIWZYxDIMgCBgMBkiSxGQy4cePH+RyOXzfp9VqoaiqyqtXr+j3+xwdHXFycsLdu3fJZrO8fv2alZUV7t27R7PZxLIsjo6OODs7QwhBpVJhbm4Ox3EIw5B8Po9hGLiui6qqSJJEGIaEYUgmkwHAcZx4g0EQMB6PEUIghCAIApSPHz9Sr9dxXZd8Ps\/t27f59OkT79+\/J5\/Ps7y8jO\/7rK+vc3BwQBAEHB8fA1AsFomiCMdxME0zvi0ASZKQZZkoikgmkwghcF0Xx3Hicd\/3MQyDZDJJo9HAcRxEtVrd\/vz5M2tra2xsbPDy5Uva7TbXrl1jeXmZhYUFgiBgOBxSKpUAEEKgqipCCMIwpFQqMT09jaIoWJaFrusAFAoFoigiCAISiQTn5+eYpkkikUBRFPr9Pp1OJ57PdV2UbrfLs2fPaLVavHnzBs\/zWFpaIpfLsbu7C8DMzAySJHF2dkalUsFxHEajEZIkoaoq37594+rVqwCUSiXS6XQcSSqVQpIk\/v8bDAZ4nkcQBERRRLPZpFgsIjRN2378+DEvXrxACMFoNCKZTLK3t4dpmqytraGqKr7v4zgOtm2ztLREJpNBURT+\/PnD6ekppVIJWZYxTRMAXddRFIUgCPB9nyAIcF2XbreLpmlkMhnG4zG9Xg\/f97EsCwB5amqKTqdDLpej0+lgWRYHBwckEgkymQypVCqGLpvNIoTAtm2EEDFL09PT9Pt9PM\/D933a7Tau68ZRRFGEaZpYloUQgkwmQxiGDIdDbNtmMpkgyzKj0QhlcXGR58+f8\/TpU6Iool6vI4RgOBySy+XQdR3DMBBCkMvlkGWZbDaLJEmkUimCIIg3ValU4n+apiFJElEUoaoqxWKRTqeDruuEYYjv+zFfsiyjqiqmaSL29\/e3wzDk69ev3Lx5k3Q6TavVIpVK0e12WVlZIZ1Ok06nmZ2dpVKp\/Of1HB8fx4tOJhMGgwG9Xg9FUUgmk0wmE2zbJgxDxuMxh4eHNJtNRqMRg8EA3\/dJpVJEUfQ3CVVVt\/\/Jq16vU6vVWFlZod1uk0wmWV9fJ5PJkMlkYrgVRUFVVTzPo1QqMZlMGA6HDAYD2u02p6endLtdhBBEUYRlWfi+j+u61Ot1wjDEdV1s22ZqaoowDJmbm\/ubhKqq257nxQAeHR2haRqbm5t0Oh0uX77MhQsXmJ6exrZtHMchCAJmZmZQFOVv7opCuzuicXhAr9fDNE0cx0FRFDzPw7btWBPtdpswDAHQNC3G4t+YAqCqKqqqIssyruvy8+dPPM\/jwYMHzM\/P47oug8EAXdfxfT+ePJ\/PM5lMODw8pFKugjvC933m5uYoFAo0m02GwyGLi4sIIZBlGUVRSCQSWJaFpmn0ej263S6GYZDP51GEEExNTREEQfwioiji169f\/P79O2YhDEMKhQKzs7NIkkS328W2bTzP4\/z8HNd1WV1djQ28uroKwM7ODslkkmKxCMDe3h7VapVisYiu6\/R6PRKJBLlc7q8Yx+MxhmHgeR7pdBrf95FlmStXrnBwcMDi4iKqqsZ2\/ReX67qcnp7G9cuyLFRV5eTkBNM0GY\/HhGGI4zh0Oh16vR75fJ5yuYymaWiahq7rJJNJbNvm\/PycQqGABESqqsYykySJra0tTk5OODk5wbZtxuMxiUQCx3HQNI3JZEK5XMayLC5dukS9XscwDGq1GsPhkO\/fv8cHK5fLTE9Ps76+zo0bN5BlmX6\/T6lUiotyo9GgVqthGAayLMux0BYWFnjy5Ak7Ozvs7Ozgui6SJBEEAaPRCF3XUVWVfD4fl490Os2jR4+4ePEiHz58QJIkNjY2CMMQWZapVqtsbW3x8OFDNjc3Y5Zc1yWbzcbdwXg8\/lv579y5s22aJvfv30dRFN6+fctkMolbhX9Q+74fC83zPBzHYW5ujoWFBSqVCru7u\/T7fVqtFrlcjuvXr+N5HsvLy1SrVVZXVxmNRjHM\/3opx3GoVquxy\/4H69Nv42Fs0AsAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/can-i-go-home-now_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022478.49765258216\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EMissing your cosy home? Come in to find out, if you can stop working already and head back home!\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["assetic","countdown","free time","javascript","job","js","micrus","php","programming","programowanie","weekend"],"hasMore":false,"image":"https:\/\/avris.it\/image\/can-i-go-home-now_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/can-i-go-home-now_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/can-i-go-home-now_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022119.62441314554\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EMissing your cosy home? Come in to find out, if you can stop working already and head back home!\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/can-i-go-home-now_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/can-i-go-home-now_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022119.62441314554\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EMissing your cosy home? Come in to find out, if you can stop working already and head back home!\u003C\/p\u003E","words":19,"readTime":null,"lang":"en"}}},"blog\/technology\/proste-potwierdzenie-w-javascripcie-a-rozdzielenie-warstw-aplikacji":{"key":"blog\/technology\/proste-potwierdzenie-w-javascripcie-a-rozdzielenie-warstw-aplikacji","type":"article","published":true,"meta":{"createdAt":"2017-04-28T19:43:44+02:00","publishedAt":"2015-11-15T00:07:00+01:00","group":null,"category":"blog","subcategory":"technology","slug":"proste-potwierdzenie-w-javascripcie-a-rozdzielenie-warstw-aplikacji"},"content":{"pl":{"slug":"proste-potwierdzenie-w-javascripcie-a-rozdzielenie-warstw-aplikacji","title":"Proste potwierdzenie w JavaScripcie, a rozdzielenie warstw aplikacji","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/proste-potwierdzenie-w-javascripcie-a-rozdzielenie-warstw-aplikacji_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022268.48780487805\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAUCAYAAADlep81AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAEo0lEQVRIib2WS4\/l1BGAvzoP2\/f6PvtB98AwPfRoIkE2JLCJlCChSInEht+BWOVPBGUb\/k8UKSEPokiwIauMEMOgnu5hOt3X9vXj+FQWvj28pi\/DIqnNsc+pcn1Vripbfvve7zRNE1AFEVClrCrycQ4oddOSZSn\/L3F\/\/\/BDfnT3Dvfvf07oOkZ5TuharHVEhXVRcPv4mPliwXSS\/++B3vjFzwE4PLzxncO+D\/S9kiT+mR7W1GsuLgsmk5wYIwKIsaRZyrqqEAEwm1XxPqUsVozGOXW9Zjqd4rY5sNZh7bNH533Czs4OqnHYUEUBI0KWZWhUEJCNvrGGfDLBGoubTBAR3D\/+9tfBuULcaJorDwoIqAxnUUGu9vQrXQWuuFWGjat1swxgQA9Y73n9tdcHe\/PEGwDus3v\/xhhD3zb4xBNjjxXLYr5gthyi7bqAEWgZgORrEBFFjWA2sBHdAAkRMKpMFgsenpzw+IsHmDSjaOonQN8W18UGgxAk0MUeEyImNfzq7bd4593fPPv7+h5569dvQmjIkpQQr9dzl7Ma3yghF9QprhaCV2o6ROR6y6eIql5rU60uKLVnVZwzdePrgUaXyqhSnEInytopgqAtVGXJ6dkjUKVeVxjryVJP0wacH6om9pG2bTEiQ0d5S90FVJVRlqIi3D46Iu2hFEgEvlU23wQyZWSthpeWMy7WNbkKJ21NH2Gc5xyNh2hEBN1U8g+9Bug3iUsjX7XZ04AEw2KSMZ5mHN3a53HVkdYtUSMhhOstf6CsDIwFlledeh2Qc5bjecLB7ojRfM7zLx\/zyccfYVSpqmqrk3uPalQjsgl5MnLMffxGZpxzOOdAYF+HDG0bbe6Vg5y9vRliDX3XEpuanfmCw9nse4v6wZcrZqbh4dkZL968SdGkuHHg9OEJRbFmb3+f\/f1dvPfkEVzYzLJ+C1AbIYSeto2Uj1aEk3Pu3H2Z3cViKwzAz+7uo8Ard24CYAUEZblcPtG5CkoiBB2yc7klRa5qAqfnNYk1PH\/4Aqo9jsg\/\/\/gH3n\/\/99jNuA0GWrEoCQZBVJl0HWrCMMUjdAa6ONSsN4NNzZCVplqRCSQKflsNjZ1jb+xIfMK6uKBtwTlLJynPzRbc\/+wehkgwsLaGQmBaK8tG6YAygcoPTjvAINRWEYVmc69RsYCYIUPzbW1\/9p+CxAi7S8fqvMBYR914Znu7\/OSXr3F8fsr64jFdH9jdP2Bdlnzwpz\/TdJc4gWBhbcFESKLQGMUgmKjc6KAwyjoRrCqjCJlu7XpMsA69cYtV78lmjmziKC4r6qpEtGM2TZn5hqUPjLxl9\/CQn776KohQGFgLjOPwRceCNeCBpRpmETKBnQh7CDvRMFYIW5DcWW9xnz\/AWOU5C8XlJc5Y0r2K9qO\/YAj0XY1NUtqmJ5\/kHEwNx3du8vGn9wk99D2MRDBGGFnDCEsOnNqWqUvotcfHSOYcKw+1vf6dOQ0N2XjJ8e0Dvvj0hLotufvj28xvHZFmGesvH\/Hgk3+Rj5RYPqQrcyS07IwMdpJRNjX0YH3CC9mYPRU6oPeKj54XJzNWdU1Jj7eOcYwM\/wpPl\/8CWIcTbntq1pMAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/proste-potwierdzenie-w-javascripcie-a-rozdzielenie-warstw-aplikacji_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022268.48780487805\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EProste zadanie: umie\u015bci\u0107 na stronie przycisk, kt\u00f3ry przekieruje nas do usuwania jakiego\u015b obiektu z bazy, ale zanim to zrobi, spyta, czy na pewno tego chcemy.\u003C\/p\u003E\n\u003Cp\u003EStandardowa cz\u0119\u015b\u0107 interfejsu, mo\u017cliwa do zrealizowania w webie na wiele r\u00f3\u017cnych sposob\u00f3w. Najprostszym z nich jest zwyk\u0142e okienko \u003Ccode\u003Econfirm()\u003C\/code\u003E.\u003C\/p\u003E\n\u003Cp\u003EW wersji najbardziej prymitywnej wykonanie zadania wygl\u0105da mniej wi\u0119cej tak:\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/proste-potwierdzenie-w-javascripcie-a-rozdzielenie-warstw-aplikacji_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022615\u0022 height=\u0022344\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAUCAYAAADlep81AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAEo0lEQVRIib2WS4\/l1BGAvzoP2\/f6PvtB98AwPfRoIkE2JLCJlCChSInEht+BWOVPBGUb\/k8UKSEPokiwIauMEMOgnu5hOt3X9vXj+FQWvj28pi\/DIqnNsc+pcn1Vripbfvve7zRNE1AFEVClrCrycQ4oddOSZSn\/L3F\/\/\/BDfnT3Dvfvf07oOkZ5TuharHVEhXVRcPv4mPliwXSS\/++B3vjFzwE4PLzxncO+D\/S9kiT+mR7W1GsuLgsmk5wYIwKIsaRZyrqqEAEwm1XxPqUsVozGOXW9Zjqd4rY5sNZh7bNH533Czs4OqnHYUEUBI0KWZWhUEJCNvrGGfDLBGoubTBAR3D\/+9tfBuULcaJorDwoIqAxnUUGu9vQrXQWuuFWGjat1swxgQA9Y73n9tdcHe\/PEGwDus3v\/xhhD3zb4xBNjjxXLYr5gthyi7bqAEWgZgORrEBFFjWA2sBHdAAkRMKpMFgsenpzw+IsHmDSjaOonQN8W18UGgxAk0MUeEyImNfzq7bd4593fPPv7+h5569dvQmjIkpQQr9dzl7Ma3yghF9QprhaCV2o6ROR6y6eIql5rU60uKLVnVZwzdePrgUaXyqhSnEInytopgqAtVGXJ6dkjUKVeVxjryVJP0wacH6om9pG2bTEiQ0d5S90FVJVRlqIi3D46Iu2hFEgEvlU23wQyZWSthpeWMy7WNbkKJ21NH2Gc5xyNh2hEBN1U8g+9Bug3iUsjX7XZ04AEw2KSMZ5mHN3a53HVkdYtUSMhhOstf6CsDIwFlledeh2Qc5bjecLB7ojRfM7zLx\/zyccfYVSpqmqrk3uPalQjsgl5MnLMffxGZpxzOOdAYF+HDG0bbe6Vg5y9vRliDX3XEpuanfmCw9nse4v6wZcrZqbh4dkZL968SdGkuHHg9OEJRbFmb3+f\/f1dvPfkEVzYzLJ+C1AbIYSeto2Uj1aEk3Pu3H2Z3cViKwzAz+7uo8Ard24CYAUEZblcPtG5CkoiBB2yc7klRa5qAqfnNYk1PH\/4Aqo9jsg\/\/\/gH3n\/\/99jNuA0GWrEoCQZBVJl0HWrCMMUjdAa6ONSsN4NNzZCVplqRCSQKflsNjZ1jb+xIfMK6uKBtwTlLJynPzRbc\/+wehkgwsLaGQmBaK8tG6YAygcoPTjvAINRWEYVmc69RsYCYIUPzbW1\/9p+CxAi7S8fqvMBYR914Znu7\/OSXr3F8fsr64jFdH9jdP2Bdlnzwpz\/TdJc4gWBhbcFESKLQGMUgmKjc6KAwyjoRrCqjCJlu7XpMsA69cYtV78lmjmziKC4r6qpEtGM2TZn5hqUPjLxl9\/CQn776KohQGFgLjOPwRceCNeCBpRpmETKBnQh7CDvRMFYIW5DcWW9xnz\/AWOU5C8XlJc5Y0r2K9qO\/YAj0XY1NUtqmJ5\/kHEwNx3du8vGn9wk99D2MRDBGGFnDCEsOnNqWqUvotcfHSOYcKw+1vf6dOQ0N2XjJ8e0Dvvj0hLotufvj28xvHZFmGesvH\/Hgk3+Rj5RYPqQrcyS07IwMdpJRNjX0YH3CC9mYPRU6oPeKj54XJzNWdU1Jj7eOcYwM\/wpPl\/8CWIcTbntq1pMAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/proste-potwierdzenie-w-javascripcie-a-rozdzielenie-warstw-aplikacji_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022615\u0022 height=\u0022344\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EProste zadanie: umie\u015bci\u0107 na stronie przycisk, kt\u00f3ry przekieruje nas do usuwania jakiego\u015b obiektu z bazy, ale zanim to zrobi, spyta, czy na pewno tego chcemy.\u003C\/p\u003E\n\u003Cp\u003EStandardowa cz\u0119\u015b\u0107 interfejsu, mo\u017cliwa do zrealizowania w webie na wiele r\u00f3\u017cnych sposob\u00f3w. Najprostszym z nich jest zwyk\u0142e okienko \u003Ccode\u003Econfirm()\u003C\/code\u003E.\u003C\/p\u003E\n\u003Cp\u003EW wersji najbardziej prymitywnej wykonanie zadania wygl\u0105da mniej wi\u0119cej tak:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs xml border\u0022\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;\u003Cspan class=\u0022hljs-name\u0022\u003Ea\u003C\/span\u003E \u003Cspan class=\u0022hljs-attr\u0022\u003Ehref\u003C\/span\u003E=\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022{{ route(\u0027product_delete\u0027, {id: product.id}) }}\u0022\u003C\/span\u003E\n    \u003Cspan class=\u0022hljs-attr\u0022\u003Eonclick\u003C\/span\u003E=\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022return confirm(\u0027{{ \u0027delete.confirm\u0027|l|e }}\u0027)\u0022\u003C\/span\u003E\u0026gt;\u003C\/span\u003E\n    {{ \u0027delete\u0027|l }}\n\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;\/\u003Cspan class=\u0022hljs-name\u0022\u003Ea\u003C\/span\u003E\u0026gt;\u003C\/span\u003E\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EProsta sprawa \u2013 linkujemy do adresu, kt\u00f3ry usunie produkt z bazy, ale przy klikni\u0119ciu pytamy u\u017cytkownika, czy na pewno chce to zrobi\u0107. Je\u015bli nie chce, wtedy \u003Ccode\u003Econfirm()\u003C\/code\u003E zwr\u00f3ci \u003Ccode\u003Efalse\u003C\/code\u003E, a wi\u0119c wykonanie przekierowania zostanie zablokowane.\u003C\/p\u003E\n\u003Cp\u003EJest z tym kodem tylko jeden problem \u2013 mieszamy ze sob\u0105 HTML i JS. A to nie tak powinny dzia\u0142a\u0107 internety.\u003C\/p\u003E\n\u003Cp\u003EPoprawnie napisana strona internetowa sk\u0142ada si\u0119 (oczywi\u015bcie w cz\u0119\u015bci frontendowej) z trzech warstw:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003Ew HTML-u umieszczamy \u003Cstrong\u003Eustrukturyzowane dane\u003C\/strong\u003E,\u003C\/li\u003E\n\u003Cli\u003Ew CSS-ach definiujemy, jak te dane maj\u0105 by\u0107 \u003Cstrong\u003Eprezentowane\u003C\/strong\u003E,\u003C\/li\u003E\n\u003Cli\u003Ea w JS-ie dodajemy wszystkie te \u003Cstrong\u003Efajerwerki\u003C\/strong\u003E i \u015bwiecide\u0142ka, dzi\u0119ki kt\u00f3rym strona jest dynamiczniejsza i atrakcyjniejsza.\u003C\/li\u003E\n\u003C\/ul\u003E\n\u003Cp\u003ENajlepiej, gdyby warstwy te w og\u00f3le si\u0119 ze sob\u0105 nie miesza\u0142y. Dzi\u0119ki temu kod jest czystszy, a warstwy mog\u0105 by\u0107 u\u017cywane i modyfikowane niezale\u017cnie od siebie. Mo\u017cna na przyk\u0142ad w banalnie prosty spos\u00f3b zaimplementowa\u0107 r\u00f3\u017cne sk\u00f3rki na stronie, po prostu podmieniaj\u0105c u\u017cywany akrusz styl\u00f3w na inny. Je\u015bli w HTML-u nie umie\u015bcimy \u017cadnych styl\u00f3w inline (mam nadziej\u0119, \u017ce nikomu cho\u0107 troch\u0119 znaj\u0105cemu temat nie trzeba t\u0142umaczy\u0107, jak z\u0142y jest to pomys\u0142), lecz tylko dane oraz struktur\u0119, w jakiej s\u0105 u\u0142o\u017cone, to ca\u0142kowita zmiana wygl\u0105du strony jest nadzwyczaj \u0142atwa. (Dla przyk\u0142adu cho\u0107by \u003Ca href=\u0022http:\/\/bootswatch.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E bootswatch.com\u003C\/a\u003E albo \u003Ca href=\u0022http:\/\/www.csszengarden.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E csszengarden.com\u003C\/a\u003E \u2013 wszystkie podstrony w dziale \u201cthemes\u201d r\u00f3\u017cni\u0105 si\u0119 tylko jedn\u0105 rzecz\u0105: nazw\u0105 pliku .css)\u003C\/p\u003E\n\u003Cp\u003EDok\u0142adnie to samo tyczy si\u0119 JavaScriptu. Je\u015bli kod wykonywalny umie\u015bcimy bezpo\u015brednio wewn\u0105trz znacznika HTML, nasz kod staje si\u0119 zdecydowanie mniej czytelny i bardziej nara\u017cony na powtarzalno\u015b\u0107. Wprowadzanie w nim potem zmian mo\u017ce si\u0119 okaza\u0107 drog\u0105 przez m\u0119k\u0119. Powiedzmy, \u017ce po jakim\u015b czasie zechcemy zmieni\u0107 to brzydkie okienko \u003Ccode\u003Econfirm()\u003C\/code\u003E na przyk\u0142ad na bootstrapowy \u003Ca href=\u0022http:\/\/getbootstrap.com\/javascript\/#modals\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E modal\u003C\/a\u003E. B\u0119dziemy wtedy musieli znale\u017a\u0107 wszystkie u\u017cycia podobnego kodu w naszym projekcie i przerobi\u0107 ka\u017cde z nich. Po co si\u0119 tak m\u0119czy\u0107?\u003C\/p\u003E\n\u003Cp\u003ENatkn\u0105\u0142em si\u0119 ostatnio na taki oto kod, maj\u0105cy wykona\u0107 nasze proste zadanie bez mieszania ze sob\u0105 warstw aplikacji:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs xml border\u0022\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;\u003Cspan class=\u0022hljs-name\u0022\u003Ea\u003C\/span\u003E \u003Cspan class=\u0022hljs-attr\u0022\u003Eclass\u003C\/span\u003E=\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022js-delete-event\u0022\u003C\/span\u003E \n    \u003Cspan class=\u0022hljs-attr\u0022\u003Ehref\u003C\/span\u003E=\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022javascript:void(0)\u0022\u003C\/span\u003E\n    \u003Cspan class=\u0022hljs-attr\u0022\u003Edata-delete-url\u003C\/span\u003E=\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022{{ route(\u0027product_delete\u0027, {id: product.id}) }}\u0022\u003C\/span\u003E\n    \u003Cspan class=\u0022hljs-attr\u0022\u003Edata-confirm-message\u003C\/span\u003E=\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022{{ \u0027delete.confirm\u0027|l|e }}\u0022\u003C\/span\u003E\u0026gt;\u003C\/span\u003E\n    {{ \u0027delete\u0027|l }}\n\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;\/\u003Cspan class=\u0022hljs-name\u0022\u003Ea\u003C\/span\u003E\u0026gt;\u003C\/span\u003E\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003ENatomiast w pliku JavaScriptu:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs javascript border\u0022\u003E$(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027.js-delete-event\u0027\u003C\/span\u003E).on(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027click\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E(\u003Cspan class=\u0022hljs-params\u0022\u003E\u003C\/span\u003E) \u003C\/span\u003E{\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E (\u003Cspan class=\u0022hljs-literal\u0022\u003Etrue\u003C\/span\u003E == confirm($(\u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E).data(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027confirm-message\u0027\u003C\/span\u003E))) {\n        \u003Cspan class=\u0022hljs-built_in\u0022\u003Ewindow\u003C\/span\u003E.location.href = $(\u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E).data(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027delete-url\u0027\u003C\/span\u003E);\n    }\n});\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EWygl\u0105da na zdecydowanie bardziej skomplikowany ni\u017c powien by\u0107... Niby jest w porz\u0105dku: w HTML-u nie mamy skrypt\u00f3w, a jedno z drugim komunikuje si\u0119 za pomoc\u0105 klas i atrybut\u00f3w \u003Ccode\u003Edata\u003C\/code\u003E, tak jak powinno by\u0107. HTML definiuje, \u017ce link jest klasy \u003Ccode\u003Ejs-delete-event\u003C\/code\u003E, dok\u0105d powinien kierowa\u0107 i jak brzmi przet\u0142umaczona pro\u015bba o potwierdzenie, natomiast JS szuka wszystkich element\u00f3w z klas\u0105 \u003Ccode\u003Ejs-delete-event\u003C\/code\u003E i podpina pod nie listenera, kt\u00f3ry o potwierdzenie faktycznie spyta, i w zale\u017cno\u015bci od odpowiedzi, przekierowuje u\u017cytkownika do strony usuwaj\u0105cej, b\u0105d\u017a te\u017c nie.\u003C\/p\u003E\n\u003Cp\u003EA jednak JS w tym HTML-owym kodzie si\u0119 pojawia, i to w swojej najbrzydszej formie: jako pseudoprotok\u00f3\u0142. Link, zamiast kierowa\u0107 nas do rzeczywistej strony, odsy\u0142a nas do jakiego\u015b \u003Ccode\u003Evoid(0)\u003C\/code\u003E przez nieistniej\u0105cy protok\u00f3\u0142 \u003Ccode\u003Ejavascript\u003C\/code\u003E... Jest to zwyk\u0142y zabieg maj\u0105cy na celu zablokowanie linka, skierowanie go donik\u0105d, ale jak\u017ce strasznie psuje semantyk\u0119 strony...\u003C\/p\u003E\n\u003Cp\u003EI ma w dupie \u003Ca href=\u0022https:\/\/en.wikipedia.org\/wiki\/Progressive_enhancement\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Progressive enhancement\u003C\/a\u003E. A to bardzo \u017ale, mie\u0107 go w dupie...\u003C\/p\u003E\n\u003Cp\u003EW progressive enhancement chodzi mniej wi\u0119cej o to, aby zapewni\u0107 dost\u0119p do wszystkich podstawowych danych na stronie oraz do wszystkich podstawowych funkcji naszej aplikacji dla \u003Cstrong\u003Eka\u017cdego\u003C\/strong\u003E u\u017cytkownika. Nawet je\u015bli u\u017cywa IE6 albo nie daj bogini jakiego\u015b lynxa czy innej wy\u0142\u0105cznie tekstowej przegl\u0105darki. Natomiast im jego przegl\u0105darka jest lepsza, nowocze\u015bniejsza i zgodniejsza ze standardami, tym wi\u0119cej deweloper mo\u017ce zaszale\u0107 z \u0142adnym wygl\u0105dem i wodotryskami.\u003C\/p\u003E\n\u003Cp\u003ENie zawsze u\u017cytkownikowi zadzia\u0142aj\u0105 skrypty. Mo\u017ce CDN z jak\u0105\u015b bibliotek\u0105 zaszwankuje, mo\u017ce user jedzie poci\u0105giem i mu net przerywa, a mo\u017ce po prostu sam je wy\u0142\u0105czy\u0142 (tak, niekt\u00f3rzy to robi\u0105).\u003C\/p\u003E\n\u003Cp\u003EJak w takim przypadku zadzia\u0142a powy\u017cszy kod? Ano w\u0142a\u015bnie, nie zadzia\u0142a w og\u00f3le. Chyba \u017ce user zajrzy w \u017ar\u00f3d\u0142o strony, domy\u015bli si\u0119, o co chodzi, i r\u0119cznie przejdzie do URL-a podanego w atrybucie \u003Ccode\u003Edata-delete-url\u003C\/code\u003E. Powodzenia.\u003C\/p\u003E\n\u003Cp\u003EA wi\u0119c progressive enhancement le\u017cy. Dla pewnej grupy u\u017cytkownik\u00f3w dost\u0119p do wa\u017cnej funkcjonalno\u015bci jest niemo\u017cliwy.\u003C\/p\u003E\n\u003Cp\u003ESp\u00f3jrzmy teraz na inny kod:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs xml border\u0022\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;\u003Cspan class=\u0022hljs-name\u0022\u003Ea\u003C\/span\u003E \u003Cspan class=\u0022hljs-attr\u0022\u003Ehref\u003C\/span\u003E=\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022{{ route(\u0027product_delete\u0027, {id: product.id}) }}\u0022\u003C\/span\u003E \n    \u003Cspan class=\u0022hljs-attr\u0022\u003Edata-confirm\u003C\/span\u003E=\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022{{ \u0027delete.confirm\u0027|l|e }}\u0022\u003C\/span\u003E\u0026gt;\u003C\/span\u003E\n    {{ \u0027delete\u0027|l }}\n\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;\/\u003Cspan class=\u0022hljs-name\u0022\u003Ea\u003C\/span\u003E\u0026gt;\u003C\/span\u003E\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs javascript border\u0022\u003E$(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027a[data-confirm]\u0027\u003C\/span\u003E).click(\u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E(\u003Cspan class=\u0022hljs-params\u0022\u003E\u003C\/span\u003E) \u003C\/span\u003E{\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E confirm($(\u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E).data(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027confirm\u0027\u003C\/span\u003E));\n});\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003ETutaj mamy w HTML-u najzwyczajniejszy w \u015bwiecie link, po prostu z jednym dodatkowym atrybutem. Gdyby z jakiego\u015b powodu nie za\u0142adowa\u0142 si\u0119 skypt, \u015bwiat si\u0119 nie zawali. U\u017cytkownik dalej ma mo\u017cliwo\u015b\u0107 usuni\u0119cia elementu, po prostu jest bardziej nara\u017cony na zrobienie tego przez przypadek, bo nie zobaczy potwierdzenia.\u003C\/p\u003E\n\u003Cp\u003EJe\u015bli natomiast JS dzia\u0142a, skrypt znajdzie wszystkie elementy posiadaj\u0105ce atrybut \u003Ccode\u003Edata-confirm\u003C\/code\u003E i podepnie pod nie listenera, zadaj\u0105cego u\u017cytkownikowi pytanie, kt\u00f3re si\u0119 w tym atrybucie znajduje.\u003C\/p\u003E\n\u003Cp\u003ETen kod jest o wiele lepszy od poprzedniego nie tylko ze wzgl\u0119du na respektowanie progressive enhancement:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003EElement A zosta\u0142 odchudzony ze wszystkich zb\u0119dnych atrybut\u00f3w (czyli po\u0142owy!). W poprzednim kodzie jego autor uda\u0142, \u017ce link donik\u0105d nie kieruje, tylko po to, by p\u00f3\u017aniej przekaza\u0107 odpowiedni URL w osbobnym atrybucie. U\u017cy\u0142 te\u017c specjalnej klasy, po kt\u00f3rej JS mia\u0142 rozpozna\u0107 interesuj\u0105ce go elementy, mimo \u017ce sam fakt posiadania tekstu potwierdzenia ju\u017c dostatecznie jasno identyfikuje elementy, kt\u00f3re powinny wy\u015bwietli\u0107 potwierdzenie.\u003C\/li\u003E\n\u003Cli\u003EWykorzystanli\u015bmy \u015bwietnego ficzera jQuery \u2013 to, \u017ce zwr\u00f3cenie \u003Ccode\u003Efalse\u003C\/code\u003E w event hadlerze automatycznie zatrzymuje propagacj\u0119 zdarzenia. W bardzo elegancki i zwi\u0119z\u0142y spos\u00f3b zatrzymali\u015bmy przekierowanie po klikni\u0119ciu, bez potrzeby uciekania si\u0119 do pseudoprotoko\u0142\u00f3w ani \u003Ccode\u003Eevent.stoppropagation(); event.preventdefault();\u003C\/code\u003E, przy okazji jeszcze pytaj\u0105c o zgod\u0119 u\u017cytkownika \u2013 w jednej prostej linijce!\u003C\/li\u003E\n\u003Cli\u003ENie u\u017cywamy okropnego \u003Ccode\u003Ewindow.location.href\u003C\/code\u003E. Pozwalamy na zwyczajn\u0105 obs\u0142ug\u0119 operacji przekierowania po klikni\u0119ciu w link, po prostu rozszerzaj\u0105c j\u0105 o mo\u017cliwo\u015b\u0107 warunkowego przerwania, zamiast sztucznie i nieelegancko blokowa\u0107 przekierowanie tylko po to, by potem jeszcze sztuczniej wywo\u0142a\u0107 je od nowa...\u003C\/li\u003E\n\u003C\/ul\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["html","javascript","js","programowanie","progressive enhancement","warstwy abstracji","web"],"hasMore":true,"image":"https:\/\/avris.it\/image\/proste-potwierdzenie-w-javascripcie-a-rozdzielenie-warstw-aplikacji_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/proste-potwierdzenie-w-javascripcie-a-rozdzielenie-warstw-aplikacji_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/proste-potwierdzenie-w-javascripcie-a-rozdzielenie-warstw-aplikacji_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022134.24390243902\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EProste zadanie: umie\u015bci\u0107 na stronie przycisk, kt\u00f3ry przekieruje nas do usuwania jakiego\u015b obiektu z bazy, ale zanim to zrobi, spyta, czy na pewno tego chcemy.\u003C\/p\u003E\n\u003Cp\u003EStandardowa cz\u0119\u015b\u0107 interfejsu, mo\u017cliwa do zrealizowania w webie na wiele r\u00f3\u017cnych sposob\u00f3w. Najprostszym z nich jest zwyk\u0142e okienko \u003Ccode\u003Econfirm()\u003C\/code\u003E.\u003C\/p\u003E\n\u003Cp\u003EW wersji najbardziej prymitywnej wykonanie zadania wygl\u0105da mniej wi\u0119cej tak:\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/proste-potwierdzenie-w-javascripcie-a-rozdzielenie-warstw-aplikacji_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/proste-potwierdzenie-w-javascripcie-a-rozdzielenie-warstw-aplikacji_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022134.24390243902\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EProste zadanie: umie\u015bci\u0107 na stronie przycisk, kt\u00f3ry przekieruje nas do usuwania jakiego\u015b obiektu z bazy, ale zanim to zrobi, spyta, czy na pewno tego chcemy.\u003C\/p\u003E\n\u003Cp\u003EStandardowa cz\u0119\u015b\u0107 interfejsu, mo\u017cliwa do zrealizowania w webie na wiele r\u00f3\u017cnych sposob\u00f3w. Najprostszym z nich jest zwyk\u0142e okienko \u003Ccode\u003Econfirm()\u003C\/code\u003E.\u003C\/p\u003E\n\u003Cp\u003EW wersji najbardziej prymitywnej wykonanie zadania wygl\u0105da mniej wi\u0119cej tak:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E\u0026lt;a href=\u0022{{ route(\u0027product_delete\u0027, {id: product.id}) }}\u0022\n    onclick=\u0022return confirm(\u0027{{ \u0027delete.confirm\u0027|l|e }}\u0027)\u0022\u0026gt;\n    {{ \u0027delete\u0027|l }}\n\u0026lt;\/a\u0026gt;\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EProsta sprawa \u2013 linkujemy do adresu, kt\u00f3ry usunie produkt z bazy, ale przy klikni\u0119ciu pytamy u\u017cytkownika, czy na pewno chce to zrobi\u0107. Je\u015bli nie chce, wtedy \u003Ccode\u003Econfirm()\u003C\/code\u003E zwr\u00f3ci \u003Ccode\u003Efalse\u003C\/code\u003E, a wi\u0119c wykonanie przekierowania zostanie zablokowane.\u003C\/p\u003E\n\u003Cp\u003EJest z tym kodem tylko jeden problem \u2013 mieszamy ze sob\u0105 HTML i JS. A to nie tak powinny dzia\u0142a\u0107 internety.\u003C\/p\u003E\n\u003Cp\u003EPoprawnie napisana strona internetowa sk\u0142ada si\u0119 (oczywi\u015bcie w cz\u0119\u015bci frontendowej) z trzech warstw:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003Ew HTML-u umieszczamy \u003Cstrong\u003Eustrukturyzowane dane\u003C\/strong\u003E,\u003C\/li\u003E\n\u003Cli\u003Ew CSS-ach definiujemy, jak te dane maj\u0105 by\u0107 \u003Cstrong\u003Eprezentowane\u003C\/strong\u003E,\u003C\/li\u003E\n\u003Cli\u003Ea w JS-ie dodajemy wszystkie te \u003Cstrong\u003Efajerwerki\u003C\/strong\u003E i \u015bwiecide\u0142ka, dzi\u0119ki kt\u00f3rym strona jest dynamiczniejsza i atrakcyjniejsza.\u003C\/li\u003E\n\u003C\/ul\u003E\n\u003Cp\u003ENajlepiej, gdyby warstwy te w og\u00f3le si\u0119 ze sob\u0105 nie miesza\u0142y. Dzi\u0119ki temu kod jest czystszy, a warstwy mog\u0105 by\u0107 u\u017cywane i modyfikowane niezale\u017cnie od siebie. Mo\u017cna na przyk\u0142ad w banalnie prosty spos\u00f3b zaimplementowa\u0107 r\u00f3\u017cne sk\u00f3rki na stronie, po prostu podmieniaj\u0105c u\u017cywany akrusz styl\u00f3w na inny. Je\u015bli w HTML-u nie umie\u015bcimy \u017cadnych styl\u00f3w inline (mam nadziej\u0119, \u017ce nikomu cho\u0107 troch\u0119 znaj\u0105cemu temat nie trzeba t\u0142umaczy\u0107, jak z\u0142y jest to pomys\u0142), lecz tylko dane oraz struktur\u0119, w jakiej s\u0105 u\u0142o\u017cone, to ca\u0142kowita zmiana wygl\u0105du strony jest nadzwyczaj \u0142atwa. (Dla przyk\u0142adu cho\u0107by \u003Ca href=\u0022http:\/\/bootswatch.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E bootswatch.com\u003C\/a\u003E albo \u003Ca href=\u0022http:\/\/www.csszengarden.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E csszengarden.com\u003C\/a\u003E \u2013 wszystkie podstrony w dziale \u201cthemes\u201d r\u00f3\u017cni\u0105 si\u0119 tylko jedn\u0105 rzecz\u0105: nazw\u0105 pliku .css)\u003C\/p\u003E\n\u003Cp\u003EDok\u0142adnie to samo tyczy si\u0119 JavaScriptu. Je\u015bli kod wykonywalny umie\u015bcimy bezpo\u015brednio wewn\u0105trz znacznika HTML, nasz kod staje si\u0119 zdecydowanie mniej czytelny i bardziej nara\u017cony na powtarzalno\u015b\u0107. Wprowadzanie w nim potem zmian mo\u017ce si\u0119 okaza\u0107 drog\u0105 przez m\u0119k\u0119. Powiedzmy, \u017ce po jakim\u015b czasie zechcemy zmieni\u0107 to brzydkie okienko \u003Ccode\u003Econfirm()\u003C\/code\u003E na przyk\u0142ad na bootstrapowy \u003Ca href=\u0022http:\/\/getbootstrap.com\/javascript\/#modals\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E modal\u003C\/a\u003E. B\u0119dziemy wtedy musieli znale\u017a\u0107 wszystkie u\u017cycia podobnego kodu w naszym projekcie i przerobi\u0107 ka\u017cde z nich. Po co si\u0119 tak m\u0119czy\u0107?\u003C\/p\u003E\n\u003Cp\u003ENatkn\u0105\u0142em si\u0119 ostatnio na taki oto kod, maj\u0105cy wykona\u0107 nasze proste zadanie bez mieszania ze sob\u0105 warstw aplikacji:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E\u0026lt;a class=\u0022js-delete-event\u0022 \n    href=\u0022javascript:void(0)\u0022\n    data-delete-url=\u0022{{ route(\u0027product_delete\u0027, {id: product.id}) }}\u0022\n    data-confirm-message=\u0022{{ \u0027delete.confirm\u0027|l|e }}\u0022\u0026gt;\n    {{ \u0027delete\u0027|l }}\n\u0026lt;\/a\u0026gt;\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003ENatomiast w pliku JavaScriptu:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E$(\u0027.js-delete-event\u0027).on(\u0027click\u0027, function() {\n    if (true == confirm($(this).data(\u0027confirm-message\u0027))) {\n        window.location.href = $(this).data(\u0027delete-url\u0027);\n    }\n});\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EWygl\u0105da na zdecydowanie bardziej skomplikowany ni\u017c powien by\u0107... Niby jest w porz\u0105dku: w HTML-u nie mamy skrypt\u00f3w, a jedno z drugim komunikuje si\u0119 za pomoc\u0105 klas i atrybut\u00f3w \u003Ccode\u003Edata\u003C\/code\u003E, tak jak powinno by\u0107. HTML definiuje, \u017ce link jest klasy \u003Ccode\u003Ejs-delete-event\u003C\/code\u003E, dok\u0105d powinien kierowa\u0107 i jak brzmi przet\u0142umaczona pro\u015bba o potwierdzenie, natomiast JS szuka wszystkich element\u00f3w z klas\u0105 \u003Ccode\u003Ejs-delete-event\u003C\/code\u003E i podpina pod nie listenera, kt\u00f3ry o potwierdzenie faktycznie spyta, i w zale\u017cno\u015bci od odpowiedzi, przekierowuje u\u017cytkownika do strony usuwaj\u0105cej, b\u0105d\u017a te\u017c nie.\u003C\/p\u003E\n\u003Cp\u003EA jednak JS w tym HTML-owym kodzie si\u0119 pojawia, i to w swojej najbrzydszej formie: jako pseudoprotok\u00f3\u0142. Link, zamiast kierowa\u0107 nas do rzeczywistej strony, odsy\u0142a nas do jakiego\u015b \u003Ccode\u003Evoid(0)\u003C\/code\u003E przez nieistniej\u0105cy protok\u00f3\u0142 \u003Ccode\u003Ejavascript\u003C\/code\u003E... Jest to zwyk\u0142y zabieg maj\u0105cy na celu zablokowanie linka, skierowanie go donik\u0105d, ale jak\u017ce strasznie psuje semantyk\u0119 strony...\u003C\/p\u003E\n\u003Cp\u003EI ma w dupie \u003Ca href=\u0022https:\/\/en.wikipedia.org\/wiki\/Progressive_enhancement\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Progressive enhancement\u003C\/a\u003E. A to bardzo \u017ale, mie\u0107 go w dupie...\u003C\/p\u003E\n\u003Cp\u003EW progressive enhancement chodzi mniej wi\u0119cej o to, aby zapewni\u0107 dost\u0119p do wszystkich podstawowych danych na stronie oraz do wszystkich podstawowych funkcji naszej aplikacji dla \u003Cstrong\u003Eka\u017cdego\u003C\/strong\u003E u\u017cytkownika. Nawet je\u015bli u\u017cywa IE6 albo nie daj bogini jakiego\u015b lynxa czy innej wy\u0142\u0105cznie tekstowej przegl\u0105darki. Natomiast im jego przegl\u0105darka jest lepsza, nowocze\u015bniejsza i zgodniejsza ze standardami, tym wi\u0119cej deweloper mo\u017ce zaszale\u0107 z \u0142adnym wygl\u0105dem i wodotryskami.\u003C\/p\u003E\n\u003Cp\u003ENie zawsze u\u017cytkownikowi zadzia\u0142aj\u0105 skrypty. Mo\u017ce CDN z jak\u0105\u015b bibliotek\u0105 zaszwankuje, mo\u017ce user jedzie poci\u0105giem i mu net przerywa, a mo\u017ce po prostu sam je wy\u0142\u0105czy\u0142 (tak, niekt\u00f3rzy to robi\u0105).\u003C\/p\u003E\n\u003Cp\u003EJak w takim przypadku zadzia\u0142a powy\u017cszy kod? Ano w\u0142a\u015bnie, nie zadzia\u0142a w og\u00f3le. Chyba \u017ce user zajrzy w \u017ar\u00f3d\u0142o strony, domy\u015bli si\u0119, o co chodzi, i r\u0119cznie przejdzie do URL-a podanego w atrybucie \u003Ccode\u003Edata-delete-url\u003C\/code\u003E. Powodzenia.\u003C\/p\u003E\n\u003Cp\u003EA wi\u0119c progressive enhancement le\u017cy. Dla pewnej grupy u\u017cytkownik\u00f3w dost\u0119p do wa\u017cnej funkcjonalno\u015bci jest niemo\u017cliwy.\u003C\/p\u003E\n\u003Cp\u003ESp\u00f3jrzmy teraz na inny kod:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E\u0026lt;a href=\u0022{{ route(\u0027product_delete\u0027, {id: product.id}) }}\u0022 \n    data-confirm=\u0022{{ \u0027delete.confirm\u0027|l|e }}\u0022\u0026gt;\n    {{ \u0027delete\u0027|l }}\n\u0026lt;\/a\u0026gt;\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cpre\u003E\u003Ccode\u003E$(\u0027a[data-confirm]\u0027).click(function() {\n    return confirm($(this).data(\u0027confirm\u0027));\n});\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003ETutaj mamy w HTML-u najzwyczajniejszy w \u015bwiecie link, po prostu z jednym dodatkowym atrybutem. Gdyby z jakiego\u015b powodu nie za\u0142adowa\u0142 si\u0119 skypt, \u015bwiat si\u0119 nie zawali. U\u017cytkownik dalej ma mo\u017cliwo\u015b\u0107 usuni\u0119cia elementu, po prostu jest bardziej nara\u017cony na zrobienie tego przez przypadek, bo nie zobaczy potwierdzenia.\u003C\/p\u003E\n\u003Cp\u003EJe\u015bli natomiast JS dzia\u0142a, skrypt znajdzie wszystkie elementy posiadaj\u0105ce atrybut \u003Ccode\u003Edata-confirm\u003C\/code\u003E i podepnie pod nie listenera, zadaj\u0105cego u\u017cytkownikowi pytanie, kt\u00f3re si\u0119 w tym atrybucie znajduje.\u003C\/p\u003E\n\u003Cp\u003ETen kod jest o wiele lepszy od poprzedniego nie tylko ze wzgl\u0119du na respektowanie progressive enhancement:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003EElement A zosta\u0142 odchudzony ze wszystkich zb\u0119dnych atrybut\u00f3w (czyli po\u0142owy!). W poprzednim kodzie jego autor uda\u0142, \u017ce link donik\u0105d nie kieruje, tylko po to, by p\u00f3\u017aniej przekaza\u0107 odpowiedni URL w osbobnym atrybucie. U\u017cy\u0142 te\u017c specjalnej klasy, po kt\u00f3rej JS mia\u0142 rozpozna\u0107 interesuj\u0105ce go elementy, mimo \u017ce sam fakt posiadania tekstu potwierdzenia ju\u017c dostatecznie jasno identyfikuje elementy, kt\u00f3re powinny wy\u015bwietli\u0107 potwierdzenie.\u003C\/li\u003E\n\u003Cli\u003EWykorzystanli\u015bmy \u015bwietnego ficzera jQuery \u2013 to, \u017ce zwr\u00f3cenie \u003Ccode\u003Efalse\u003C\/code\u003E w event hadlerze automatycznie zatrzymuje propagacj\u0119 zdarzenia. W bardzo elegancki i zwi\u0119z\u0142y spos\u00f3b zatrzymali\u015bmy przekierowanie po klikni\u0119ciu, bez potrzeby uciekania si\u0119 do pseudoprotoko\u0142\u00f3w ani \u003Ccode\u003Eevent.stoppropagation(); event.preventdefault();\u003C\/code\u003E, przy okazji jeszcze pytaj\u0105c o zgod\u0119 u\u017cytkownika \u2013 w jednej prostej linijce!\u003C\/li\u003E\n\u003Cli\u003ENie u\u017cywamy okropnego \u003Ccode\u003Ewindow.location.href\u003C\/code\u003E. Pozwalamy na zwyczajn\u0105 obs\u0142ug\u0119 operacji przekierowania po klikni\u0119ciu w link, po prostu rozszerzaj\u0105c j\u0105 o mo\u017cliwo\u015b\u0107 warunkowego przerwania, zamiast sztucznie i nieelegancko blokowa\u0107 przekierowanie tylko po to, by potem jeszcze sztuczniej wywo\u0142a\u0107 je od nowa...\u003C\/li\u003E\n\u003C\/ul\u003E","words":1140,"readTime":5,"lang":"pl"}}}}}