├── assets
├── css
│ └── main.min.css
├── fonts
│ ├── inter-v12-latin-500.woff2
│ ├── inter-v12-latin-600.woff2
│ ├── inter-v12-latin-800.woff2
│ └── inter-v12-latin-regular.woff2
├── images
│ ├── apple-touch-icon.png
│ ├── banner-1544x500.png
│ ├── banner-772x250.png
│ ├── favicon.ico
│ ├── icon-128.png
│ ├── icon-128x128.png
│ ├── icon-16.png
│ ├── icon-192.png
│ ├── icon-196.png
│ ├── icon-256x256.png
│ ├── icon-32.png
│ ├── icon-48.png
│ ├── icon-96.png
│ ├── icon-og.png
│ ├── icon-rounded.png
│ ├── icon-square.png
│ ├── illustration-1.png
│ ├── illustration-1.svg
│ ├── illustration-and.png
│ ├── illustration-and.svg
│ ├── illustration-og.png
│ ├── right-triangle-02.png
│ ├── right-triangle-03.png
│ ├── right-triangle-example.png
│ ├── screenshot-1.png
│ ├── screenshot-2.png
│ └── triangle.svg
└── js
│ ├── all-calculators.js
│ ├── app.js
│ ├── calculator.js
│ ├── chart.js
│ ├── datepicker.js
│ ├── dialog-table.js
│ ├── dropdown-icon.js
│ ├── fractions.js
│ ├── functions.js
│ ├── hourpicker.js
│ ├── lib
│ ├── air-datepicker.js
│ ├── chartjs
│ │ ├── chart.js
│ │ ├── chart.js.map
│ │ ├── chart.min.js
│ │ ├── chart.umd.js
│ │ ├── chart.umd.js.map
│ │ ├── chunks
│ │ │ ├── helpers.core.d.ts
│ │ │ ├── helpers.segment.js
│ │ │ └── helpers.segment.js.map
│ │ ├── helpers.d.ts
│ │ ├── helpers.js
│ │ ├── helpers.js.map
│ │ └── types.d.ts
│ ├── input-mask.min.js
│ ├── katex
│ │ ├── auto-render.min.js
│ │ ├── fonts
│ │ │ ├── KaTeX_AMS-Regular.ttf
│ │ │ ├── KaTeX_AMS-Regular.woff
│ │ │ ├── KaTeX_AMS-Regular.woff2
│ │ │ ├── KaTeX_Caligraphic-Bold.ttf
│ │ │ ├── KaTeX_Caligraphic-Bold.woff
│ │ │ ├── KaTeX_Caligraphic-Bold.woff2
│ │ │ ├── KaTeX_Caligraphic-Regular.ttf
│ │ │ ├── KaTeX_Caligraphic-Regular.woff
│ │ │ ├── KaTeX_Caligraphic-Regular.woff2
│ │ │ ├── KaTeX_Fraktur-Bold.ttf
│ │ │ ├── KaTeX_Fraktur-Bold.woff
│ │ │ ├── KaTeX_Fraktur-Bold.woff2
│ │ │ ├── KaTeX_Fraktur-Regular.ttf
│ │ │ ├── KaTeX_Fraktur-Regular.woff
│ │ │ ├── KaTeX_Fraktur-Regular.woff2
│ │ │ ├── KaTeX_Main-Bold.ttf
│ │ │ ├── KaTeX_Main-Bold.woff
│ │ │ ├── KaTeX_Main-Bold.woff2
│ │ │ ├── KaTeX_Main-BoldItalic.ttf
│ │ │ ├── KaTeX_Main-BoldItalic.woff
│ │ │ ├── KaTeX_Main-BoldItalic.woff2
│ │ │ ├── KaTeX_Main-Italic.ttf
│ │ │ ├── KaTeX_Main-Italic.woff
│ │ │ ├── KaTeX_Main-Italic.woff2
│ │ │ ├── KaTeX_Main-Regular.ttf
│ │ │ ├── KaTeX_Main-Regular.woff
│ │ │ ├── KaTeX_Main-Regular.woff2
│ │ │ ├── KaTeX_Math-BoldItalic.ttf
│ │ │ ├── KaTeX_Math-BoldItalic.woff
│ │ │ ├── KaTeX_Math-BoldItalic.woff2
│ │ │ ├── KaTeX_Math-Italic.ttf
│ │ │ ├── KaTeX_Math-Italic.woff
│ │ │ ├── KaTeX_Math-Italic.woff2
│ │ │ ├── KaTeX_SansSerif-Bold.ttf
│ │ │ ├── KaTeX_SansSerif-Bold.woff
│ │ │ ├── KaTeX_SansSerif-Bold.woff2
│ │ │ ├── KaTeX_SansSerif-Italic.ttf
│ │ │ ├── KaTeX_SansSerif-Italic.woff
│ │ │ ├── KaTeX_SansSerif-Italic.woff2
│ │ │ ├── KaTeX_SansSerif-Regular.ttf
│ │ │ ├── KaTeX_SansSerif-Regular.woff
│ │ │ ├── KaTeX_SansSerif-Regular.woff2
│ │ │ ├── KaTeX_Script-Regular.ttf
│ │ │ ├── KaTeX_Script-Regular.woff
│ │ │ ├── KaTeX_Script-Regular.woff2
│ │ │ ├── KaTeX_Size1-Regular.ttf
│ │ │ ├── KaTeX_Size1-Regular.woff
│ │ │ ├── KaTeX_Size1-Regular.woff2
│ │ │ ├── KaTeX_Size2-Regular.ttf
│ │ │ ├── KaTeX_Size2-Regular.woff
│ │ │ ├── KaTeX_Size2-Regular.woff2
│ │ │ ├── KaTeX_Size3-Regular.ttf
│ │ │ ├── KaTeX_Size3-Regular.woff
│ │ │ ├── KaTeX_Size3-Regular.woff2
│ │ │ ├── KaTeX_Size4-Regular.ttf
│ │ │ ├── KaTeX_Size4-Regular.woff
│ │ │ ├── KaTeX_Size4-Regular.woff2
│ │ │ ├── KaTeX_Typewriter-Regular.ttf
│ │ │ ├── KaTeX_Typewriter-Regular.woff
│ │ │ └── KaTeX_Typewriter-Regular.woff2
│ │ ├── katex.min.css
│ │ └── katex.min.js
│ ├── lazysizes.min.js
│ └── math.min.js
│ ├── mask.js
│ ├── module.js
│ ├── options.js
│ ├── themes.js
│ └── timepicker.js
├── ci_right_triangle_calculator.php
├── index.html
├── plugin.php
├── readme.md
└── readme.txt
/assets/fonts/inter-v12-latin-500.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pub-calculator-io/right-triangle-calculator/262159fa214b4b216ed779c382de4b0e1fb84bff/assets/fonts/inter-v12-latin-500.woff2
--------------------------------------------------------------------------------
/assets/fonts/inter-v12-latin-600.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pub-calculator-io/right-triangle-calculator/262159fa214b4b216ed779c382de4b0e1fb84bff/assets/fonts/inter-v12-latin-600.woff2
--------------------------------------------------------------------------------
/assets/fonts/inter-v12-latin-800.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pub-calculator-io/right-triangle-calculator/262159fa214b4b216ed779c382de4b0e1fb84bff/assets/fonts/inter-v12-latin-800.woff2
--------------------------------------------------------------------------------
/assets/fonts/inter-v12-latin-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pub-calculator-io/right-triangle-calculator/262159fa214b4b216ed779c382de4b0e1fb84bff/assets/fonts/inter-v12-latin-regular.woff2
--------------------------------------------------------------------------------
/assets/images/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pub-calculator-io/right-triangle-calculator/262159fa214b4b216ed779c382de4b0e1fb84bff/assets/images/apple-touch-icon.png
--------------------------------------------------------------------------------
/assets/images/banner-1544x500.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pub-calculator-io/right-triangle-calculator/262159fa214b4b216ed779c382de4b0e1fb84bff/assets/images/banner-1544x500.png
--------------------------------------------------------------------------------
/assets/images/banner-772x250.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pub-calculator-io/right-triangle-calculator/262159fa214b4b216ed779c382de4b0e1fb84bff/assets/images/banner-772x250.png
--------------------------------------------------------------------------------
/assets/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pub-calculator-io/right-triangle-calculator/262159fa214b4b216ed779c382de4b0e1fb84bff/assets/images/favicon.ico
--------------------------------------------------------------------------------
/assets/images/icon-128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pub-calculator-io/right-triangle-calculator/262159fa214b4b216ed779c382de4b0e1fb84bff/assets/images/icon-128.png
--------------------------------------------------------------------------------
/assets/images/icon-128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pub-calculator-io/right-triangle-calculator/262159fa214b4b216ed779c382de4b0e1fb84bff/assets/images/icon-128x128.png
--------------------------------------------------------------------------------
/assets/images/icon-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pub-calculator-io/right-triangle-calculator/262159fa214b4b216ed779c382de4b0e1fb84bff/assets/images/icon-16.png
--------------------------------------------------------------------------------
/assets/images/icon-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pub-calculator-io/right-triangle-calculator/262159fa214b4b216ed779c382de4b0e1fb84bff/assets/images/icon-192.png
--------------------------------------------------------------------------------
/assets/images/icon-196.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pub-calculator-io/right-triangle-calculator/262159fa214b4b216ed779c382de4b0e1fb84bff/assets/images/icon-196.png
--------------------------------------------------------------------------------
/assets/images/icon-256x256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pub-calculator-io/right-triangle-calculator/262159fa214b4b216ed779c382de4b0e1fb84bff/assets/images/icon-256x256.png
--------------------------------------------------------------------------------
/assets/images/icon-32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pub-calculator-io/right-triangle-calculator/262159fa214b4b216ed779c382de4b0e1fb84bff/assets/images/icon-32.png
--------------------------------------------------------------------------------
/assets/images/icon-48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pub-calculator-io/right-triangle-calculator/262159fa214b4b216ed779c382de4b0e1fb84bff/assets/images/icon-48.png
--------------------------------------------------------------------------------
/assets/images/icon-96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pub-calculator-io/right-triangle-calculator/262159fa214b4b216ed779c382de4b0e1fb84bff/assets/images/icon-96.png
--------------------------------------------------------------------------------
/assets/images/icon-og.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pub-calculator-io/right-triangle-calculator/262159fa214b4b216ed779c382de4b0e1fb84bff/assets/images/icon-og.png
--------------------------------------------------------------------------------
/assets/images/icon-rounded.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pub-calculator-io/right-triangle-calculator/262159fa214b4b216ed779c382de4b0e1fb84bff/assets/images/icon-rounded.png
--------------------------------------------------------------------------------
/assets/images/icon-square.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pub-calculator-io/right-triangle-calculator/262159fa214b4b216ed779c382de4b0e1fb84bff/assets/images/icon-square.png
--------------------------------------------------------------------------------
/assets/images/illustration-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pub-calculator-io/right-triangle-calculator/262159fa214b4b216ed779c382de4b0e1fb84bff/assets/images/illustration-1.png
--------------------------------------------------------------------------------
/assets/images/illustration-and.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pub-calculator-io/right-triangle-calculator/262159fa214b4b216ed779c382de4b0e1fb84bff/assets/images/illustration-and.png
--------------------------------------------------------------------------------
/assets/images/illustration-og.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pub-calculator-io/right-triangle-calculator/262159fa214b4b216ed779c382de4b0e1fb84bff/assets/images/illustration-og.png
--------------------------------------------------------------------------------
/assets/images/right-triangle-02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pub-calculator-io/right-triangle-calculator/262159fa214b4b216ed779c382de4b0e1fb84bff/assets/images/right-triangle-02.png
--------------------------------------------------------------------------------
/assets/images/right-triangle-03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pub-calculator-io/right-triangle-calculator/262159fa214b4b216ed779c382de4b0e1fb84bff/assets/images/right-triangle-03.png
--------------------------------------------------------------------------------
/assets/images/right-triangle-example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pub-calculator-io/right-triangle-calculator/262159fa214b4b216ed779c382de4b0e1fb84bff/assets/images/right-triangle-example.png
--------------------------------------------------------------------------------
/assets/images/screenshot-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pub-calculator-io/right-triangle-calculator/262159fa214b4b216ed779c382de4b0e1fb84bff/assets/images/screenshot-1.png
--------------------------------------------------------------------------------
/assets/images/screenshot-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pub-calculator-io/right-triangle-calculator/262159fa214b4b216ed779c382de4b0e1fb84bff/assets/images/screenshot-2.png
--------------------------------------------------------------------------------
/assets/images/triangle.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/assets/js/app.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | window._ = document.getElementById.bind(document);
4 | window.$ = document.querySelector.bind(document);
5 | window.$$ = document.querySelectorAll.bind(document);
6 |
7 | console.log('Script is OK! ༼ つ ◕_◕ ༽つ')
8 | // IS MAIN PAGE
9 | // if(window.location.pathname === '/') document.body.classList.add('isMainPage')
10 |
11 | // DIALOG TABLE
12 | if(document.querySelector('.result-table__dialog')) {
13 | import('./dialog-table.js').then(e => {
14 | console.log("Dialog table loaded (づ ◕‿◕ )づ")
15 | }).catch(e => {
16 | console.log("Sorry, dialog tables not loaded (ಥ﹏ಥ)", e)
17 | })
18 | }
19 | // MASK
20 | if(document.querySelector('[data-inputmask]')) {
21 | import('./mask.js').then(e => {
22 | console.log("Mask loaded (づ ◕‿◕ )づ")
23 | }).catch(e => {
24 | console.log("Sorry, masks not loaded (ಥ﹏ಥ)", e)
25 | })
26 | }
27 | // DATEPICKER
28 | if(document.querySelector('.datepicker')) {
29 | import('./datepicker.js').then(e => {
30 | console.log("Datepicker loaded (づ ◕‿◕ )づ")
31 | }).catch(e => {
32 | console.log("Sorry, datepicker not loaded (ಥ﹏ಥ)", e)
33 | })
34 | }
35 | // TIMEPICKER
36 | if(document.querySelector('.timepicker-input')) {
37 | import('./timepicker.js').then(e => {
38 | console.log("Timepicker loaded (づ ◕‿◕ )づ")
39 | }).catch(e => {
40 | console.log("Sorry, timepicker not loaded (ಥ﹏ಥ)", e)
41 | })
42 | }
43 | // HOURPICKER
44 | if(document.querySelector('.hourpicker-input')) {
45 | import('./hourpicker.js').then(e => {
46 | console.log("Hourpicker loaded (づ ◕‿◕ )づ")
47 | }).catch(e => {
48 | console.log("Sorry, Hourpicker not loaded (ಥ﹏ಥ)", e)
49 | })
50 | }
51 | // OPTIONS
52 | if(document.querySelector('.calculator-content--options')) {
53 | import('./options.js').then(e => {
54 | console.log("Options loaded (づ ◕‿◕ )づ")
55 | }).catch(e => {
56 | console.log("Sorry, options not loaded (ಥ﹏ಥ)", e)
57 | })
58 | }
59 | // ICON DROPDOWN
60 | if(document.querySelector('.dropdown-icon')) {
61 | import('./dropdown-icon.js').then(e => {
62 | console.log("Dropdown-icon loaded (づ ◕‿◕ )づ")
63 | }).catch(e => {
64 | console.log("Sorry, dropdown-icon not loaded (ಥ﹏ಥ)", e)
65 | })
66 | }
67 |
68 | // MODAL
69 | const MODAL_OPENERS = document.querySelectorAll('.js-modal-open')
70 | const MODAL_CLOSERS = document.querySelectorAll('.js-modal-close')
71 | const MODAL_WINDOW = document.querySelector('.modal-window')
72 |
73 | let currentShare = 0
74 | let isOpenPopupHeader = false;
75 | let focusedElement = 0;
76 |
77 | const closeAll = () => {
78 | MODAL_SEARCH.value = ''
79 | MODAL_SEARCH_LIST.classList.remove('modal-search__list--error')
80 | MODAL_SEARCH_LIST.classList.remove('modal-search__list--active')
81 | MODAL_OPENERS.forEach(MODAL_OPENER => {
82 | const MODAL_ID = MODAL_OPENER.getAttribute('data-modal')
83 | const MODAL = document.querySelector(`.modal-${MODAL_ID}`)
84 | MODAL.classList.remove(`modal-${MODAL_ID}--active`)
85 | })
86 | }
87 |
88 | window.addEventListener('click', (e) => {
89 | let controllerTheme = document.querySelector('#popup-theme')
90 | let controllerLang = document.querySelector('#popup-lang')
91 | if(isOpenPopupHeader && !(e.composedPath().includes(controllerLang) || e.composedPath().includes(controllerTheme))) {
92 | isOpenPopupHeader = false
93 | document.querySelector('.modal-lang--active')?.classList.remove(`modal-lang--active`)
94 | document.querySelector('.modal-theme--active')?.classList.remove(`modal-theme--active`)
95 | }
96 | })
97 |
98 | window.addEventListener('keydown', (e) => {
99 | if(e.key === 'Escape') {
100 | MODAL_WINDOW.classList.remove('modal-window--active')
101 | closeAll()
102 | }
103 |
104 | if((e.metaKey && e.key === 'k') || (e.ctrlKey && e.key === 'k')) {
105 | closeAll();
106 | $('.modal-search__input').focus();
107 | MODAL_WINDOW.classList.add(`modal-window--active`)
108 | $('.modal-search').classList.toggle(`modal-search--active`);
109 | }
110 |
111 | if(!MODAL_WINDOW) return;
112 |
113 | if(e.key === 'ArrowUp') {
114 | let listItem = [...MODAL_SEARCH_LIST_CONTENT.children]
115 | if(focusedElement - 1 < 0) {
116 | focusedElement = listItem.length - 1
117 | } else {
118 | focusedElement--
119 | }
120 | listItem[focusedElement]?.focus()
121 | // listItem[focusedElement].scrollIntoView(true)
122 | }
123 |
124 | if(e.key === 'ArrowDown') {
125 | let listItem = [...MODAL_SEARCH_LIST_CONTENT.children]
126 | listItem[focusedElement]?.focus()
127 | if(focusedElement + 1 > listItem.length - 1) {
128 | focusedElement = 0
129 | } else {
130 | focusedElement++
131 | }
132 | }
133 | })
134 |
135 | if(MODAL_WINDOW) {
136 | MODAL_WINDOW.addEventListener('click', (e) => {
137 | if(e.target.classList.contains('modal-window')) {
138 | MODAL_WINDOW.classList.remove(`modal-window--active`)
139 | MODAL_WINDOW.classList.remove(`modal-window--active-mini`)
140 | closeAll()
141 | }
142 | })
143 | }
144 | if(MODAL_OPENERS.length > 0) {
145 | MODAL_OPENERS.forEach(MODAL_OPENER => {
146 | MODAL_OPENER.addEventListener('click', () => {
147 | const MODAL_ID = MODAL_OPENER.getAttribute('data-modal')
148 | const MODAL = document.querySelector(`.modal-${MODAL_ID}`)
149 |
150 | closeAll();
151 |
152 | if(MODAL_ID !== 'lang' && MODAL_ID !== 'theme') MODAL_WINDOW.classList.toggle(`modal-window--active`)
153 | else isOpenPopupHeader = true
154 |
155 | if(MODAL_ID === 'search') document.querySelector('.modal-search__input').focus()
156 | if(MODAL_ID === 'share') {
157 | console.log($('.modal-share__textarea').value)
158 | $$('.modal-share__textarea')[currentShare].focus()
159 | $$('.modal-share__textarea')[currentShare].setSelectionRange(0, $$('.modal-share__textarea')[currentShare].value.length)
160 | }
161 |
162 | MODAL.classList.toggle(`modal-${MODAL_ID}--active`)
163 | })
164 | })
165 | }
166 | if(MODAL_CLOSERS.length > 0) {
167 | MODAL_CLOSERS.forEach(MODAL_CLOSER => {
168 | MODAL_CLOSER.addEventListener('click', () => {
169 | const MODAL_ID = MODAL_CLOSER.getAttribute('data-modal')
170 | const MODAL = document.querySelector(`.modal-${MODAL_ID}`)
171 |
172 | closeAll();
173 |
174 | if(MODAL_ID !== 'lang' && MODAL_ID !== 'theme') MODAL_WINDOW.classList.toggle(`modal-window--active`)
175 | else isOpenPopupHeader = true
176 |
177 | MODAL.classList.remove(`modal-${MODAL_ID}--active`)
178 | })
179 | })
180 | }
181 |
182 | // THEME
183 | const light = document.querySelectorAll('.light-theme');
184 | const dark = document.querySelectorAll('.dark-theme');
185 | const system = document.querySelectorAll('.system-theme');
186 |
187 | light.forEach((i) =>
188 | i.addEventListener('click', () => {
189 | document.documentElement.classList = '';
190 | localStorage.setItem('theme', 'light');
191 | setActiveThemeButton('light')
192 | if(switchTheme !== null) {
193 | if(typeof switchTheme === 'object') {
194 | switchTheme.forEach(element => element('light'))
195 | } else {
196 | switchTheme('light')
197 | }
198 | }
199 | }),
200 | );
201 | dark.forEach((i) =>
202 | i.addEventListener('click', () => {
203 | document.documentElement.classList = 'dark';
204 | localStorage.setItem('theme', 'dark');
205 | setActiveThemeButton('dark')
206 | if(switchTheme !== null) {
207 | if(typeof switchTheme === 'object') {
208 | switchTheme.forEach(element => element('dark'))
209 | } else {
210 | switchTheme('dark')
211 | }
212 | }
213 | }),
214 | );
215 | system.forEach((i) =>
216 | i.addEventListener('click', () => {
217 | document.documentElement.classList = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : '';
218 | localStorage.setItem('theme', 'system');
219 | setActiveThemeButton('system')
220 | if(switchTheme !== null) {
221 | if(typeof switchTheme === 'object') {
222 | switchTheme.forEach(element => element(window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'))
223 | } else {
224 | switchTheme(window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')
225 | }
226 | }
227 | }),
228 | );
229 |
230 | // SEARCH
231 | const MODAL_SEARCH = document.querySelector('.modal-search__input')
232 | const MODAL_SEARCH_LIST = document.querySelector('.modal-search__list')
233 | const MODAL_SEARCH_LIST_CONTENT = document.querySelector('.modal-search__list-content')
234 |
235 | if(MODAL_SEARCH) MODAL_SEARCH.addEventListener('input', (e) => {
236 | focusedElement = 0
237 | if(e.target.value.length > 0) {
238 | const FILTERED_JSON = JSON_CALCULATORS.filter(CALCULATOR => {
239 | return (CALCULATOR.description.toLowerCase().match(e.target.value.toLowerCase()) !== null) ||
240 | CALCULATOR.title.toLowerCase().match(e.target.value.toLowerCase()) !== null;
241 | })
242 | if(FILTERED_JSON.length > 0) {
243 | MODAL_SEARCH_LIST.classList.remove('modal-search__list--error')
244 | MODAL_SEARCH_LIST.classList.add('modal-search__list--active')
245 | MODAL_SEARCH_LIST_CONTENT.innerHTML = ''
246 | FILTERED_JSON.forEach(CALCULATOR => {
247 | let calculatorWrapper = document.createElement('a')
248 | calculatorWrapper.classList.add('modal-search-item')
249 | calculatorWrapper.href = CALCULATOR.uri
250 |
251 | let calculatorImg = document.createElement('img')
252 | calculatorImg.classList.add('modal-search-item__img')
253 | calculatorImg.src = CALCULATOR.image
254 |
255 | let calculatorTitle = document.createElement('span')
256 | calculatorTitle.classList.add('modal-search-item__text')
257 | calculatorTitle.innerText = CALCULATOR.title
258 |
259 | calculatorWrapper.append(calculatorImg, calculatorTitle)
260 | MODAL_SEARCH_LIST_CONTENT.append(calculatorWrapper)
261 | })
262 | } else {
263 | MODAL_SEARCH_LIST_CONTENT.innerHTML = ''
264 | MODAL_SEARCH_LIST.classList.remove('modal-search__list--active')
265 | MODAL_SEARCH_LIST.classList.add('modal-search__list--error')
266 | }
267 | } else {
268 | MODAL_SEARCH_LIST_CONTENT.innerHTML = ''
269 | MODAL_SEARCH_LIST.classList.remove('modal-search__list--active')
270 | MODAL_SEARCH_LIST.classList.remove('modal-search__list--error')
271 | }
272 | })
273 |
274 | // LANG
275 | const LANG_SELECTS = document.querySelectorAll('.header-lang__select')
276 |
277 | if (LANG_SELECTS){
278 | let langIsEng = true
279 |
280 | for (const LANG_SELECT of LANG_SELECTS) {
281 | if(LANG_SELECT.innerText !== 'ENG' && window.location.href.match(LANG_SELECT.href) !== null) {
282 | LANG_SELECT.classList.add('header-lang__select--active')
283 | langIsEng = false
284 | }
285 | }
286 |
287 | if(langIsEng) LANG_SELECTS[0]?.classList?.add('header-lang__select--active')
288 | }
289 |
290 | // SHARE
291 | $$('.modal-share__button').forEach((button,index) => {
292 | button.addEventListener('click', () => {
293 | $$('.modal-share__button').forEach(i => i.classList.remove('modal-share__button--active'))
294 | $$('.modal-share__content').forEach(i => i.classList.remove('modal-share__content--active'))
295 | button.classList.add('modal-share__button--active')
296 | $$('.modal-share__content')[index].classList.add('modal-share__content--active')
297 | $$('.modal-share__textarea')[index].setSelectionRange(0, $$('.modal-share__textarea')[index].value.length)
298 | currentShare = index
299 | })
300 | })
301 |
302 | window.copyWidget = function (button) {
303 | button.classList.add('button--copy-active')
304 | navigator.clipboard.writeText($$('.modal-share__textarea')[currentShare].value)
305 | setTimeout(() => {
306 | button.classList.remove('button--copy-active')
307 | }, 1000)
308 | }
309 |
310 | window.now = function (suffix = 0){
311 | let date = new Date();
312 | date.setDate(date.getDate() + suffix);
313 | return ("0" + date.getHours()).slice(-2) + ':' + ("0" + date.getMinutes()).slice(-2) + ':' + ("0" + date.getSeconds()).slice(-2)
314 | }
315 |
316 | if(window.innerWidth < 1024){
317 | $$('.calculator-content .button--primary').forEach((button) => {
318 | button.addEventListener('click', () => {
319 | let scrollValue = _('result-container').offsetTop;
320 | window.scrollTo({ top: scrollValue, behavior: 'smooth'});
321 | })
322 | });
323 | }
324 |
--------------------------------------------------------------------------------
/assets/js/calculator.js:
--------------------------------------------------------------------------------
1 | function calculate(){
2 | // 1. init & validate
3 | const getSide = id => input.get(id).optional().positive().val();
4 | const getAngle = id => input.get(id).optional().positive().lt(180).val();
5 | let a = getSide('side_a');
6 | let b = getSide('side_b');
7 | let c = getSide('side_c');
8 | let A = getAngle('angle_a');
9 | let B = getAngle('angle_b');
10 | let h = getSide('height');
11 | let S = getSide('area');
12 | let p = getSide('perimeter');
13 | input.silent = false;
14 | if([a,b,c,A,B,h,S,p].reduce((count,item)=>item?count+1:count,0) != 2){
15 | input.error([],"Provide only 2 values to calculate");
16 | }
17 | if(A&&A>=90 || B&&B>=90){
18 | input.error([],"Angles must be less than 90° or π/2 radians");
19 | }
20 | if(!input.valid()) return;
21 |
22 | // 2. calculate
23 | const calcP = (expression, scope) => calc(expression, scope, 'positive');
24 | const toDeg = angle => calcP('angle*180/pi',{angle});
25 | const toRad = angle => calcP('angle*pi/180',{angle});
26 | if(A) A = toRad(A);
27 | if(B) B = toRad(B);
28 |
29 | try{
30 | // Case 1. AB
31 | if(A&&B){
32 | input.error(['angle_a','angle_b'],"Can not calculate based on 2 angles only",true);
33 | return;
34 | }
35 |
36 | // Case 2. ab,ac,bc - 2 sides
37 | else if(a&&b || a&&c || b&&c){
38 | if(a && b){
39 | c = calcP(`sqrt(a^2+b^2)`,{a,b});
40 | }
41 | else if(a && c){
42 | b = calcP(`sqrt(c^2-a^2)`,{a,c});
43 | }
44 | else if(b && c){
45 | a = calcP(`sqrt(c^2-b^2)`,{b,c});
46 | }
47 | A = calcP(`asin(a/c)`,{a,c});
48 | B = calcP(`asin(b/c)`,{b,c});
49 | h = calcP(`a*b/c`,{a,b,c});
50 | S = calcP(`a*b/2`,{a,b});
51 | p = calcP(`a+b+c`,{a,b,c});
52 | }
53 |
54 | // Case 3. Aa,Ab,Ac,Ba,Bb,Bc - angle + side
55 | else if(A&&a||A&&b||A&&c||B&&a||B&&b||B&&c){
56 | if(A){
57 | B = calcP(`pi/2-${A}`);
58 | }
59 | else if(B){
60 | A = calcP(`pi/2-${B}`);
61 | }
62 | if(a){
63 | c = calcP(`${a}/sin(${A})`);
64 | b = calcP(`sqrt(${c}^2-${a}^2)`);
65 | }
66 | else if(b){
67 | c = calcP(`${b}/cos(${A})`);
68 | a = calcP(`sqrt(${c}^2-${b}^2)`);
69 | }
70 | else if(c){
71 | a = calcP(`${c}*sin(${A})`);
72 | b = calcP(`sqrt(${c}^2-${a}^2)`);
73 | }
74 | h = calcP(`a*b/c`,{a,b,c});
75 | S = calcP(`a*b/2`,{a,b});
76 | p = calcP(`a+b+c`,{a,b,c});
77 | }
78 |
79 | // Case 4. ah,bh,ch - height + side
80 | else if(a&&h||b&&h||c&&h){
81 | if(a && h){
82 | // if(this.checkError(h >= a, ['a','h'], '', false)) setError();
83 | c = calcP(`${a}^2/sqrt(${a}^2-${h}^2)`);
84 | b = calcP(`sqrt(${c}^2-${a}^2)`);
85 | }
86 | else if(b && h){
87 | // if(this.checkError(h >= b, ['b','h'], '', false)) setError();
88 | c = calcP(`${b}^2/sqrt(${b}^2-${h}^2)`);
89 | a = calcP(`sqrt(${c}^2-${b}^2)`);
90 | }
91 | else if(c && h){
92 | // if(this.checkError(h > c/2, ['c','h'], '', false)) setError();
93 | a = calcP(`sqrt((${c}^2+sqrt(${c}^4-4*${c}^2*${h}^2))/2)`);
94 | b = calcP(`sqrt((${c}^2-sqrt(${c}^4-4*${c}^2*${h}^2))/2)`);
95 | }
96 |
97 | A = calcP(`asin(${a}/${c})`);
98 | B = calcP(`asin(${b}/${c})`);
99 | S = calcP(`${a}*${b}/2`);
100 | p = calcP(`${a}+${b}+${c}`);
101 | }
102 |
103 | // Case 5. Ah,Bh - height + angle
104 | else if(A&&h||B&&h){
105 | if(A){
106 | B = calcP(`pi/2-${A}`);
107 | }
108 | else if(B){
109 | A = calcP(`pi/2-${B}`);
110 | }
111 |
112 | a = calcP(`${h}/cos(${A})`);
113 | b = calcP(`${h}/sin(${A})`);
114 | c = calcP(`sqrt(${a}^2+${b}^2)`);
115 | S = calcP(`${a}*${b}/2`);
116 | p = calcP(`${a}+${b}+${c}`);
117 | }
118 |
119 | // 6. hS,hp - height + S/p
120 | else if(h&&S||h&&p){
121 | if(h&&p){
122 | input.error(['height','perimeter'],"Unable to calculate based on height and perimeter", true);
123 | return;
124 | }
125 | else if(h && S){
126 | a = calcP(`sqrt(2*${S}^2-2*${S}*(sqrt(${S}^2-${h}^4)))/${h}`);
127 | b = calcP(`sqrt(2*${S}^2+2*${S}*(sqrt(${S}^2-${h}^4)))/${h}`);
128 | c = calcP(`sqrt(${a}^2+${b}^2)`);
129 | p = calcP(`${a}+${b}+${c}`);
130 | A = calcP(`asin(${a}/${c})`);
131 | B = calcP(`asin(${b}/${c})`);
132 | }
133 | }
134 |
135 | // 7. aS,bS,cS - side + S
136 | else if(a&&S||b&&S||c&&S){
137 | if(a && S){
138 | b = calcP(`2*${S}/${a}`);
139 | c = calcP(`sqrt(${a}^2+${b}^2)`);
140 | }
141 | else if(b && S){
142 | b = calcP(`2*${S}/${b}`);
143 | c = calcP(`sqrt(${a}^2+${b}^2)`);
144 | }
145 | else if(c && S){
146 | a = calcP(`sqrt((${c}^2+sqrt(${c}^4-16*${S}^2))/2)`);
147 | b = calcP(`sqrt((${c}^2-sqrt(${c}^4-16*${S}^2))/2)`);
148 | }
149 |
150 | A = calcP(`asin(${a}/${c})`);
151 | B = calcP(`asin(${b}/${c})`);
152 | h = calcP(`${a}*${b}/${c}`);
153 | p = calcP(`${a}+${b}+${c}`);
154 | }
155 |
156 | // 8. AS,BS - angle + S
157 | else if(A&&S||B&&S){
158 | if(A){
159 | B = calcP(`pi/2-${A}`);
160 | }
161 | else if(B){
162 | A = calcP(`pi/2-${B}`);
163 | }
164 |
165 | a = calcP(`sqrt(2*${S}*tan(${A}))`);
166 | b = calcP(`sqrt(2*${S}/tan(${A}))`);
167 | c = calcP(`sqrt(${a}^2+${b}^2)`);
168 | h = calcP(`${a}*${b}/${c}`);
169 | p = calcP(`${a}+${b}+${c}`);
170 | }
171 |
172 | // 9. ap,bp,cp - side + p
173 | else if(a&&p||b&&p||c&&p){
174 | if(a && p){
175 | b = calcP(`(${p}^2-2*${a}*${p})/(2*${p}-2*${a})`);
176 | c = calcP(`${p}-${a}-${b}`);
177 | }
178 | else if(b && p){
179 | a = calcP(`(${p}^2-2*${b}*${p})/(2*${p}-2*${b})`);
180 | c = calcP(`${p}-${a}-${b}`);
181 | }
182 | else if(c && p){
183 | a = calcP(`(${p}-${c}+sqrt(${c}^2+2*${p}*${c}-${p}^2))/2`);
184 | b = calcP(`(${p}-${c}-sqrt(${c}^2+2*${p}*${c}-${p}^2))/2`);
185 | }
186 |
187 | A = calcP(`asin(${a}/${c})`);
188 | B = calcP(`asin(${b}/${c})`);
189 | h = calcP(`${a}*${b}/${c}`);
190 | S = calcP(`${a}*${b}/2`);
191 | }
192 |
193 | // 10. Ap,Bp - angle + p
194 | else if(A&&p||B&&p){
195 | if(A){
196 | B = calcP(`pi/2-${A}`);
197 | }
198 | else if(B){
199 | A = calcP(`pi/2-${B}`);
200 | }
201 |
202 | c = calcP(`${p}/(1+sin(${A})+cos(${A}))`);
203 | a = calcP(`${c}*sin(${A})`);
204 | b = calcP(`${c}*cos(${A})`);
205 | h = calcP(`${a}*${b}/${c}`);
206 | S = calcP(`${a}*${b}/2`);
207 | }
208 |
209 | // 11. Sp
210 | else if(S&&p){
211 | a = calcP(`(p^2+4*S+sqrt((p^2+4*S)^2-32*S*p^2))/(4*p)`,{S,p});
212 | b = calcP(`(p^2+4*S-sqrt((p^2+4*S)^2-32*S*p^2))/(4*p)`,{S,p});
213 | c = calcP(`sqrt(${a}^2+${b}^2)`);
214 | A = calcP(`asin(${a}/${c})`);
215 | B = calcP(`asin(${b}/${c})`);
216 | h = calcP(`${a}*${b}/${c}`);
217 | }
218 | }
219 | catch(e){
220 | // to catch uncheckable values combinations
221 | input.exception([], e);
222 | return;
223 | }
224 |
225 | const r = calcP('S/(p/2)',{S,p});
226 | const R = calcP('a/(2*sin(A))',{A,a});
227 |
228 | // 3. output
229 | _('result_a').innerHTML = format(a);
230 | _('result_b').innerHTML = format(b);
231 | _('result_c').innerHTML = format(c);
232 | _('result_A').innerHTML = `${format(toDeg(A))}° = ${format(A)} rad`;
233 | _('result_B').innerHTML = `${format(toDeg(B))}° = ${format(B)} rad`;
234 | _('result_h').innerHTML = format(h);
235 | _('result_S').innerHTML = format(S);
236 | _('result_p').innerHTML = format(p);
237 | _('result_r').innerHTML = format(r);
238 | _('result_R').innerHTML = format(R);
239 | }
--------------------------------------------------------------------------------
/assets/js/chart.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | let theme = 'light';
4 | if (localStorage.getItem('theme') === 'dark' || (localStorage.getItem('theme') === 'system' && window.matchMedia('(prefers-color-scheme: dark)').matches)) theme = 'dark';
5 |
6 | Chart.defaults.borderColor = '#000';
7 |
8 | const colors = {
9 | light: {
10 | purple: '#A78BFA',
11 | yellow: '#FBBF24',
12 | sky: '#7DD3FC',
13 | blue: '#1D4ED8',
14 | textColor: '#6B7280',
15 | yellowGradientStart: 'rgba(250, 219, 139, 0.33)',
16 | purpleGradientStart: 'rgba(104, 56, 248, 0.16)',
17 | skyGradientStart: 'rgba(56, 187, 248, 0.16)',
18 | tealGradientStart: 'rgba(56, 248, 222, 0.16)',
19 | yellowGradientStop: 'rgba(250, 219, 139, 0)',
20 | purpleGradientStop: 'rgba(104, 56, 248, 0)',
21 | gridColor: '#DBEAFE',
22 | tooltipBackground: '#fff',
23 | fractionColor: '#EDE9FE',
24 | },
25 | dark: {
26 | purple: '#7C3AED',
27 | yellow: '#D97706',
28 | sky: '#0284C7',
29 | blue: '#101E47',
30 | textColor: '#fff',
31 | yellowGradientStart: 'rgba(146, 123, 67, 0.23)',
32 | purpleGradientStart: 'rgba(78, 55, 144, 0.11)',
33 | skyGradientStart: 'rgba(56, 187, 248, 0.16)',
34 | tealGradientStart: 'rgba(56, 248, 222, 0.16)',
35 | yellowGradientStop: 'rgba(250, 219, 139, 0)',
36 | purpleGradientStop: 'rgba(104, 56, 248, 0)',
37 | gridColor: '#162B64',
38 | tooltipBackground: '#1C3782',
39 | fractionColor: '#41467D',
40 | },
41 | };
42 |
43 | class Custom extends LineController {
44 | draw() {
45 | super.draw(arguments);
46 |
47 | const ctx = this.chart.ctx;
48 | let _stroke = ctx.stroke;
49 |
50 | ctx.stroke = function () {
51 | ctx.save();
52 | ctx.shadowColor = 'black';
53 | ctx.shadowBlur = 20;
54 | ctx.shadowOffsetX = 0;
55 | ctx.shadowOffsetY = 20;
56 | _stroke.apply(this, arguments);
57 | ctx.restore();
58 | };
59 | }
60 | }
61 |
62 | Custom.id = 'shadowLine';
63 | Custom.defaults = LineController.defaults;
64 |
65 | Chart.register(Custom);
66 |
67 | let switchTheme = []
68 |
69 | if (document.getElementById('chartC150')) {
70 | let ctx = document.getElementById('chartC150').getContext('2d');
71 |
72 | let purpleGradient = ctx.createLinearGradient(0, 0, 2048, 0);
73 | purpleGradient.addColorStop(0, 'rgba(152, 96, 250, 0)');
74 | purpleGradient.addColorStop(1, 'rgba(152, 96, 250, .8)');
75 |
76 | const dataCharts = {
77 | labels: [0, 1, 2, 3, 4, 5, 6],
78 | datasets: [
79 | {
80 | label: 'D1',
81 | data: [{ x: 4, y: 40 }],
82 | backgroundColor: '#7C3AED',
83 | borderWidth: 0,
84 | radius: 6,
85 | hoverRadius: 6,
86 | type: 'scatter',
87 | stacked: true,
88 | order: 0,
89 | },
90 | {
91 | label: 'D2',
92 | data: [0, 10, 20, 40, 60, 80, 100],
93 | borderColor: colors[theme].purple,
94 | type: 'line',
95 | fill: '-1',
96 | order: 1,
97 | pointHoverRadius: 0,
98 | },
99 | {
100 | label: 'D3',
101 | data: [0, 5, 5, 15, 25, 35, 45],
102 | borderColor: colors[theme].purple,
103 | backgroundColor: purpleGradient,
104 | type: 'line',
105 | fill: '-1',
106 | order: 1,
107 | pointHoverRadius: 0,
108 | },
109 | ],
110 | };
111 |
112 | let chart = new Chart(document.getElementById('chartC150'), {
113 | data: dataCharts,
114 | options: {
115 | stepSize: 1,
116 | response: true,
117 | elements: {
118 | point: {
119 | radius: 0,
120 | },
121 | },
122 | plugins: {
123 | legend: {
124 | display: false,
125 | },
126 | tooltip: false,
127 | },
128 | interaction: {
129 | mode: 'index',
130 | intersect: false,
131 | },
132 | scales: {
133 | y: {
134 | max: 100,
135 | grid: {
136 | tickLength: 0,
137 | color: colors[theme].gridColor,
138 | },
139 | ticks: {
140 | display: false,
141 | stepSize: 25,
142 | },
143 | border: {
144 | color: colors[theme].gridColor,
145 | },
146 | },
147 | x: {
148 | stacked: false,
149 | border: {
150 | color: colors[theme].gridColor,
151 | },
152 | ticks: {
153 | display: false,
154 | color: colors[theme].gridColor,
155 | stepSize: 1,
156 | },
157 | grid: {
158 | tickLength: 0,
159 | color: colors[theme].gridColor,
160 | },
161 | },
162 | },
163 | },
164 | });
165 |
166 | let switchThemeChartC150 = function(theme) {
167 | let y = chart.config.options.scales.y
168 | let x = chart.config.options.scales.x
169 | let data = chart.config.data
170 | y.grid.color = colors[theme].gridColor;
171 | y.border.color = colors[theme].gridColor;
172 | x.border.color = colors[theme].gridColor;
173 | x.grid.color = colors[theme].gridColor;
174 | x.ticks.color = colors[theme].gridColor;
175 | data.datasets[1].borderColor = colors[theme].purple;
176 | data.datasets[2].borderColor = colors[theme].purple;
177 | chart.update()
178 | }
179 |
180 | switchTheme.push(switchThemeChartC150)
181 |
182 | }
--------------------------------------------------------------------------------
/assets/js/datepicker.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll('.datepicker_us').forEach((datepicker) => {
2 | new AirDatepicker(datepicker, {
3 | dateFormat: 'MM/dd/yyyy',
4 | autoClose: true,
5 | onSelect: function(event){
6 | return updateDate(event.datepicker.$el);
7 | },
8 | // visible: true,
9 | prevHtml:
10 | '',
11 | nextHtml:
12 | '',
13 | locale: {
14 | months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
15 | monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
16 | days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
17 | daysShort: ['S', 'M', 'T', 'W', 'T', 'F', 'S'],
18 | daysMin: ['S', 'M', 'T', 'W', 'T', 'F', 'S'],
19 | },
20 | });
21 | });
22 |
23 | document.querySelectorAll('.datepicker').forEach((datepicker) => {
24 | new AirDatepicker(datepicker, {
25 | dateFormat: 'yyyy-MM-dd',
26 | autoClose: true,
27 | onSelect: function(event){
28 | return updateDate(event.datepicker.$el);
29 | },
30 | // visible: true,
31 | prevHtml:
32 | '',
33 | nextHtml:
34 | '',
35 | locale: {
36 | months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
37 | monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
38 | days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
39 | daysShort: ['S', 'M', 'T', 'W', 'T', 'F', 'S'],
40 | daysMin: ['S', 'M', 'T', 'W', 'T', 'F', 'S'],
41 | },
42 | });
43 | });
--------------------------------------------------------------------------------
/assets/js/dialog-table.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | $$('.result-table__dialog').forEach(element => {
4 | const ELEMENT_OPEN = element.querySelector('.result-table__open');
5 | ELEMENT_OPEN.addEventListener('click', () => {
6 | element.classList.toggle('result-table__dialog--active');
7 | })
8 | })
--------------------------------------------------------------------------------
/assets/js/dropdown-icon.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const setSelect = (list, index) => {
4 | list.forEach(item => {
5 | item.classList.remove('dropdown-select--selected')
6 | })
7 | list[index].classList.add('dropdown-select--selected')
8 | }
9 |
10 | const setValue = (input, value, index) => {
11 | if(index !== undefined) {
12 | setTab(index)
13 | }
14 | input.innerHTML = value
15 | }
16 |
17 | const setTab = (index) => {
18 | document.querySelectorAll(`[data-tab]`)?.forEach(element => {
19 | if(element.getAttribute('data-tab') == index) {
20 | element.classList.add('tab--active');
21 | } else {
22 | element.classList.remove('tab--active');
23 | element.classList.remove('tab--active')
24 | }
25 | })
26 | }
27 |
28 | const DROPDOWN_WRAPPER = document.querySelectorAll('.dropdown-wrapper')
29 |
30 |
31 | DROPDOWN_WRAPPER.forEach(wrapper => {
32 | // CLOSE DROPDOWN WHEN CLICK OUTSIDE
33 | window.addEventListener('click', (e) => {
34 | if(!(e.composedPath().includes(wrapper))) {
35 | wrapper.classList.remove('dropdown-wrapper--active')
36 | }
37 | })
38 |
39 | const DROPDOWN_FIELD = wrapper.querySelector('.input-field')
40 | const DROPDOWN_VALUE = wrapper.querySelector('.input-field__text')
41 | const DROPDOWN_SELECTS = wrapper.querySelectorAll('.dropdown-select')
42 | // DEFAULT TAB
43 | setTab(0)
44 |
45 | // OPEN DROPDOWN WHEN CLICK ON INPUT
46 | DROPDOWN_FIELD.addEventListener('click', () => {
47 | // CLOSE OTHERS DROPDOWN
48 | if(!wrapper.classList.contains('dropdown-wrapper--active')) {
49 | DROPDOWN_WRAPPER.forEach(wrapper => {wrapper.classList.remove('dropdown-wrapper--active')})
50 | }
51 | // OPEN THIS DROPDOWN
52 | wrapper.classList.toggle('dropdown-wrapper--active')
53 | })
54 |
55 | // SET EVENT LISTENERS FOR SELECT
56 | DROPDOWN_SELECTS.forEach((select, index) => {
57 | const SELECT_VALUE = select.innerHTML
58 | select.addEventListener('click', () => {
59 | wrapper.classList.remove('dropdown-wrapper--active')
60 |
61 | // SET SELECT FOR DROPDOWN
62 | setSelect(DROPDOWN_SELECTS, index)
63 |
64 | // SET VALUE FOR DROPDOWN
65 | if(select.classList.contains('dropdown-select--tab')) {
66 | // IF DROPDOWN IS DROPDOWN TAB : example due-date-calculator dropdown "Calculate based on"
67 | setValue(DROPDOWN_VALUE,SELECT_VALUE, index)
68 | } else {
69 | setValue(DROPDOWN_VALUE,SELECT_VALUE)
70 | }
71 | })
72 | })
73 | })
--------------------------------------------------------------------------------
/assets/js/fractions.js:
--------------------------------------------------------------------------------
1 | const Fractions = {
2 | // helpers
3 | isCorrectMixed(whole, num, denom){
4 | return !(!whole && !num && !denom || !num && denom || num && !denom);
5 | },
6 | buildFrac(whole, num, denom){
7 | whole = Number(whole);
8 | num = Number(num);
9 | denom = Number(denom);
10 | return num && denom ?
11 | math.fraction(
12 | (math.sign(whole) || 1) * (math.sign(num) || 1) * (math.sign(denom) || 1) *
13 | (math.abs(whole) * math.abs(denom) + math.abs(num)), math.abs(denom)
14 | ) :
15 | math.fraction(whole, 1)
16 | ;
17 | },
18 | getFracPart(frac){
19 | return frac.d != 1 ? {
20 | num: frac.n % frac.d, denom: frac.d,
21 | } : '';
22 | },
23 | getWholePart(frac){
24 | const sign = frac.s == -1 ? '-' : '';
25 | const wholePart = (frac.n - frac.n % frac.d) / frac.d;
26 | if(wholePart == 0 && this.getFracPart(frac)) return sign;
27 | return sign + wholePart;
28 | },
29 | getChartData(frac){
30 | const fracPart = this.getFracPart(frac);
31 | const wholePart = this.getWholePart(frac);
32 | return fracPart ? [fracPart.num, fracPart.denom-fracPart.num] : (wholePart == 0 ? [0,1]:[1,0]);
33 | },
34 | outputFrac(frac, prefix){
35 | const isWhole = frac.d == 1;
36 | const sign = frac.s == -1 ? '-' : '';
37 | _(prefix+'Whole').classList[!isWhole && !sign ? 'add':'remove']('hidden');
38 | _(prefix+'Whole').innerText = sign + (isWhole ? frac.n : '');
39 | _(prefix+'Frac').classList[isWhole?'add':'remove']('hidden');
40 | _(prefix+'Num').innerText = frac.n;
41 | _(prefix+'Denom').innerText = frac.d;
42 | },
43 | outputMixed(frac, prefix){
44 | const fracPart = this.getFracPart(frac);
45 | const wholePart = this.getWholePart(frac);
46 | _(prefix+'Whole').classList[!wholePart?'add':'remove']('hidden');
47 | _(prefix+'Whole').innerText = wholePart;
48 | _(prefix+'Frac').classList[!fracPart?'add':'remove']('hidden');
49 | _(prefix+'Num').innerText = fracPart.num;
50 | _(prefix+'Denom').innerText = fracPart.denom;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/assets/js/functions.js:
--------------------------------------------------------------------------------
1 | window.log = console.log;
2 |
3 | window.setValue = function (inputId, value, index){
4 | _(inputId).value = value;
5 | _(inputId).index = index;
6 | }
7 |
8 | window.switcher = function(button, id, action) {
9 | $('#' + id).value = button.value;
10 | $('#' + id).onchange && $('#' + id).onchange(button.value);
11 | $('#' + id + '-a')?.classList.remove("button-switcher--active");
12 | $('#' + id + '-b')?.classList.remove("button-switcher--active");
13 | $('#' + id + '-c')?.classList.remove("button-switcher--active");
14 | $('#' + id + '-d')?.classList.remove("button-switcher--active");
15 | $('#' + id + '-e')?.classList.remove("button-switcher--active");
16 | button.classList.add("button-switcher--active");
17 | toggleRelatedInputs(button, id, action);
18 | }
19 |
20 | window.toggleRelatedInputs = function(element, id, action){
21 | element = element instanceof Event ? element.target : element
22 | id = id ?? element.id;
23 | let value = element.value;
24 | if(element.type == 'select-one') value = element.selectedIndex;
25 | $$('.' + id).forEach(element => {
26 | if(action === "disabled") {
27 | element.classList.remove("disabled");
28 | } else if (action === "finding") {
29 | element.classList.remove("disabled");
30 | if(element.querySelector('.input-field__input').value === "???") {
31 | element.querySelector('.input-field__input').value = ""
32 | }
33 | } else {
34 | element.classList.add("related-item-hidden");
35 | }
36 | });
37 | $$('.related-to-' + id + '-' + value)?.forEach(element => {
38 | if(action === "disabled") {
39 | element.classList.add("disabled");
40 | } else if (action === "finding") {
41 | element.querySelector('.input-field__input').value = "???"
42 | element.classList.add("disabled");
43 | } else {
44 | element.classList.remove("related-item-hidden");
45 | }
46 | });
47 | }
48 |
49 | window.switch_data_tab = function(owner, index, value){
50 | $$('[data-tab]')?.forEach(element => {
51 | if(element.getAttribute('data-tab') == index) {
52 | element.classList.add('tab--active');
53 | owner.classList.add('tab--active');
54 | } else {
55 | element.classList.remove('tab--active');
56 | }
57 | });
58 | }
59 |
60 | window.isMetricSystem = function() {
61 | return $('.system-switcher').classList.contains('system-switcher--active');
62 | }
63 |
64 | window.setSystem = function(system) {
65 | const add = (system == "metric" ? ".imperial-system-item" : ".metric-system-item");
66 | $$(".system-item-hidden").forEach(element => {
67 | element.classList.remove("system-item-hidden");
68 | });
69 | $$(add).forEach(element => {
70 | element.classList.add("system-item-hidden");
71 | });
72 | localStorage.setItem("system", system);
73 | }
74 |
75 | window.toggleSystem = function(button) {
76 | button.classList.toggle('system-switcher--active');
77 | if(button.classList.contains('system-switcher--active')) {
78 | return setSystem('metric');
79 | }
80 | return setSystem('imperial');
81 | }
82 |
83 | window.isHidden = function(element) {
84 | const styles = window.getComputedStyle(element);
85 | return styles.display === 'none' || styles.visibility === 'hidden';
86 | }
87 |
88 | window.output = {
89 | value: null,
90 | val: function(value){
91 | this.value = value;
92 | return this;
93 | },
94 | replace: function(search, replacement) {
95 | this.value = this.value.replace(search, replacement);
96 | return this;
97 | },
98 | set: function(elementId){
99 | _(elementId).innerHTML = this.value;
100 | return this;
101 | }
102 | };
103 |
104 | // check erroneous result of expression (or if it's not string - check itself)
105 | // usefull in cases when erroneous values of input fields are unknown
106 | window.calc = (expression,scope,resultType) => {
107 | let result = expression;
108 | scope = scope || {};
109 | if(typeof expression == 'string'){
110 | result = math.evaluate(expression,scope); // can throw error as well
111 | }
112 | let valid = true;
113 | switch(resultType){
114 | case 'positive': valid = result > 0;
115 | }
116 | if(isNaN(result)||result.im||!valid) {
117 | const args = Object.keys(scope).map(arg=>arg+'='+scope[arg]);
118 | throw new Error(
119 | `result of expression ${expression} is ${result}.`
120 | + (resultType ? `
Should be ${resultType}.`:'')
121 | + (args.length != 0 ? `
Args: ${args.join(', ')}.`:'')
122 | );
123 | }
124 | return result;
125 | };
126 |
127 | // allows to show accurate results with fixed precision/length (instead of using BigNumber)
128 | window.format = number => math.format(number,{precision:7})
129 |
130 | window.input = {
131 | box: $('#error-box'),
132 | list: $('#error-list'),
133 | value: null,
134 | elementId: null,
135 | shown: false,
136 | processed: false,
137 | silent: false,
138 | reset: function(){
139 | this.shown = false;
140 | this.box.classList.remove('calculator-result--error-active');
141 | $$('.input-field--error')?.forEach(el => el.classList.remove('input-field--error'))
142 | $$('.calculator-result:not(.calculator-result--error)').forEach(el => el.classList.remove('calculator-result--hidden'))
143 | },
144 | error: function (inputId, message = `Incorrect value for "${inputId}"`, last = false) {
145 | if(this.silent) return;
146 | if(this.processed) this.reset();
147 | if(!Array.isArray(inputId)) inputId = [inputId];
148 | for(const inputIdItem of inputId) _(inputIdItem).parentNode.classList.add('input-field--error');
149 | if(!this.shown){
150 | this.processed = false;
151 | this.shown = true;
152 | this.list.innerHTML = '';
153 | this.box.classList.add('calculator-result--error-active');
154 | $$('.calculator-result:not(.calculator-result--error)').forEach(el => el.classList.add('calculator-result--hidden'))
155 | }
156 | const element = document.createElement('p');
157 | element.classList.add('calculator-error__item');
158 | element.innerHTML = message;
159 | this.list.append(element);
160 | if(last) this.processed = true;
161 | },
162 | // sometimes it's complicated to check input values
163 | // so we're checking `calc` result for an erroneous result, show exception and return
164 | // e.g.: try{calc(...);}catch(e){input.exception(field{s},e);return;}
165 | exception(inputId, message){
166 | if(typeof message != 'string'){
167 | let error = '';
168 | if(message instanceof Error){
169 | error = message.toString();
170 | }
171 | // default message
172 | if(Array.isArray(inputId) && inputId.length == 0){
173 | message = `${error}`;
174 | } else {
175 | message = `Value${Array.isArray(inputId)?'s':` "${this.get(inputId).value}"`} of "${inputId}" ${Array.isArray(inputId)?'are':'is'} invalid.
${error}`;
176 | }
177 | }
178 | return this.error(inputId, message, true);
179 | },
180 | valid: function(){
181 | if(!this.shown || this.processed) this.reset();
182 | this.processed = true;
183 | this.silent = false;
184 | return !this.shown;
185 | },
186 | get: function(elementId){
187 | this.elementId = elementId;
188 | let element = _(elementId);
189 | this.silent = false;
190 | if(element == null){
191 | this.value = null;
192 | } else {
193 | this.value = element.value;
194 | for (; element && element !== document; element = element.parentNode ) {
195 | if(element.classList.contains('related-item-hidden')) this.silent = true;
196 | }
197 | }
198 | return this;
199 | },
200 | index: function(){
201 | this.value = _(this.elementId).selectedIndex;
202 | return this;
203 | },
204 | checked: function(elementId){
205 | this.value = _(this.elementId).checked;
206 | return this;
207 | },
208 | split: function(separator){
209 | this.value = this.value.split(separator);
210 | return this;
211 | },
212 | replace: function(pattern, replacement){
213 | this.value = this.value.replace(pattern, replacement);
214 | return this;
215 | },
216 | default: function(value){
217 | if(!this.value) this.value = value;
218 | return this;
219 | },
220 | optional: function(value){
221 | if(!this.value) this.silent = true;
222 | return this;
223 | },
224 | gt: function(compare = 0, errorText = `The ${this.elementId} must be greater than ${compare}.`){
225 | if (this.value instanceof Date) {
226 | compare = compare instanceof Date ? compare : new Date(_(compare).value);
227 | if (this.value.getTime() <= compare.getTime()) this.error(this.elementId, errorText);
228 | } else {
229 | compare = isNaN(compare) ? Number(_(compare).value) : compare;
230 | if(this.value === '' || isNaN(Number(this.value)))
231 | this.error(this.elementId, `The ${this.elementId} must be a number.`);
232 | else
233 | if (Number(this.value) <= compare) this.error(this.elementId, errorText);
234 | }
235 | return this;
236 | },
237 | gte: function(compare = 0, errorText = `The ${this.elementId} must be greater than or equal to ${compare}.`){
238 | if (this.value instanceof Date) {
239 | compare = compare instanceof Date ? compare : new Date(_(compare).value);
240 | if (this.value.getTime() < compare.getTime()) this.error(this.elementId, errorText);
241 | } else {
242 | compare = isNaN(compare) ? Number(_(compare).value) : compare;
243 | if(this.value === '' || isNaN(Number(this.value)))
244 | this.error(this.elementId, `The ${this.elementId} must be a number.`);
245 | else
246 | if (Number(this.value) < compare) this.error(this.elementId, errorText);
247 | }
248 | return this;
249 | },
250 | lt: function(compare = 0, errorText = `The ${this.elementId} must be less than ${compare}.`){
251 | if (this.value instanceof Date) {
252 | compare = compare instanceof Date ? compare : new Date(_(compare).value);
253 | if (this.value.getTime() >= compare.getTime()) this.error(this.elementId, errorText);
254 | } else {
255 | compare = isNaN(compare) ? Number(_(compare).value) : compare;
256 | if(this.value === '' || isNaN(Number(this.value)))
257 | this.error(this.elementId, `The ${this.elementId} must be a number.`);
258 | else
259 | if (Number(this.value) >= compare) this.error(this.elementId, errorText);
260 | }
261 | return this;
262 | },
263 | lte: function(compare = 0, errorText = `The ${this.elementId} must be less than or equal to ${compare}.`){
264 | if (this.value instanceof Date) {
265 | compare = compare instanceof Date ? compare : new Date(_(compare).value);
266 | if (this.value.getTime() > compare.getTime()) this.error(this.elementId, errorText);
267 | } else {
268 | compare = isNaN(compare) ? Number(_(compare).value) : compare;
269 | if(this.value === '' || isNaN(Number(this.value)))
270 | this.error(this.elementId, `The ${this.elementId} must be a number.`);
271 | else
272 | if (Number(this.value) > compare) this.error(this.elementId, errorText);
273 | }
274 | return this;
275 | },
276 | integer: function(errorText = `The ${this.elementId} must be integer number (-3, -2, -1, 0, 1, 2, 3, ...).`){
277 | if (!this.value.match(/^-?(0|[1-9]\d*)$/)) this.error(this.elementId, errorText);
278 | return this;
279 | },
280 | _naturalRegexp: /^([1-9]\d*)$/,
281 | natural: function(errorText = `The ${this.elementId} must be a natural number (1, 2, 3, ...).`){
282 | if (!this.value.match(this._naturalRegexp)) this.error(this.elementId, errorText);
283 | return this;
284 | },
285 | natural_numbers: function(errorText = `The ${this.elementId} must be a set of natural numbers (1, 2, 3, ...).`){
286 | this.split(/[ ,]+/);
287 | if (!this.value.every(value=>value.match(this._naturalRegexp))) this.error(this.elementId, errorText);
288 | return this;
289 | },
290 | _mixedRegexp: /^(0|-?[1-9]\d*|-?[1-9]\d*\/[1-9]\d*|-?[1-9]\d*\s[1-9]\d*\/[1-9]\d*)$/,
291 | mixed: function(errorText = `The ${this.elementId} must be an integer/fraction/mixed number (1, 2/3, 4 5/6, ...).`){
292 | if (!this.value.match(this._mixedRegexp)) this.error(this.elementId, errorText);
293 | return this;
294 | },
295 | mixed_numbers: function(errorText = `The ${this.elementId} must be a set of integer/fraction/mixed numbers (1, 2/3, 4 5/6, ...).`){
296 | this.split(/,\s*/);
297 | if (!this.value.every(value=>value.match(this._mixedRegexp))) this.error(this.elementId, errorText);
298 | return this;
299 | },
300 | number: function(errorText = `The "${this.elementId}" must be a number.`){
301 | if(this.value === '' || isNaN(Number(this.value))) this.error(this.elementId, errorText);
302 | return this;
303 | },
304 | probability: function(errorText = `The "${this.elementId}" must be a number between 0 and 1.`){
305 | if(this.value === '' || isNaN(Number(this.value)) || Number(this.value) < 0 || Number(this.value) > 1)
306 | this.error(this.elementId, errorText);
307 | return this;
308 | },
309 | percentage: function(errorText = `The "${this.elementId}" must be a number between 0 and 100.`){
310 | if(this.value === '' || isNaN(Number(this.value)) || Number(this.value) < 0 || Number(this.value) > 100)
311 | this.error(this.elementId, errorText);
312 | return this;
313 | },
314 | numbers: function(errorText = `The ${this.elementId} must be a set of numbers.`){
315 | if (this.value.filter(value => isNaN(Number(value))).length) this.error(this.elementId, errorText);
316 | return this;
317 | },
318 | whole: function(errorText = `The ${this.elementId} must be a whole number.`){
319 | if (!this.value.match(/^(0|[1-9]\d*)$/)) this.error(this.elementId, errorText);
320 | return this;
321 | },
322 | positive: function(errorText = `The ${this.elementId} must be greater than 0.`){
323 | this.gt(0, errorText);
324 | return this;
325 | },
326 | nonZero: function(errorText = `The ${this.elementId} must be non-zero.`){
327 | if(this.value === '' || isNaN(Number(this.value)))
328 | this.error(this.elementId, `The ${this.elementId} must be a number.`);
329 | else
330 | if(Number(this.value) == 0) this.error(this.elementId, errorText);
331 | return this;
332 | },
333 | nonNegative: function(errorText = `The ${this.elementId} must be greater than or equal to 0.`){
334 | this.gte(0, errorText);
335 | return this;
336 | },
337 | negative: function(errorText = `The ${this.elementId} must be less than 0.`){
338 | this.lt(0, errorText);
339 | return this;
340 | },
341 | scientific: function(errorText = `The ${this.elementId} must be in scientific notation.`){
342 | if (!this.value.match(/^(-|\+)?((0|[1-9]\d*)(\.\d*)?|(\.\d+))((e|\s?(\*|x)\s?10\^)(-|\+)?(0|[1-9]\d*))?$/i)) this.error(this.elementId, errorText);
343 | return this;
344 | },
345 | periodic: function(errorText = `The ${this.elementId} must be regular or periodic number.`){
346 | if (this.value === '' || isNaN(Number(this.value)) && !this.value.match(/\.\d*\(\d+\)$/)) this.error(this.elementId, errorText);
347 | return this;
348 | },
349 | time: function(format = 'hh:mm:ss', errorText = `The ${this.elementId} must be in format ${format}.`){
350 | let regex = new RegExp("^" + format.replace(/[\:\-\/\\]/g, '\\$&').replace(/h|m|s/g, '\\d') + "$");
351 | if (!this.value.match(regex) || isNaN(this.value = new Date(`1900-01-01 ${this.value}`))) this.error(this.elementId, errorText);
352 | return this;
353 | },
354 | date: function(format = 'yyyy-mm-dd', errorText = `The ${this.elementId} is required field.`){
355 | let regex = new RegExp("^" + format.replace(/[\:\-\/\\]/g, '\\$&').replace(/y|m|d|h|s/g, '\\d') + "$");
356 | if (!this.value.match(regex) || isNaN(this.value = new Date(this.value))) this.error(this.elementId, errorText);
357 | this.value = convertTZ(this.value, "UTC");
358 | return this;
359 | },
360 | bool: function(){
361 | return !!this.value;
362 | },
363 | val: function(){
364 | if(this.value === '' || this.value === null) return null;
365 | return Number(this.value);
366 | },
367 | vals: function(){
368 | return this.value.map(value => Number(value));
369 | },
370 | raw: function(){
371 | return this.value;
372 | },
373 | group(name,ids){
374 | const result = ids.split('|')
375 | .reduce((result,ids)=>{
376 | const obj = ids.split('.').every(id=>_(name+id.match(/^[_a-zA-Z]+/)[0]).value) ?
377 | ids.split('.').reduce((obj,id)=>{
378 | let type = 'number';
379 | let getter = 'val';
380 | switch((id.match(/[^_a-zA-Z]+$/)||[])[0]){
381 | case '+': type = 'positive'; break;
382 | case '!0': type = 'nonZero'; break;
383 | case '#': getter = 'raw'; break;
384 | default: /* custom modificator */; break;
385 | }
386 | id = id.match(/^[_a-zA-Z]+/)[0];
387 | return {...obj, ...{
388 | [id]: input.get(name+id)[type]()[getter]()
389 | }};
390 | }, {}) : null;
391 | if(!result && !obj) return null;
392 | return {...result,...obj};
393 | }, null);
394 | return result;
395 | },
396 | }
397 |
398 | window.sysnumconv = function(element){
399 | const id = element.dataset.target;
400 | const metric = _(id);
401 | const imperial = _(id + "_imperial");
402 | if(window.isMetricSystem()){
403 | let value = metric.value;
404 | imperial.value = eval(imperial.dataset.formula).toFixed(2);
405 | } else {
406 | let value = imperial.value;
407 | metric.value = eval(metric.dataset.formula).toFixed(2);
408 | }
409 | };
410 |
411 | window.updateHeight = function(element){
412 | var id = element.dataset.target;
413 | var cm = _(id);
414 | var feet = _(id + "_ft");
415 | var inches = _(id + "_in");
416 | if(window.isMetricSystem()){
417 | feet.value = Math.floor(cm.value * 0.393701 / 12);
418 | inches.value = (cm.value * 0.393701 % 12).toFixed(2);
419 | } else {
420 | cm.value = ((feet.value * 30.48) + (inches.value * 2.54)).toFixed(2);
421 | }
422 | };
423 |
424 | window.setDate = function (id, suffix) {
425 | var date = new Date();
426 | var date_m = _(id);
427 | var date_us = _(id + "_us");
428 | date.setDate(date.getDate() + suffix);
429 | date_us.value = ("0" + (date.getMonth() + 1)).slice(-2) + '/' + ("0" + date.getDate()).slice(-2) + '/' + date.getFullYear();
430 | date_m.value = date.getFullYear() + '-' + ("0" + (date.getMonth() + 1)).slice(-2) + '-' + ("0" + date.getDate()).slice(-2);
431 | }
432 |
433 | window.updateDate = function(element){
434 | var id = element.dataset.target;
435 | var date_m = _(id);
436 | var date_us = _(id + "_us");
437 | if(window.isMetricSystem()){
438 | let date = new Date(Date.parse(date_m.value));
439 | date_us.value = ("0" + (date.getMonth() + 1)).slice(-2) + '/' + ("0" + date.getDate()).slice(-2) + '/' + date.getFullYear();
440 | } else {
441 | let date = new Date(Date.parse(date_us.value));
442 | date_m.value = date.getFullYear() + '-' + ("0" + (date.getMonth() + 1)).slice(-2) + '-' + ("0" + date.getDate()).slice(-2);
443 | }
444 | };
445 |
446 | window.switchTab = function (event, index) {
447 | if(index !== undefined && index !== null) {
448 | if(event.target.classList.contains('tab-item')) {
449 | $$(`.${event.target.classList[0]}`).forEach((tab, i) => {
450 | if(index === i) {
451 | tab.classList.add('tab-item--active')
452 | } else {
453 | tab.classList.remove('tab-item--active')
454 | }
455 | })
456 | }
457 | }
458 | $$(`[data-tab]`).forEach(element => {
459 | if(element.dataset.tab == event.selectedIndex || element.dataset.tab == index) {
460 | element.classList.add('tab--active')
461 | } else {
462 | element.classList.remove('tab--active')
463 | }
464 | })
465 | }
466 |
467 | window.setMaxLength = function(element, maxLength) {
468 | if(getComputedStyle(element).getPropertyValue('--fontStep') !== '') {
469 | element.style = `--maxWidth: ${Number(getComputedStyle(element).getPropertyValue('--fontStep').replace(/px/gi, '')) * (element.value.length === 0 ? 1 : element.value.length > maxLength ? maxLength : element.value.length) }px`
470 | }
471 | if(element.value.length > maxLength) {
472 | element.value = element.value.substring(0, maxLength);
473 | }
474 | }
475 |
476 | window.relatedToggle = function(element, related, action) {
477 | if(action === "disabled") {
478 | if(element.target.checked) {
479 | $$(`.related-to-${related}`)?.forEach(el => el.classList.remove('disabled'))
480 | } else {
481 | $$(`.related-to-${related}`)?.forEach(el => el.classList.add('disabled'))
482 | }
483 | } else {
484 | if(element.target.checked) {
485 | $$(`.related-to-${related}-a`)?.forEach(el => el.classList.add('related-item-hidden'))
486 | $$(`.related-to-${related}-b`)?.forEach(el => el.classList.remove('related-item-hidden'))
487 | } else {
488 | $$(`.related-to-${related}-a`)?.forEach(el => el.classList.remove('related-item-hidden'))
489 | $$(`.related-to-${related}-b`)?.forEach(el => el.classList.add('related-item-hidden'))
490 | }
491 | }
492 | }
493 |
494 | window.roundTo = function (num, decimals = 5) {
495 | if (typeof num !== 'number' || !isFinite(num)) return num;
496 | if (num.toString().includes('e')) {
497 | const splitted = num.toString().split('e');
498 | return roundTo(+splitted[0], decimals) + `e${splitted[1]}`;
499 | };
500 | return +(Math.round(num + `e+${decimals}`) + `e-${decimals}`);
501 | }
502 |
503 | window.delay = ms => new Promise(resolve => setTimeout(resolve, ms));
504 | window.generateRandomDigit = () => Math.floor(Math.random() * 10);
505 | window.convertTZ = (date, tzString) => new Date((typeof date === "string" ? new Date(date) : date).toLocaleString("en-US", {timeZone: tzString}));
506 | window.animateElement = async (element, isText) => {
507 | const originalText = element.innerHTML;
508 | let digitIndices = [];
509 | let originalDigits = [];
510 |
511 | [...originalText].forEach((char, index) => {
512 | if (!isNaN(parseInt(char, 10)) && char !== ' ') {
513 | digitIndices.push(index);
514 | originalDigits.push(char);
515 | }
516 | });
517 |
518 | for (let i = 0; i < 10; i++) {
519 | let textArray = [...originalText];
520 | digitIndices.forEach(index => {
521 | textArray[index] = generateRandomDigit();
522 | });
523 | element.innerHTML = textArray.join('');
524 | await delay(30);
525 | }
526 |
527 | digitIndices.forEach((index, digitIndex) => {
528 | let textArray = [...originalText];
529 | textArray[index] = originalDigits[digitIndex];
530 | element.innerHTML = textArray.join('');
531 | });
532 | };
533 | window.animateElements = function(){
534 | $$('.animate').forEach(async (element) => animateElement(element));
535 | $$('.animate-text').forEach(async (element) => animateElement(element, true));
536 | }
537 | window.plural = function (number, versions, options = { showNumber: true, localize: true, locale: null }) {
538 | const words = {
539 | zero: "",
540 | one: "",
541 | two: "",
542 | few: "",
543 | many: "",
544 | other: ""
545 | };
546 | const parts = versions.split(':');
547 | if (parts.length === 1) {
548 | Object.keys(words).forEach(key => words[key] = versions);
549 | } else {
550 | let i = 0;
551 | for (let key in words) {
552 | words[key] = parts[i] || parts[0];
553 | i++;
554 | }
555 | }
556 | const rule = new Intl.PluralRules(options.locale ?? window.locale).select(Math.floor(number));
557 | return `${options.showNumber ? `${options.localize ? number.toLocaleString(options.locale ?? window.locale) : number} ` : ''}${words[rule]}`;
558 | };
559 |
560 | window.numberToWords = function(num) {
561 | if (num === 0) return 'zero';
562 | const belowTwenty = [
563 | '', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine',
564 | 'ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen',
565 | 'sixteen', 'seventeen', 'eighteen', 'nineteen'];
566 |
567 | const tens = ['', '', 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety'];
568 |
569 | const hundreds = [
570 | '', 'one hundred', 'two hundred', 'three hundred', 'four hundred', 'five hundred',
571 | 'six hundred', 'seven hundred', 'eight hundred', 'nine hundred'];
572 |
573 | const integerScales = [
574 | 'thousands:thousand:thousands:thousands:thousands:thousands', 'millions:million:millions:millions:millions:millions', 'billions:billion:billions:billions:billions:billions', 'trillions:trillion:trillions:trillions:trillions:trillions', 'quadrillions:quadrillion:quadrillions:quadrillions:quadrillions:quadrillions',
575 | 'quintillions:quintillion:quintillions:quintillions:quintillions:quintillions', 'sextillions:sextillion:sextillions:sextillions:sextillions:sextillions', 'septillions:septillion:septillions:septillions:septillions:septillions', 'octillions:octillion:octillions:octillions:octillions:octillions', 'nonillions:nonillion:nonillions:nonillions:nonillions:nonillions',
576 | 'decillions:decillion:decillions:decillions:decillions:decillions', 'undecillions:undecillion:undecillions:undecillions:undecillions:undecillions', 'duodecillions:duodecillion:duodecillions:duodecillions:duodecillions:duodecillions', 'tredecillions:tredecillion:tredecillions:tredecillions:tredecillions:tredecillions', 'quattuordecillions:quattuordecillion:quattuordecillions:quattuordecillions:quattuordecillions:quattuordecillions',
577 | 'quindecillions:quindecillion:quindecillions:quindecillions:quindecillions:quindecillions', 'sexdecillions:sexdecillion:sexdecillions:sexdecillions:sexdecillions:sexdecillions', 'septendecillions:septendecillion:septendecillions:septendecillions:septendecillions:septendecillions', 'octodecillions:octodecillion:octodecillions:octodecillions:octodecillions:octodecillions',
578 | 'novemdecillions:novemdecillion:novemdecillions:novemdecillions:novemdecillions:novemdecillions', 'vigintillions:vigintillion:vigintillions:vigintillions:vigintillions:vigintillions'];
579 |
580 | const decimalScales = [
581 | 'tenths:tenth:tenths:tenths:tenths:tenths', 'hundredths:hundredth:hundredths:hundredths:hundredths:hundredths', 'thousandths:thousandth:thousandths:thousandths:thousandths:thousandths', 'ten-thousandths:ten-thousandth:ten-thousandths:ten-thousandths:ten-thousandths:ten-thousandths', 'hundred-thousandths:hundred-thousandth:hundred-thousandths:hundred-thousandths:hundred-thousandths:hundred-thousandths', 'millionths:millionth:millionths:millionths:millionths:millionths',
582 | 'ten-millionths:ten-millionth:ten-millionths:ten-millionths:ten-millionths:ten-millionths', 'hundred-millionths:hundred-millionth:hundred-millionths:hundred-millionths:hundred-millionths:hundred-millionths', 'billionths:billionth:billionths:billionths:billionths:billionths', 'ten-billionths:ten-billionth:ten-billionths:ten-billionths:ten-billionths:ten-billionths', 'hundred-billionths:hundred-billionth:hundred-billionths:hundred-billionths:hundred-billionths:hundred-billionths',
583 | 'trillionths:trillionth:trillionths:trillionths:trillionths:trillionths', 'ten-trillionths:ten-trillionth:ten-trillionths:ten-trillionths:ten-trillionths:ten-trillionths', 'hundred-trillionths:hundred-trillionth:hundred-trillionths:hundred-trillionths:hundred-trillionths:hundred-trillionths', 'quadrillionths:quadrillionth:quadrillionths:quadrillionths:quadrillionths:quadrillionths', 'ten-quadrillionths:ten-quadrillionth:ten-quadrillionths:ten-quadrillionths:ten-quadrillionths:ten-quadrillionths',
584 | 'hundred-quadrillionths:hundred-quadrillionth:hundred-quadrillionths:hundred-quadrillionths:hundred-quadrillionths:hundred-quadrillionths', 'quintillionths:quintillionth:quintillionths:quintillionths:quintillionths:quintillionths', 'ten-quintillionths:ten-quintillionth:ten-quintillionths:ten-quintillionths:ten-quintillionths:ten-quintillionths', 'hundred-quintillionths:hundred-quintillionth:hundred-quintillionths:hundred-quintillionths:hundred-quintillionths:hundred-quintillionths',
585 | 'sextillionths:sextillionth:sextillionths:sextillionths:sextillionths:sextillionths', 'septillionths:septillionth:septillionths:septillionths:septillionths:septillionths', 'octillionths:octillionth:octillionths:octillionths:octillionths:octillionths', 'nonillionths:nonillionth:nonillionths:nonillionths:nonillionths:nonillionths', 'decillionths:decillionth:decillionths:decillionths:decillionths:decillionths',
586 | 'undecillionths:undecillionth:undecillionths:undecillionths:undecillionths:undecillionths', 'duodecillionths:duodecillionth:duodecillionths:duodecillionths:duodecillionths:duodecillionths', 'tredecillionths:tredecillionth:tredecillionths:tredecillionths:tredecillionths:tredecillionths', 'quattuordecillionths:quattuordecillionth:quattuordecillionths:quattuordecillionths:quattuordecillionths:quattuordecillionths', 'quindecillionths:quindecillionth:quindecillionths:quindecillionths:quindecillionths:quindecillionths',
587 | 'sexdecillionths:sexdecillionth:sexdecillionths:sexdecillionths:sexdecillionths:sexdecillionths', 'septendecillionths:septendecillionth:septendecillionths:septendecillionths:septendecillionths:septendecillionths', 'octodecillionths:octodecillionth:octodecillionths:octodecillionths:octodecillionths:octodecillionths', 'novemdecillionths:novemdecillionth:novemdecillionths:novemdecillionths:novemdecillionths:novemdecillionths', 'vigintillionths:vigintillionth:vigintillionths:vigintillionths:vigintillionths:vigintillionths'];
588 |
589 | let chunks = [];
590 | let currentNum = BigInt(Math.floor(num));
591 |
592 | while (currentNum > 0n) {
593 | chunks.unshift(currentNum % 1000n);
594 | currentNum = currentNum / 1000n;
595 | }
596 |
597 | if (chunks.length === 0) chunks.push(0n); // Handle numbers less than 1
598 |
599 | let integerWords = chunks.map((chunk, index) => {
600 | chunk = Number(chunk);
601 | if (chunk === 0) return '';
602 | const hundred = Math.floor(chunk / 100);
603 | const tenUnit = chunk % 100;
604 | const ten = Math.floor(tenUnit / 10);
605 | const unit = tenUnit % 10;
606 |
607 | let chunkText = '';
608 |
609 | if (hundred > 0) chunkText += hundreds[hundred] + ' ';
610 | if (tenUnit >= 20) {
611 | chunkText += tens[ten] + ' ';
612 | if (unit > 0) chunkText += belowTwenty[unit];
613 | } else if (tenUnit > 0) {
614 | chunkText += belowTwenty[tenUnit];
615 | }
616 |
617 | if (chunk > 0 && index < chunks.length - 1) {
618 | let scale = integerScales[chunks.length - index - 2];
619 | return chunkText.trim() + ' ' + plural(chunk, scale, {showNumber: false});
620 | }
621 | return chunkText.trim();
622 | }).join(' ').trim();
623 |
624 | let decimalPart = (num - Math.floor(num)).toFixed(num.toString().split('.')?.[1]?.length).toString().slice(2);
625 | let decimalLength = decimalPart > 0 ? decimalPart.toString().replace('-', '').length : 0;
626 |
627 | return (integerWords.length > 0 ? integerWords : 'zero') + (decimalLength > 0 ? ' point ' + numberToWords(decimalPart) + ' ' + plural(decimalPart, decimalScales[decimalLength-1], {showNumber: false}) : '');
628 | }
629 |
630 | window.toSentenceCase = function(str){
631 | const firstLetter = str.substr(0, 1);
632 | return firstLetter.toUpperCase() + str.substr(1).toLowerCase();
633 | }
634 |
635 | window.toTitleCase = function(str) {
636 | return str.toLowerCase().split(' ').map(function(word) {
637 | return (word.charAt(0).toUpperCase() + word.slice(1));
638 | }).join(' ');
639 | }
640 |
641 | window.setCookie = function(key, value){
642 | const date = new Date();
643 | date.setTime(date.getTime() + (10 * 365 * 24 * 60 * 60 * 1000));
644 | document.cookie = `${key}=${value};expires=${date.toUTCString()};path=/`;
645 | }
646 |
647 | window.getCookie = function(key) {
648 | let nameEQ = key + "=";
649 | let ca = document.cookie.split(';');
650 | for (let i = 0; i < ca.length; i++) {
651 | let c = ca[i];
652 | while (c.charAt(0) === ' ') c = c.substring(1);
653 | if (c.indexOf(nameEQ) === 0) {
654 | return decodeURIComponent(c.substring(nameEQ.length, c.length));
655 | }
656 | }
657 | return null;
658 | }
--------------------------------------------------------------------------------
/assets/js/hourpicker.js:
--------------------------------------------------------------------------------
1 | const INPUTS = $$('.hourpicker-input');
2 | let timepickerFormat = true
3 | let currentInput = {
4 | input: null,
5 | hour: null,
6 | minute: null,
7 | }
8 |
9 | function createTimepicker() {
10 | const TIMEPICKER = document.createElement('div');
11 | const {top, left} = currentInput.input.getBoundingClientRect()
12 | const {offsetHeight} = currentInput.input
13 | const VALUE = currentInput.input.value.split(':')
14 |
15 | TIMEPICKER.classList.add('timepicker');
16 | TIMEPICKER.classList.add('timepicker--hourpicker');
17 | TIMEPICKER.innerHTML = `
18 |
Hour
22 | 23 |:
25 |Minute
27 | 28 |(parentContext: P, context: T): P extends null ? T : P & T;
339 |
340 | /**
341 | * @alias Chart.helpers.math
342 | * @namespace
343 | */
344 | declare const PI: number;
345 | declare const TAU: number;
346 | declare const PITAU: number;
347 | declare const INFINITY: number;
348 | declare const RAD_PER_DEG: number;
349 | declare const HALF_PI: number;
350 | declare const QUARTER_PI: number;
351 | declare const TWO_THIRDS_PI: number;
352 | declare const log10: (x: number) => number;
353 | declare const sign: (x: number) => number;
354 | declare function almostEquals(x: number, y: number, epsilon: number): boolean;
355 | /**
356 | * Implementation of the nice number algorithm used in determining where axis labels will go
357 | */
358 | declare function niceNum(range: number): number;
359 | /**
360 | * Returns an array of factors sorted from 1 to sqrt(value)
361 | * @private
362 | */
363 | declare function _factorize(value: number): number[];
364 | declare function isNumber(n: unknown): n is number;
365 | declare function almostWhole(x: number, epsilon: number): boolean;
366 | /**
367 | * @private
368 | */
369 | declare function _setMinAndMaxByKey(array: Record Hour : Minute : Second There was an error with your calculation. {
4 | const OPTION_HEAD = option.querySelector('.calculator-content-head')
5 |
6 | OPTION_HEAD.addEventListener('click', (event) => {
7 |
8 | if(!event.composedPath().includes($('.js-add-button'))) {
9 | option.classList.toggle('calculator-content--active')
10 | }
11 | })
12 | })
--------------------------------------------------------------------------------
/assets/js/themes.js:
--------------------------------------------------------------------------------
1 | const setActiveThemeButton = (theme) => {
2 | document.querySelectorAll('.header-popup__button').forEach(button => {
3 | if(button.classList.contains(`${theme}-theme`)) button.classList.add('header-popup__button--active')
4 | else button.classList.remove('header-popup__button--active')
5 | })
6 | }
7 |
8 | switch (localStorage.getItem('theme')) {
9 | case 'light':
10 | document.documentElement.classList = '';
11 | console.log('Theme: Light');
12 | localStorage.setItem('theme', 'light');
13 | window.addEventListener('DOMContentLoaded', () => {
14 | setActiveThemeButton('light')
15 | })
16 | break;
17 | case 'dark':
18 | document.documentElement.classList = 'dark';
19 | console.log('Theme: Dark');
20 | localStorage.setItem('theme', 'dark');
21 | window.addEventListener('DOMContentLoaded', () => {
22 | setActiveThemeButton('dark')
23 | })
24 | break;
25 | case 'system':
26 | default:
27 | document.documentElement.classList = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : '';
28 | console.log('Theme: System');
29 | localStorage.setItem('theme', 'system');
30 | window.addEventListener('DOMContentLoaded', () => {
31 | setActiveThemeButton('system')
32 | })
33 | }
--------------------------------------------------------------------------------
/assets/js/timepicker.js:
--------------------------------------------------------------------------------
1 | const INPUTS = $$('.timepicker-input');
2 | let timepickerFormat = true
3 | let currentInput = {
4 | input: null,
5 | hour: null,
6 | minute: null,
7 | second: null,
8 | }
9 |
10 | function createTimepicker() {
11 | const TIMEPICKER = document.createElement('div');
12 | const {top, left} = currentInput.input.getBoundingClientRect()
13 | const {offsetHeight} = currentInput.input
14 | const VALUE = currentInput.input.value.split(':')
15 |
16 | TIMEPICKER.classList.add('timepicker');
17 | TIMEPICKER.innerHTML = `
18 | Right Triangle Calculator';
20 | }
21 |
22 |
23 | add_shortcode( 'ci_right_triangle_calculator', 'display_calcio_ci_right_triangle_calculator' );
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
148 |
149 |
192 |
150 |
152 |
153 |
154 | Result
151 |
155 |
158 | a
156 | 3
157 |
159 |
162 | b
160 | 4
161 |
163 |
166 | c
164 | 5
165 |
167 |
170 | h
168 | 2.4
169 |
171 |
174 | α
172 | 36.8699° = 0.6435011 rad
173 |
175 |
178 | β
176 | 53.1301° = 0.9272952 rad
177 |
179 |
184 | area
180 | 6
181 | inradius
182 | 1
183 |
185 |
190 |
191 | perimeter
186 | 12
187 | circumradius
188 | 2.5
189 | Right Triangle Calculator';
20 | }
21 |
22 | add_shortcode( 'ci_right_triangle_calculator', 'display_ci_right_triangle_calculator' );
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Right Triangle Calculator Widget for WordPress
2 |
3 | Right triangle calculator finds missing triangle measurements. It calculates side lengths, angles, perimeter, area, altitude-to-hypotenuse, inradius, and circumradius.
4 |
5 | 
6 |
7 | ## Installation
8 |
9 | 1. [Download](https://github.com/pub-calculator-io/right-triangle-calculator/archive/refs/heads/master.zip) the ZIP file of this repository.
10 | 2. Upload the /right-triangle-calculator-master/ folder to the /wp-content/plugins/ directory.
11 | 3. Activate the [Right Triangle Calculator](https://www.calculator.io/right-triangle-calculator/ "Right Triangle Calculator Homepage") plugin through the "Plugins" menu in WordPress.
12 |
13 | ## Usage
14 | * Add the shortcode `[ci_right_triangle_calculator]` to your page, post or sidebar.
15 | * Or add the following code: `` to your template where you would like the Right Triangle Calculator to appear.
16 |
17 | ## Libraries in Use
18 | 1. https://mathjs.org/
19 | 2. https://katex.org/
20 | 3. https://github.com/aFarkas/lazysizes
21 | 4. https://github.com/RobinHerbots/Inputmask
22 | 5. https://air-datepicker.com/
23 | 6. https://www.chartjs.org/
24 |
--------------------------------------------------------------------------------
/readme.txt:
--------------------------------------------------------------------------------
1 | === CI Right triangle calculator ===
2 | Contributors: calculatorio
3 | Tags: right triangle calculator, 90-degree angle triangle calculation, hypotenuse determination, Pythagorean triples, triangle area and perimeter calculation, special right triangles, trigonometry in right triangles, calculating triangle altitude
4 | Requires at least: 5.0
5 | Tested up to: 6.4.0
6 | Stable tag: 1.0.0
7 | License: GPLv2 or later
8 | License URI: https://www.gnu.org/licenses/gpl-2.0.html
9 |
10 | Right triangle calculator finds missing triangle measurements. It calculates side lengths, angles, perimeter, area, altitude-to-hypotenuse, inradius, and circumradius.
11 |
12 | [https://www.calculator.io/right-triangle-calculator/](https://www.calculator.io/right-triangle-calculator/)
13 |
14 | == Usage ==
15 |
16 | Add the Right Triangle Calculator shortcode to your page, post or sidebar:
17 |
18 | `[ci_right_triangle_calculator]`
19 |
20 | Add the following code to your template where you would like the Right Triangle Calculator to appear:
21 |
22 | ``
23 |
24 | == Screenshots ==
25 |
26 | 1. The Right Triangle Calculator Input Form.
27 |
28 | == Installation ==
29 |
30 | 1. Upload the Right Triangle Calculator /ci_right_triangle_calculator/ folder to the /wp-content/plugins/ directory.
31 | 2. Activate the Right Triangle Calculator plugin through the "Plugins" menu in WordPress.
32 |
33 | == Changelog ==
34 |
35 | = 1.0.0 =
36 | * Initial release of Right Triangle Calculator
37 |
--------------------------------------------------------------------------------