├── assets ├── fonts │ └── Roboto-Regular.ttf └── satus │ ├── satus.css │ └── satus.js ├── _locales ├── am │ └── messages.json ├── ar │ └── messages.json ├── bg │ └── messages.json ├── bn │ └── messages.json ├── ca │ └── messages.json ├── cs │ └── messages.json ├── da │ └── messages.json ├── de │ └── messages.json ├── el │ └── messages.json ├── en │ └── messages.json ├── es │ └── messages.json ├── et │ └── messages.json ├── fa │ └── messages.json ├── fi │ └── messages.json ├── fil │ └── messages.json ├── fr │ └── messages.json ├── gu │ └── messages.json ├── he │ └── messages.json ├── hi │ └── messages.json ├── hin │ └── messages.json ├── hr │ └── messages.json ├── hu │ └── messages.json ├── id │ └── messages.json ├── it │ └── messages.json ├── ja │ └── messages.json ├── kn │ └── messages.json ├── ko │ └── messages.json ├── lt │ └── messages.json ├── lv │ └── messages.json ├── ml │ └── messages.json ├── mr │ └── messages.json ├── ms │ └── messages.json ├── nb_NO │ └── messages.json ├── nl │ └── messages.json ├── no │ └── messages.json ├── pl │ └── messages.json ├── pt_BR │ └── messages.json ├── pt_PT │ └── messages.json ├── ro │ └── messages.json ├── sk │ └── messages.json ├── sl │ └── messages.json ├── sr │ └── messages.json ├── sv │ └── messages.json ├── sw │ └── messages.json ├── ta │ └── messages.json ├── te │ └── messages.json ├── th │ └── messages.json ├── tr │ └── messages.json ├── uk │ └── messages.json ├── vi │ └── messages.json ├── zh_CN │ └── messages.json ├── zh_TW │ └── messages.json └── ru │ └── messages.json ├── background.js ├── content-script.js ├── newtab ├── index.html ├── styles.css └── script.js ├── manifest.json ├── readme.md └── locale.py /assets/fonts/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code-charity/History-Manager/HEAD/assets/fonts/Roboto-Regular.ttf -------------------------------------------------------------------------------- /_locales/am/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/ar/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/bg/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/bn/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/ca/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/cs/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/da/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/de/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/el/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/en/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/es/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/et/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/fa/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/fi/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/fil/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/fr/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/gu/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/he/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/hi/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/hin/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/hr/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/hu/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/id/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/it/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/ja/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/kn/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/ko/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/lt/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/lv/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/ml/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/mr/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/ms/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/nb_NO/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/nl/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/no/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/pl/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/pt_BR/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/pt_PT/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/ro/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/sk/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/sl/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/sr/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/sv/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/sw/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/ta/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/te/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/th/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/tr/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/uk/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/vi/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/zh_CN/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/zh_TW/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Search {ENGINE} or type a URL" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "This time, search with:" 7 | } 8 | } -------------------------------------------------------------------------------- /_locales/ru/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "searchEngineOrTypeAUrl": { 3 | "message": "Найдите в {ENGINE} или введите адрес" 4 | }, 5 | "thisTimeSearchWith": { 6 | "message": "В этот раз искать в:" 7 | } 8 | } -------------------------------------------------------------------------------- /background.js: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------- 2 | >>> BACKGROUND 3 | ---------------------------------------------------------------- 4 | # 5 | --------------------------------------------------------------*/ -------------------------------------------------------------------------------- /content-script.js: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------- 2 | >>> CONTENT SCRIPT 3 | ---------------------------------------------------------------- 4 | # 5 | --------------------------------------------------------------*/ -------------------------------------------------------------------------------- /newtab/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 |
7 |
8 | ### [**chrome webstore PREVIEW version!**](https://chrome.google.com/webstore/detail/history-manager/odognhgojidbcgconbcipmgffjcmfaoj) (commit from [july26](https://github.com/code-charity/History-Manager-with-indexedDB/tree/453f6696892e1182c9667467e5a50927a72d71ba) )
9 |
10 | #### Please select* "SEARCH IN TABLES", to see the feature to filter & make use of your history in multiple ways at once:
11 |
12 |
"
13 |
14 | *(should soon be a multi-search, requiring no selection)
15 |
16 |
17 | ---
18 |
19 | Please consider joining us. We fulfill wishes since 10+ years & unfortunately lost our main developer in 2022 :(
20 |
21 | 1.) Should we use the most powerful JS lib for search and various smart, predictive queries in future? (but not reinvent the wheel)
22 | - Compare History Manager with this older version from feburary using neither DB (just JS) https://github.com/code-charity/History-Manager-with-no-DB/releases/tag/v1.0-alpha.5 (it looks polished & has search in tables enabled by default. Yet missing some features)
23 | - (BTW SqlLite is also back for chrome by now https://www.sqlite.org/2024/sqlite-wasm-3450200.zip, unlike when we started)
24 |
25 | 2.) While july26 (above) is the most functional we got, the current master.zip already has GUI updates/enhancements.
26 | Please help us pick up/carry on our GUI lib too: https://github.com/code-for-charity/SATUS I dont know why the "latest commits in this repo are the older ones"
27 |
28 |
29 |
30 | Wiki »
31 |
--------------------------------------------------------------------------------
/newtab/styles.css:
--------------------------------------------------------------------------------
1 | /*--------------------------------------------------------------
2 | >>> STYLES
3 | ----------------------------------------------------------------
4 | # Fonts
5 | # Body
6 | # Themes
7 | # Skeleton
8 | # Header
9 | # Main
10 | # Sidebar
11 | # Layers
12 | --------------------------------------------------------------*/
13 |
14 | /*--------------------------------------------------------------
15 | # FONTS
16 | --------------------------------------------------------------*/
17 |
18 | @font-face {
19 | font-family: Roboto;
20 |
21 | src: url(../assets/fonts/Roboto-Regular.ttf);
22 | }
23 |
24 |
25 | /*--------------------------------------------------------------
26 | # BODY
27 | --------------------------------------------------------------*/
28 |
29 | body {
30 | font-family: Roboto, sans-serif;
31 | font-size: 16px;
32 |
33 | overflow: hidden;
34 |
35 | height: 100vh;
36 | margin: 0;
37 | }
38 |
39 |
40 | /*--------------------------------------------------------------
41 | # THEMES
42 | --------------------------------------------------------------*/
43 |
44 | .satus-base {
45 | --satus-base-background: #fff;
46 | --satus-main-background: #fff;
47 | }
48 |
49 |
50 | /*--------------------------------------------------------------
51 | # SKELETON
52 | --------------------------------------------------------------*/
53 |
54 | /*--------------------------------------------------------------
55 | # HEADER
56 | --------------------------------------------------------------*/
57 |
58 | .satus-header {
59 | box-shadow: none;
60 | }
61 |
62 | .satus-header>* {
63 | flex: 1;
64 | }
65 |
66 | .satus-header .satus-text-field {
67 | position: relative;
68 | }
69 |
70 | .satus-header .satus-text-field[focus][results] {
71 | border-bottom-color: transparent;
72 | border-bottom-right-radius: 0;
73 | border-bottom-left-radius: 0;
74 | }
75 |
76 | .satus-header .satus-text-field>svg {
77 | box-sizing: unset;
78 | max-width: 22px;
79 | max-height: 22px;
80 | margin: 0 0 0 8px;
81 |
82 | background-repeat: no-repeat;
83 | background-position: center;
84 | background-size: contain;
85 |
86 | justify-content: center;
87 | align-items: center;
88 | }
89 |
90 | .temporary-engine {
91 | height: 28px;
92 | margin: 0 0 0 6px;
93 | padding: 0 8px;
94 |
95 | border-radius: 4px;
96 | background: var(--satus-header-background);
97 | }
98 |
99 | .temporary-engine::after {
100 | line-height: 0;
101 |
102 | position: relative;
103 | top: 1px;
104 |
105 | margin-left: 8px;
106 |
107 | content: '✕';
108 | transition: opacity .3s cubic-bezier(.25, .8, .5, 1);
109 |
110 | opacity: .4;
111 | }
112 |
113 | .temporary-engine:hover::after {
114 | opacity: .85;
115 | }
116 |
117 | .satus-search__dropdown-menu {
118 | position: absolute;
119 | top: 100%;
120 | left: -1px;
121 |
122 | display: none;
123 | flex-direction: column;
124 |
125 | width: calc(100% + 2px);
126 | padding: 1px 8px 0;
127 |
128 | border: 1px solid var(--satus-text-field-border);
129 | border-top: 0;
130 | border-bottom-right-radius: 4px;
131 | border-bottom-left-radius: 4px;
132 | background: var(--satus-text-field-background);
133 | }
134 |
135 | .satus-header .satus-text-field[focus][results] .satus-search__dropdown-menu {
136 | display: flex;
137 | }
138 |
139 | .satus-search__results-list {
140 | display: flex;
141 |
142 | padding: 8px 0;
143 |
144 | border-top: 1px solid var(--satus-text-field-border);
145 |
146 | align-items: center;
147 | }
148 |
149 | .satus-search-results__item {
150 | width: 100%;
151 | padding: 6px 4px;
152 |
153 | border-radius: 4px;
154 | }
155 |
156 | .satus-search-results__item {
157 | transition: background-color .3s cubic-bezier(.25, .8, .5, 1);
158 | }
159 |
160 | .satus-search-results__item:hover {
161 | background-color: rgba(var(--satus-light), .08);
162 | }
163 |
164 | .satus-search-results__item:focus {
165 | background-color: rgba(var(--satus-light), .24);
166 | }
167 |
168 | .satus-search-results__item-icon {
169 | width: 18px;
170 | height: 18px;
171 | margin-right: 8px;
172 |
173 | background-repeat: no-repeat;
174 | background-position: center;
175 | background-size: contain;
176 |
177 | flex: 0 0 18px;
178 | }
179 |
180 | .satus-search-results__item-query {
181 | overflow: hidden;
182 |
183 | white-space: nowrap;
184 | text-overflow: ellipsis;
185 | }
186 |
187 | .satus-search-results__item-engine {
188 | padding-left: .3em;
189 |
190 | white-space: nowrap;
191 |
192 | opacity: .64;
193 | }
194 |
195 | .satus-search__engines {
196 | display: flex;
197 |
198 | padding: 8px 0;
199 |
200 | border-top: 1px solid var(--satus-text-field-border);
201 |
202 | align-items: center;
203 | }
204 |
205 | .satus-search__engines>button {
206 | width: 28px;
207 | height: 28px;
208 | margin: 0 0 0 8px;
209 |
210 | background-repeat: no-repeat;
211 | background-position: center;
212 | background-size: 18px;
213 | }
214 |
215 |
216 | /*--------------------------------------------------------------
217 | # MAIN
218 | --------------------------------------------------------------*/
219 |
220 | /*--------------------------------------------------------------
221 | # SIDEBAR
222 | --------------------------------------------------------------*/
223 |
224 | .satus-sidebar {
225 | box-shadow: none;
226 | }
227 |
228 |
229 | /*--------------------------------------------------------------
230 | # LAYERS
231 | --------------------------------------------------------------*/
232 |
233 | .satus-layers {
234 | border: 1px solid var(--satus-header-shadow);
235 | border-right: none;
236 | border-bottom: none;
237 | }
--------------------------------------------------------------------------------
/locale.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 |
4 | # ------------------------------------------------------------------------------
5 | # >>> TABLE OF CONTENTS:
6 | # ------------------------------------------------------------------------------
7 | # 1.0 Import modules
8 | # 2.0 Lower camel case
9 | # 3.0 Get list of files
10 | # 4.0 Add item
11 | # 5.0 Remove item
12 | # 6.0 Change key
13 | # 7.0 Decode
14 | # 8.0 Upgrade
15 | # 9.0 Initialization
16 | # ------------------------------------------------------------------------------
17 |
18 | # ------------------------------------------------------------------------------
19 | # 1.0 IMPORT MODULES
20 | # ------------------------------------------------------------------------------
21 |
22 | import io
23 | import json
24 | import os
25 | import pathlib
26 | import re
27 | import sys
28 |
29 |
30 | # ------------------------------------------------------------------------------
31 | # 2.0 LOWER CAMEL CASE
32 | # ------------------------------------------------------------------------------
33 |
34 | def lowerCamelCase(string):
35 | string = re.sub(r"(-|_)+", ' ', string).title()
36 | string = re.sub(r"[^a-zA-Z0-9]", '', string)
37 |
38 | return string[0].lower() + string[1:]
39 |
40 |
41 | # ------------------------------------------------------------------------------
42 | # 3.0 GET LIST OF FILES
43 | # ------------------------------------------------------------------------------
44 |
45 | def getListOfFiles(path):
46 | allFiles = list()
47 |
48 | for entry in os.listdir(path):
49 | fullPath = os.path.join(path, entry)
50 |
51 | if not os.path.isdir(fullPath):
52 | allFiles.append(fullPath)
53 |
54 | for entry in os.listdir(path):
55 | fullPath = os.path.join(path, entry)
56 |
57 | if os.path.isdir(fullPath):
58 | allFiles = allFiles + getListOfFiles(fullPath)
59 |
60 | return allFiles
61 |
62 |
63 | # ------------------------------------------------------------------------------
64 | # 4.0 ADD ITEM
65 | # ------------------------------------------------------------------------------
66 |
67 | def addItem(allFiles):
68 | message = input('Enter your message: ')
69 | camelized_message = lowerCamelCase(message)
70 |
71 | for keyFile in allFiles:
72 | with open(keyFile, 'r+') as json_file:
73 | data = json.load(json_file)
74 |
75 | if (camelized_message in data) == False:
76 | data[camelized_message] = {'message': message}
77 |
78 | json_file.seek(0)
79 | json.dump(data, json_file, ensure_ascii=False, indent=4, sort_keys=True)
80 | json_file.truncate()
81 |
82 |
83 | # ------------------------------------------------------------------------------
84 | # 5.0 REMOVE ITEM
85 | # ------------------------------------------------------------------------------
86 |
87 | def removeItem(allFiles):
88 | key = input('Enter your key (lowerCamelCase): ')
89 |
90 | for keyFile in allFiles:
91 | with open(keyFile, 'r+') as json_file:
92 | data = json.load(json_file)
93 |
94 | if data[key]:
95 | del data[key]
96 |
97 | json_file.seek(0)
98 | json.dump(data, json_file, ensure_ascii=False, indent=4,
99 | sort_keys=True)
100 | json_file.truncate()
101 |
102 |
103 | # ------------------------------------------------------------------------------
104 | # 6.0 CHANGE KEY
105 | # ------------------------------------------------------------------------------
106 |
107 | def changeKey(allFiles):
108 | old_key = input('Enter key: ')
109 | new_key = input('Enter new key: ')
110 |
111 | for keyFile in allFiles:
112 | with open(keyFile, 'r+') as file:
113 | data = json.load(file)
114 |
115 | if old_key in data:
116 | data[new_key] = data[old_key]
117 |
118 | del data[old_key]
119 |
120 | file.seek(0)
121 | json.dump(data, file, ensure_ascii=False, indent=4, sort_keys=True)
122 | file.truncate()
123 |
124 |
125 | # ------------------------------------------------------------------------------
126 | # 7.0 DECODE
127 | # ------------------------------------------------------------------------------
128 |
129 | def decodeCharacters(allFiles):
130 | for keyFile in allFiles:
131 | with open(keyFile, 'r+') as json_file:
132 | data = json.load(json_file)
133 |
134 | json_file.seek(0)
135 | json.dump(data, json_file, ensure_ascii=False, indent=4,
136 | sort_keys=True)
137 | json_file.truncate()
138 |
139 |
140 | # ------------------------------------------------------------------------------
141 | # 8.0 UPGRADE
142 | # ------------------------------------------------------------------------------
143 |
144 | def upgrade():
145 | locales = [
146 | 'am',
147 | 'ar',
148 | 'bg',
149 | 'bn',
150 | 'ca',
151 | 'cs',
152 | 'da',
153 | 'de',
154 | 'el',
155 | 'en',
156 | 'es',
157 | 'et',
158 | 'fa',
159 | 'fi',
160 | 'fil',
161 | 'fr',
162 | 'gu',
163 | 'he',
164 | 'hi',
165 | 'hin',
166 | 'hr',
167 | 'hu',
168 | 'id',
169 | 'it',
170 | 'ja',
171 | 'kn',
172 | 'ko',
173 | 'lt',
174 | 'lv',
175 | 'ml',
176 | 'mr',
177 | 'ms',
178 | 'nb_NO',
179 | 'nl',
180 | 'no',
181 | 'pl',
182 | 'pt_BR',
183 | 'pt_PT',
184 | 'ro',
185 | 'ru',
186 | 'sk',
187 | 'sl',
188 | 'sr',
189 | 'sv',
190 | 'sw',
191 | 'ta',
192 | 'te',
193 | 'th',
194 | 'tr',
195 | 'uk',
196 | 'vi',
197 | 'zh_CN',
198 | 'zh_TW'
199 | ]
200 |
201 | if os.path.exists('_locales/en/messages.json'):
202 | file = open('_locales/en/messages.json', 'r+')
203 |
204 | default_locale = json.load(file)
205 |
206 | file.close()
207 | else:
208 | default_locale = {}
209 |
210 | for locale in locales:
211 | path = '_locales/' + locale
212 |
213 | if not os.path.exists(path):
214 | pathlib.Path(path).mkdir(parents=True, exist_ok=True)
215 |
216 | file = io.open(path + '/messages.json', mode='w', encoding='utf-8')
217 |
218 | json.dump(default_locale, file, ensure_ascii=False, indent=4, sort_keys=True)
219 |
220 | file.close()
221 | else:
222 | with open(path + '/messages.json', 'r+') as file:
223 | data = json.load(file)
224 |
225 | file.seek(0)
226 |
227 | for key in default_locale:
228 | if (key in data) == False:
229 | data[key] = default_locale[key]
230 |
231 | json.dump(data, file, ensure_ascii=False, indent=4, sort_keys=True)
232 |
233 | file.truncate()
234 |
235 | file.close()
236 |
237 |
238 | # ------------------------------------------------------------------------------
239 | # 9.0 INITIALIZATION
240 | # ------------------------------------------------------------------------------
241 |
242 | if not os.path.exists('_locales/'):
243 | pathlib.Path('_locales/').mkdir(parents=True, exist_ok=True)
244 |
245 | allFiles = getListOfFiles('_locales/')
246 |
247 | for arg in sys.argv:
248 | if arg == '-add':
249 | addItem(allFiles)
250 | elif arg == '-remove':
251 | removeItem(allFiles)
252 | elif arg == '-decode':
253 | decodeCharacters(allFiles)
254 | elif arg == '-change-key':
255 | changeKey(allFiles)
256 | elif arg == '-upgrade':
257 | upgrade()
--------------------------------------------------------------------------------
/newtab/script.js:
--------------------------------------------------------------------------------
1 | /*--------------------------------------------------------------
2 | >>> SCRIPT
3 | ----------------------------------------------------------------
4 | # Skeleton
5 | # Initialization
6 | --------------------------------------------------------------*/
7 |
8 | /*--------------------------------------------------------------
9 | # SKELETON
10 | --------------------------------------------------------------*/
11 |
12 | var skeleton = {
13 | component: 'base',
14 | on: {
15 | click: function (event) {
16 | var founded = false;
17 |
18 | for (var i = 0, l = event.path.length; i < l; i++) {
19 | var element = event.path[i];
20 |
21 | if (typeof element.className === 'string' && element.className.indexOf('satus-search') !== -1) {
22 | founded = true;
23 | }
24 | }
25 |
26 | if (founded === false) {
27 | skeleton.header.search.rendered.removeAttribute('focus');
28 | }
29 | }
30 | },
31 |
32 | header: {
33 | component: 'header',
34 |
35 | section_left: {
36 | component: 'section',
37 | variant: 'align-start'
38 | },
39 | search: {
40 | component: 'text-field',
41 | class: 'satus-search',
42 | storage: false,
43 | placeholder: function () {
44 | var placeholder = satus.locale.get('searchEngineOrTypeAUrl'),
45 | search_engine = satus.storage.get('searchEngine');
46 |
47 | if (this.skeleton.engines[search_engine]) {
48 | search_engine = this.skeleton.engines[search_engine].name;
49 | } else {
50 | search_engine = this.skeleton.engines['google'].name;
51 | }
52 |
53 | return placeholder.replace('{ENGINE}', search_engine);
54 | },
55 | on: {
56 | focus: function () {
57 | this.setAttribute('focus', '');
58 | },
59 | input: function () {
60 | this.skeleton.dropDownMenu.results.rendered.update();
61 |
62 | if (this.value.length > 0) {
63 | this.setAttribute('focus', '');
64 | this.setAttribute('results', '');
65 | } else {
66 | this.removeAttribute('results');
67 | }
68 | },
69 | keydown: function (event) {
70 | if (event.keyCode === 13) {
71 | var list = this.skeleton.dropDownMenu.results.rendered;
72 |
73 | if (list.firstChild) {
74 | list.firstChild.click();
75 | }
76 | }
77 | }
78 | },
79 | engines: {
80 | google: {
81 | name: 'Google',
82 | url: 'https://www.google.com/search?q=',
83 | favicon: 'https://www.google.com/favicon.ico'
84 | },
85 | youtube: {
86 | name: 'YouTube',
87 | url: 'https://youtube.com/results?search_query=',
88 | favicon: 'https://youtube.com/favicon.ico'
89 | },
90 | duckduckgo: {
91 | name: 'DuckDuckGo',
92 | url: 'https://duckduckgo.com/?q=',
93 | favicon: 'https://duckduckgo.com/favicon.ico'
94 | },
95 | bing: {
96 | name: 'Bing',
97 | url: 'https://www.bing.com/search?q=',
98 | favicon: 'https://www.bing.com/favicon.ico'
99 | },
100 | yahoo: {
101 | name: 'Yahoo',
102 | url: 'https://search.yahoo.com/',
103 | favicon: 'https://search.yahoo.com/favicon.ico'
104 | },
105 | ecosia: {
106 | name: 'Ecosia',
107 | url: 'https://www.ecosia.org/search?q=',
108 | favicon: 'https://cdn-static.ecosia.org/assets/images/ico/favicon.ico'
109 | }
110 | },
111 | before: {
112 | svg: {
113 | component: 'svg',
114 | attr: {
115 | 'viewBox': '0 0 24 24',
116 | 'fill': 'currentColor'
117 | },
118 |
119 | path: {
120 | component: 'path',
121 | attr: {
122 | 'd': 'm20.5 19-5.7-5.7a6.5 6.5 0 1 0-1.5 1.5l5.7 5.7 1.5-1.5zM5 9.5a4.5 4.5 0 1 1 9 0 4.5 4.5 0 0 1-9 0z'
123 | }
124 | }
125 | }
126 | },
127 |
128 | dropDownMenu: {
129 | component: 'div',
130 | class: 'satus-search__dropdown-menu',
131 |
132 | results: {
133 | component: 'div',
134 | class: 'satus-search__results-list',
135 | properties: {
136 | update: function () {
137 | var list = this.skeleton.rendered,
138 | search_element = this.skeleton.parentSkeleton.parentSkeleton.rendered,
139 | search_engines = this.skeleton.parentSkeleton.parentSkeleton.engines,
140 | default_search_engine = satus.storage.get('defaultSearchEngine') || 'google';
141 |
142 | if (satus.isElement(search_element.temporaryEngine)) {
143 | default_search_engine = search_element.temporaryEngine.name;
144 | }
145 |
146 | satus.empty(list);
147 |
148 | satus.render({
149 | component: 'button',
150 | class: 'satus-search-results__item',
151 | attr: {
152 | url: search_engines[default_search_engine].url
153 | },
154 | on: {
155 | click: function () {
156 | window.open(this.getAttribute('url') + encodeURIComponent(this.parentNode.skeleton.parentSkeleton.parentSkeleton.rendered.value), '_self');
157 | }
158 | },
159 | before: {
160 | icon: {
161 | component: 'span',
162 | class: 'satus-search-results__item-icon',
163 | style: {
164 | backgroundImage: 'url(' + search_engines[default_search_engine].favicon + ')'
165 | }
166 | }
167 | },
168 |
169 | query: {
170 | component: 'span',
171 | class: 'satus-search-results__item-query',
172 | text: this.skeleton.parentSkeleton.parentSkeleton.rendered.value
173 | },
174 | engine: {
175 | component: 'span',
176 | class: 'satus-search-results__item-engine',
177 | text: '- ' + search_engines[default_search_engine].name + ' ' + 'Search'
178 | }
179 | }, list);
180 | }
181 | }
182 | },
183 | engines: {
184 | component: 'div',
185 | class: 'satus-search__engines',
186 | on: {
187 | render: function () {
188 | var search_engines = this.skeleton.parentSkeleton.parentSkeleton.engines;
189 |
190 | satus.render({
191 | component: 'span',
192 | text: 'thisTimeSearchWith'
193 | }, this);
194 |
195 | for (var key in search_engines) {
196 | var search_engine = search_engines[key];
197 |
198 | satus.render({
199 | component: 'button',
200 | variant: 'icon',
201 | attr: {
202 | name: key
203 | },
204 | style: {
205 | backgroundImage: 'url(' + search_engine.favicon + ')'
206 | },
207 | on: {
208 | click: function () {
209 | var name = this.getAttribute('name'),
210 | search_element = this.parentNode.skeleton.parentSkeleton.parentSkeleton.rendered,
211 | search_engine = search_element.skeleton.engines[name];
212 |
213 | if (search_element.temporaryEngine) {
214 | search_element.temporaryEngine.remove();
215 | }
216 |
217 | search_element.temporaryEngine = satus.render({
218 | component: 'button',
219 | class: 'temporary-engine',
220 | text: search_engine.name,
221 | properties: {
222 | name: name,
223 | data: search_engine
224 | },
225 | on: {
226 | click: function () {
227 | var search_element = skeleton.header.search.rendered;
228 |
229 | this.remove();
230 |
231 | delete search_element.temporaryEngine;
232 |
233 | search_element.skeleton.dropDownMenu.results.rendered.update();
234 | }
235 | }
236 | });
237 |
238 | search_element.firstChild.after(search_element.temporaryEngine);
239 |
240 | search_element.skeleton.dropDownMenu.results.rendered.update();
241 | }
242 | }
243 | }, this);
244 | }
245 | }
246 | }
247 | }
248 | }
249 | },
250 | section_right: {
251 | component: 'section',
252 | variant: 'align-end'
253 | }
254 | },
255 | main: {
256 | component: 'main',
257 |
258 | sidebar: {
259 | component: 'sidebar'
260 | },
261 | layers: {
262 | component: 'layers'
263 | }
264 | }
265 | };
266 |
267 |
268 | /*--------------------------------------------------------------
269 | # INITIALIZATION
270 | --------------------------------------------------------------*/
271 |
272 | satus.storage.import(function (items) {
273 | var language = items.language || window.navigator.language;
274 |
275 | satus.locale.import(language, function () {
276 | satus.render(skeleton);
277 | }, '_locales/');
278 | });
--------------------------------------------------------------------------------
/assets/satus/satus.css:
--------------------------------------------------------------------------------
1 | /*--------------------------------------------------------------
2 | # ANIMATIONS
3 | --------------------------------------------------------------*/
4 |
5 | @keyframes fadeIn {
6 | from {
7 | opacity: 0;
8 | }
9 | to {
10 | opacity: 1;
11 | }
12 | }
13 |
14 | @keyframes fadeOut {
15 | from {
16 | opacity: 1;
17 | }
18 | to {
19 | opacity: 0;
20 | }
21 | }
22 |
23 | @keyframes zoomIn {
24 | from {
25 | transform: scale(.8);
26 | opacity: 0;
27 | }
28 | to {
29 | transform: scale(1);
30 | opacity: 1;
31 | }
32 | }
33 |
34 | @keyframes zoomOut {
35 | from {
36 | transform: scale(1);
37 | opacity: 1;
38 | }
39 | to {
40 | transform: scale(.8);
41 | opacity: 0;
42 | }
43 | }
44 | /*--------------------------------------------------------------
45 | >>> THEMES
46 | --------------------------------------------------------------*/
47 |
48 | .satus-base {
49 | --satus-light: 0, 20, 82;
50 | --satus-primary: #ff4158;
51 |
52 | --satus-base-background: #f3f4f6;
53 | --satus-base-text: #565e76;
54 |
55 | --satus-header-background: #fff;
56 | --satus-header-text: #565e76;
57 | --satus-header-shadow: #dcdee5;
58 |
59 | --satus-layers-background: #f3f4f6;
60 | --satus-layers-text: #565e76;
61 |
62 | --satus-section-background: #fff;
63 | --satus-section-border: #dcdee5;
64 |
65 | --satus-sidebar-background: #fff;
66 | --satus-sidebar-text: #565e76;
67 | --satus-sidebar-shadow: #dcdee5;
68 |
69 | --satus-modal-background: 255, 255, 255;
70 | --satus-modal-text: 103, 118, 142;
71 | --satus-modal-shadow: #7d86a1;
72 |
73 | --satus-text-field-background: #edf0f2;
74 | --satus-text-field-border: #dcdee5;
75 | --satus-text-field-color: #7d8ba1;
76 | --satus-text-field-selection: rgb(149, 166, 178, .35);
77 | --satus-text-field-cursor: #fa0;
78 |
79 | --satus-switch-track: #e1e4ea;
80 | --satus-switch-thumb: #fff;
81 |
82 | --satus-main-background: #f0f2f4;
83 | }
84 | /*--------------------------------------------------------------
85 | >>> NORMALIZE
86 | --------------------------------------------------------------*/
87 |
88 | :where([class^=satus]) {
89 | box-sizing: border-box;
90 | }
91 |
92 | :where([class^=satus])[hidden]:not([hidden^='hidden']) {
93 | display: none;
94 | }
95 |
96 | :where([class^=satus])[transparent] {
97 | opacity: 0;
98 | }
99 |
100 |
101 | /*--------------------------------------------------------------
102 | # SCROLLBAR
103 | --------------------------------------------------------------*/
104 |
105 | .satus-base ::-webkit-scrollbar {
106 | width: 4px;
107 | }
108 |
109 | .satus-base ::-webkit-scrollbar:hover {
110 | width: 8px;
111 | }
112 |
113 | .satus-base ::-webkit-scrollbar-thumb {
114 | background: rgba(var(--satus-light), .2);
115 | }
116 |
117 | .satus-base ::-webkit-scrollbar-thumb:hover {
118 | background: rgba(var(--satus-light), .3);
119 | }
120 | /*--------------------------------------------------------------
121 | >>> MODAL
122 | ----------------------------------------------------------------
123 | # Container
124 | # Scrim
125 | # Surface
126 | # Variants
127 | # Vertical menu
128 | --------------------------------------------------------------*/
129 |
130 |
131 | /*--------------------------------------------------------------
132 | # CONTAINER
133 | --------------------------------------------------------------*/
134 |
135 | .satus-modal {
136 | position: fixed;
137 | z-index: 9;
138 | top: 0;
139 | left: 0;
140 | display: flex;
141 | width: 100%;
142 | height: 100vh;
143 | justify-content: center;
144 | align-items: center;
145 | }
146 |
147 |
148 | /*--------------------------------------------------------------
149 | # SCRIM
150 | --------------------------------------------------------------*/
151 |
152 | .satus-modal__scrim {
153 | position: absolute;
154 | top: 0;
155 | left: 0;
156 | width: 100%;
157 | height: 100%;
158 | animation: fadeIn 150ms linear forwards;
159 | opacity: 0;
160 | background: rgba(0, 0, 0, .16);
161 | backdrop-filter: blur(8px);
162 | }
163 |
164 | .satus-modal--closing .satus-modal__scrim {
165 | animation: fadeOut 70ms linear forwards;
166 | }
167 |
168 |
169 | /*--------------------------------------------------------------
170 | # SURFACE
171 | --------------------------------------------------------------*/
172 |
173 | .satus-modal__surface {
174 | display: flex;
175 | overflow-y: auto;
176 | flex-direction: column;
177 | box-sizing: border-box;
178 | width: 95%;
179 | min-width: 240px;
180 | max-width: 560px;
181 | max-height: 80%;
182 | margin: 8px;
183 | padding: 12px 16px;
184 | transform: scale(.8);
185 | animation: zoomIn 150ms linear forwards;
186 | animation-delay: 20ms;
187 | opacity: 0;
188 | color: rgb(var(--satus-modal-text));
189 | border-radius: 6px;
190 | background-color: rgb(var(--satus-modal-background));
191 | box-shadow: 0 1px 4px var(--satus-modal-shadow);
192 | }
193 |
194 | .satus-modal--closing .satus-modal__surface {
195 | animation: zoomOut 70ms linear forwards;
196 | }
197 |
198 |
199 | /*--------------------------------------------------------------
200 | # VARIANTS
201 | --------------------------------------------------------------*/
202 |
203 | /*--------------------------------------------------------------
204 | # VERTICAL MENU
205 | --------------------------------------------------------------*/
206 |
207 | .satus-modal--vertical-menu .satus-modal__surface {
208 | position: absolute;
209 | top: 8px;
210 | right: 8px;
211 | left: auto;
212 | min-width: 200px;
213 | max-width: 200px;
214 | margin: 0;
215 | padding: 8px 0;
216 | transform-origin: right top;
217 | }
218 |
219 | .satus-modal--vertical-menu .satus-modal__surface>.satus-button,
220 | .satus-modal--vertical-menu .satus-modal__surface>.satus-switch,
221 | .satus-modal--vertical-menu .satus-modal__surface>.satus-select {
222 | height: 36px;
223 | padding: 0 16px;
224 | }
225 |
226 | .satus-modal--vertical-menu .satus-modal__surface>.satus-tabs {
227 | padding: 0 12px;
228 | }
229 |
230 | .satus-modal--vertical-menu .satus-modal__surface>.satus-span {
231 | font-size: 13px;
232 | font-weight: 500;
233 | margin: 6px 0;
234 | padding: 0 12px;
235 | }
236 |
237 | .satus-modal--vertical-menu .satus-button svg {
238 | width: 20px;
239 | height: 18px;
240 | margin: 0 14px 0 0;
241 | opacity: .75;
242 | flex: 0 0 20px;
243 | }
244 |
245 | .satus-modal--vertical-menu .satus-button .satus-span {
246 | overflow: hidden;
247 | white-space: nowrap;
248 | text-overflow: ellipsis;
249 | }
250 | /*--------------------------------------------------------------
251 | >>> GRID
252 | --------------------------------------------------------------*/
253 |
254 | .satus-grid {
255 | display: flex;
256 | align-items: stretch;
257 | height: 100%;
258 | padding: 8px;
259 | }
260 | /*--------------------------------------------------------------
261 | >>> TEXT FIELD
262 | ----------------------------------------------------------------
263 | # Parts
264 | # Container
265 | # Input
266 | #
267 | # Syntax highlighting
268 | # Regular expression
269 | --------------------------------------------------------------*/
270 |
271 | .satus-text-field {
272 | display: flex;
273 |
274 | min-width: 240px;
275 | height: 36px;
276 |
277 | color: var(--satus-text-field-color, inherit);
278 | border: 1px solid var(--satus-text-field-border);
279 | border-radius: 4px;
280 | background: var(--satus-text-field-background);
281 |
282 | align-items: center;
283 | justify-content: space-between;
284 | }
285 |
286 | .satus-text-field__container {
287 | position: relative;
288 |
289 | overflow: hidden;
290 |
291 | height: 100%;
292 |
293 | flex: 1;
294 | }
295 |
296 | .satus-text-field__input {
297 | font: inherit;
298 |
299 | position: absolute;
300 | z-index: 9;
301 | top: 0;
302 | left: 0;
303 |
304 | width: 100%;
305 | min-width: 0;
306 | max-width: none;
307 | height: 100%;
308 | min-height: 0;
309 | max-height: none;
310 | margin: 0;
311 | padding: 0 12px;
312 |
313 | opacity: 0;
314 | color: inherit;
315 | border: none;
316 | border-radius: 4px;
317 | outline: none;
318 |
319 | appearance: none;
320 | }
321 |
322 | .satus-text-field__pre {
323 | font: inherit;
324 |
325 | position: absolute;
326 | top: 0;
327 | left: 0;
328 |
329 | display: flex;
330 |
331 | height: 100%;
332 | margin: 0 12px;
333 |
334 | align-items: center;
335 | }
336 |
337 | .satus-text-field__hidden-value {
338 | font: inherit;
339 |
340 | position: absolute;
341 |
342 | pointer-events: none;
343 |
344 | opacity: 0;
345 | }
346 |
347 | .satus-text-field__selection {
348 | position: absolute;
349 | top: 0;
350 | left: 0;
351 |
352 | display: none;
353 |
354 | width: 0;
355 | height: 22px;
356 | margin: 6px 12px;
357 |
358 | border: 1px solid var(--satus-text-field-selection);
359 | border-radius: 3px;
360 | background: var(--satus-text-field-selection);
361 | }
362 |
363 | .satus-text-field__cursor {
364 | position: absolute;
365 | top: 0;
366 | left: 0;
367 |
368 | display: none;
369 |
370 | width: 2px;
371 | height: 24px;
372 | margin: 5px 11px;
373 |
374 | animation: blink 1s step-end 8;
375 |
376 | background: var(--satus-text-field-cursor);
377 | }
378 |
379 | .satus-text-field__input:focus+*+*+*+.satus-text-field__cursor,
380 | .satus-text-field__input:focus+*+*+.satus-text-field__selection:not([disabled]) {
381 | display: block;
382 | }
383 |
384 | @keyframes blink {
385 |
386 | from,
387 | to {
388 | opacity: 1;
389 | }
390 |
391 | 50% {
392 | opacity: 0;
393 | }
394 | }
395 |
396 |
397 | /*--------------------------------------------------------------
398 | # SYNTAX HIGHLIGHTING
399 | --------------------------------------------------------------*/
400 |
401 | /*--------------------------------------------------------------
402 | # REGULAR EXPRESSION
403 | --------------------------------------------------------------*/
404 |
405 | .satus-text-field__pre>.group {
406 | color: #47ff47;
407 | background-color: rgb(71, 255, 71, .16);
408 | }
409 |
410 | .satus-text-field__pre>.character-class {
411 | color: #ffc247;
412 | background-color: rgb(255, 170, 0, .16);
413 | }
414 |
415 | .satus-text-field__pre>.quantifier {
416 | color: #47c2ff;
417 | background-color: rgb(71, 194, 255, .16);
418 | }
419 |
420 | .satus-text-field__pre>.anchor {
421 | color: #47c2ff;
422 | background-color: rgb(71, 194, 255, .16);
423 | }
424 |
425 | .satus-text-field__pre>.metasequence {
426 | color: #47ff47;
427 | background-color: rgb(71, 255, 71, .16);
428 | }
429 |
430 | .satus-text-field__pre>.text {
431 | color: #c4c4d4;
432 | background-color: rgb(196, 196, 212, .16);
433 | }
434 | /*--------------------------------------------------------------
435 | >>> SELECT
436 | --------------------------------------------------------------*/
437 |
438 | .satus-select {
439 | position: relative;
440 | display: flex;
441 | cursor: pointer;
442 | align-items: center;
443 | justify-content: space-between;
444 | }
445 |
446 | .satus-select:hover {
447 | background-color: var(--satus-hover);
448 | }
449 |
450 | .satus-select>span:nth-child(2) {
451 | display: flex;
452 | align-items: center;
453 | }
454 |
455 | .satus-select>span:nth-child(2)>svg {
456 | width: 20px;
457 | height: 18px;
458 | margin: 0 14px 0 0;
459 | opacity: .75;
460 | }
461 |
462 | .satus-select>span:nth-child(3) {
463 | margin-left: 16px;
464 | text-align: right;
465 | opacity: .75;
466 | }
467 |
468 | .satus-select select {
469 | font: inherit;
470 | position: absolute;
471 | top: 0;
472 | left: 0;
473 | width: 100%;
474 | height: 100%;
475 | margin: 0;
476 | padding: inherit;
477 | opacity: 0;
478 | border: none;
479 | outline: none;
480 | appearance: none;
481 | z-index: 1;
482 | cursor: inherit;
483 | color: inherit;
484 | }
485 |
486 | .satus-select option {
487 | color: var(--satus-select-text);
488 | background: var(--satus-select-background);
489 | }
490 | /*--------------------------------------------------------------
491 | >>> SECTION
492 | ----------------------------------------------------------------
493 | # Card
494 | --------------------------------------------------------------*/
495 |
496 | .satus-section {
497 | display: flex;
498 | box-sizing: border-box;
499 | flex-wrap: wrap;
500 | }
501 |
502 |
503 | /*--------------------------------------------------------------
504 | # CARD
505 | --------------------------------------------------------------*/
506 |
507 | .satus-section--card {
508 | flex-direction: column;
509 | box-sizing: border-box;
510 | width: 100%;
511 | max-width: 900px;
512 | margin: 8px auto;
513 | padding: 8px 0;
514 | border: 1px solid var(--satus-section-border);
515 | border-radius: 8px;
516 | background: var(--satus-section-background);
517 | justify-content: stretch;
518 | }
519 |
520 | .satus-section--label {
521 | display: block;
522 | width: 100%;
523 | max-width: 900px;
524 | margin: 8px auto;
525 | }
526 |
527 | .satus-section--card>.satus-button,
528 | .satus-section--card>.satus-color-picker,
529 | .satus-section--card>.satus-radio,
530 | .satus-section--card>.satus-select,
531 | .satus-section--card>.satus-shortcut,
532 | .satus-section--card>.satus-slider,
533 | .satus-section--card>.satus-switch,
534 | .satus-section--card>.satus-span {
535 | display: flex;
536 | box-sizing: border-box;
537 | width: 100%;
538 | min-height: 48px;
539 | padding: 8px 16px;
540 | text-align: left;
541 | justify-content: space-between;
542 | align-items: center;
543 | }
544 |
545 | .satus-section--card>.satus-button:hover,
546 | .satus-section--card>.satus-color-picker:hover,
547 | .satus-section--card>.satus-radio:hover,
548 | .satus-section--card>.satus-select:hover,
549 | .satus-section--card>.satus-shortcut:hover,
550 | .satus-section--card>.satus-slider:hover,
551 | .satus-section--card>.satus-switch:hover {
552 | background-color: rgba(var(--satus-light), .06);
553 | }
554 |
555 | .satus-section--card>.satus-button {
556 | justify-content: flex-start;
557 | }
558 |
559 | .satus-section--card>.satus-button>svg {
560 | width: 20px;
561 | margin: 2px 16px 0 0;
562 | color: var(--satus-primary);
563 | }
564 |
565 | .satus-section--card>.satus-span {
566 | display: flex;
567 | align-items: center;
568 | }
569 |
570 |
571 | /*--------------------------------------------------------------
572 | # ALIGN
573 | --------------------------------------------------------------*/
574 |
575 | .satus-section--align-start {
576 | display: flex;
577 | align-items: center;
578 | justify-content: flex-start;
579 | }
580 |
581 | .satus-section--align-start>*:not(:last-child) {
582 | margin-right: 8px;
583 | }
584 |
585 | .satus-section--align-end {
586 | display: flex;
587 | align-items: center;
588 | justify-content: flex-end;
589 | }
590 |
591 | .satus-section--align-end>*:not(:first-child) {
592 | margin-left: 8px;
593 | }
594 | /*--------------------------------------------------------------
595 | >>> BASE
596 | --------------------------------------------------------------*/
597 |
598 | .satus-base {
599 | display: flex;
600 | flex-direction: column;
601 | width: 100%;
602 | height: 100%;
603 | color: var(--satus-base-text);
604 | background: var(--satus-base-background);
605 | }
606 | /*--------------------------------------------------------------
607 | >>> MAIN
608 | --------------------------------------------------------------*/
609 |
610 | .satus-main {
611 | display: flex;
612 | background: var(--satus-main-background);
613 | flex: 1
614 | }
615 | /*--------------------------------------------------------------
616 | >>> SIDEBAR
617 | --------------------------------------------------------------*/
618 |
619 | .satus-sidebar {
620 | z-index: 1;
621 | display: flex;
622 | flex-direction: column;
623 | width: 56px;
624 | padding: 12px 0;
625 | color: var(--satus-sidebar-text);
626 | background: var(--satus-sidebar-background);
627 | box-shadow: 1px 0 0 var(--satus-sidebar-shadow)
628 | }
629 | /*--------------------------------------------------------------
630 | >>> LAYERS
631 | --------------------------------------------------------------*/
632 |
633 | .satus-layers {
634 | position: relative;
635 | overflow: hidden;
636 | flex: 1;
637 | }
638 |
639 | .satus-layers__layer {
640 | position: absolute;
641 | top: 0;
642 | left: 0;
643 | overflow: auto;
644 | width: 100%;
645 | height: 100%;
646 | padding: 0 12px;
647 | color: var(--satus-layers-text);
648 | background: var(--satus-layers-background);
649 | }
650 | /*--------------------------------------------------------------
651 | >>> LIST:
652 | --------------------------------------------------------------*/
653 |
654 | .satus-list {
655 | list-style: none;
656 | margin: 0;
657 | }
658 |
659 | .satus-list__item {
660 | display: flex;
661 | align-items: center;
662 | justify-content: space-between;
663 | min-height: 48px;
664 | padding: 0 16px;
665 | }
666 |
667 | .satus-list__item>*:not(:first-child) {
668 | margin-left: 8px;
669 | }
670 |
671 | .satus-list__item>*:last-child {
672 | text-align: right;
673 | }
674 | /*--------------------------------------------------------------
675 | >>> COLOR PICKER:
676 | ----------------------------------------------------------------
677 | # Button
678 | # Modal
679 | --------------------------------------------------------------*/
680 |
681 |
682 | /*--------------------------------------------------------------
683 | # BUTTON
684 | --------------------------------------------------------------*/
685 |
686 | .satus-color-picker {
687 | font-size: inherit;
688 | position: relative;
689 | display: flex;
690 | box-sizing: border-box;
691 | margin: 0;
692 | cursor: pointer;
693 | color: inherit;
694 | border: none;
695 | outline: none;
696 | background-color: var(--satus-theme-button);
697 | justify-content: space-between;
698 | -webkit-tap-highlight-color: transparent;
699 | align-items: center;
700 | -webkit-appearance: none;
701 | }
702 |
703 | .satus-color-picker__value {
704 | width: 22px;
705 | height: 22px;
706 | border: 2px solid rgba(0, 0, 0, .16);
707 | border-radius: 50%;
708 | }
709 |
710 |
711 | /*--------------------------------------------------------------
712 | # MODAL
713 | --------------------------------------------------------------*/
714 |
715 | .satus-modal--color-picker {
716 | position: relative;
717 | }
718 |
719 | .satus-modal--color-picker .satus-modal__surface {
720 | padding: 8px;
721 | }
722 |
723 | .satus-color-picker__palette {
724 | position: relative;
725 | overflow: hidden;
726 | width: 100%;
727 | height: 256px;
728 | background-color: #f00;
729 | border-radius: 5px;
730 | }
731 |
732 | .satus-color-picker__palette:before {
733 | position: absolute;
734 | top: 0;
735 | left: 0;
736 | width: 100%;
737 | height: 100%;
738 | content: '';
739 | background-image: linear-gradient(0deg, black, transparent), linear-gradient(90deg, white, transparent);
740 | }
741 |
742 | .satus-color-picker__cursor {
743 | position: absolute;
744 | width: 5px;
745 | height: 5px;
746 | transform: translate(-50%, -50%);
747 | pointer-events: none;
748 | border: 1px solid #fff;
749 | border-radius: 50%;
750 | box-shadow: 0 0 0 1px #000;
751 | }
752 |
753 | .satus-modal--color-picker .satus-modal__surface .satus-section--color {
754 | margin: 8px 16px 0;
755 | align-items: center;
756 | }
757 |
758 | .satus-color-picker__color {
759 | width: 32px;
760 | height: 32px;
761 | margin: 0 16px 0 0;
762 | border: 2px solid rgba(0, 0, 0, .16);
763 | border-radius: 50%;
764 | background: #f00;
765 | }
766 |
767 | .satus-slider.satus-color-picker__hue {
768 | padding: 0;
769 | flex: 1;
770 | }
771 |
772 | .satus-color-picker__hue .satus-slider__track {
773 | height: 16px;
774 | border-radius: 4px;
775 | background-image: linear-gradient(90deg, #f00, #ff2a00, #f50, #ff7f00, #fa0, #ffd400, #ff0, #d4ff00, #af0, #80ff00, #5f0, #2bff00, #0f0, #00ff2b, #0f5, #00ff80, #0fa, #00ffd5, #0ff, #00d4ff, #0af, #007fff, #05f, #002bff, #00f, #2a00ff, #50f, #7f00ff, #a0f, #d400ff, #f0f, #ff00d4, #f0a, #ff0080, #f05, #ff002b, #f00);
776 | }
777 |
778 | .satus-color-picker__hue .satus-slider__handle {
779 | width: 16px;
780 | height: 16px;
781 | background: #fff;
782 | box-shadow: 0 0 4px rgb(0, 0, 0, .64);
783 | }
784 |
785 | .satus-color-picker__hue::before,
786 | .satus-color-picker__hue .satus-slider__track-fill,
787 | .satus-color-picker__hue .satus-slider__handle:focus::after {
788 | display: none;
789 | }
790 | /*--------------------------------------------------------------
791 | >>> BUTTON
792 | ----------------------------------------------------------------
793 | # Base
794 | # Basic
795 | # Icon
796 | --------------------------------------------------------------*/
797 |
798 |
799 | /*--------------------------------------------------------------
800 | # BASE
801 | --------------------------------------------------------------*/
802 |
803 | .satus-button {
804 | font: inherit;
805 |
806 | position: relative;
807 |
808 | display: inline-flex;
809 | overflow: hidden;
810 |
811 | height: 36px;
812 | padding: 8px;
813 |
814 | color: inherit;
815 | border: none;
816 | outline: none;
817 | background: transparent;
818 |
819 | appearance: none;
820 | align-items: center;
821 | }
822 |
823 | .satus-button:hover {
824 | cursor: pointer;
825 | }
826 |
827 | .satus-button svg {
828 | width: 100%;
829 | max-width: 24px;
830 | height: 100%;
831 | max-height: 24px;
832 | }
833 |
834 |
835 | /*--------------------------------------------------------------
836 | # BASIC
837 | --------------------------------------------------------------*/
838 |
839 | /*--------------------------------------------------------------
840 | # ICON
841 | --------------------------------------------------------------*/
842 |
843 | .satus-button--icon {
844 | width: 40px;
845 | height: 40px;
846 |
847 | transition: background-color .3s cubic-bezier(.25, .8, .5, 1);
848 |
849 | border-radius: 50%;
850 | }
851 |
852 | .satus-button--icon:hover {
853 | background-color: rgba(var(--satus-light), .08);
854 | }
855 |
856 | .satus-button--icon:focus {
857 | background-color: rgba(var(--satus-light), .24);
858 | }
859 |
860 | .satus-button--icon svg {
861 | width: 24px;
862 | height: 24px;
863 | }
864 | /*--------------------------------------------------------------
865 | >>> HEADER
866 | --------------------------------------------------------------*/
867 |
868 | .satus-header {
869 | z-index: 1;
870 | display: flex;
871 | height: 56px;
872 | padding: 0 12px;
873 | color: var(--satus-header-text);
874 | background: var(--satus-header-background);
875 | box-shadow: 0 1px 0 var(--satus-header-shadow);
876 | justify-content: space-between;
877 | align-items: center;
878 | }
879 |
880 | .satus-span--title {
881 | font-size: 16px;
882 | }
883 | /*--------------------------------------------------------------
884 | >>> RADIO
885 | --------------------------------------------------------------*/
886 | /*--------------------------------------------------------------
887 | >>> SLIDER
888 | --------------------------------------------------------------*/
889 |
890 | .satus-slider__track {
891 | height: 32px;
892 | }
893 |
894 | .satus-slider__track__range {
895 | margin: 0;
896 | padding: 0;
897 | width: 100%;
898 | height: 100%;
899 | }
900 |
901 | /*.satus-slider {
902 | display: block;
903 | background: #fff;
904 | }
905 |
906 | .satus-slider__label {
907 | display: flex;
908 | margin: 12px 0 0;
909 | justify-content: space-between;
910 | align-items: center;
911 | }
912 |
913 | .satus-slider .satus-input[type=number] {
914 | font: inherit;
915 | width: 64px;
916 | margin: 0;
917 | padding: 0;
918 | text-align: right;
919 | color: inherit;
920 | background: transparent;
921 | }
922 |
923 | .satus-slider__track {
924 | position: relative;
925 | display: block;
926 | min-width: 128px;
927 | height: 40px;
928 | margin: 0 2px;
929 | }
930 |
931 | .satus-slider__track::before {
932 | position: absolute;
933 | top: 50%;
934 | left: 0;
935 | display: block;
936 | width: 100%;
937 | height: 2px;
938 | content: '';
939 | transform: translateY(-50%);
940 | opacity: .24;
941 | background: var(--satus-primary);
942 | }
943 |
944 | .satus-slider__slice {
945 | position: absolute;
946 | top: 50%;
947 | left: 0;
948 | height: 2px;
949 | transform: translateY(-50%);
950 | background: var(--satus-primary);
951 | }
952 |
953 | .satus-slider__slice::before {
954 | position: absolute;
955 | top: 50%;
956 | right: 0;
957 | display: block;
958 | width: 22px;
959 | height: 22px;
960 | content: '';
961 | transition: width 200ms, height 200ms, opacity 200ms;
962 | transform: translate(50%, -50%);
963 | opacity: 0;
964 | border-radius: 50%;
965 | background: var(--satus-primary);
966 | }
967 |
968 | .satus-slider__track:focus .satus-slider__slice::before {
969 | width: 32px;
970 | height: 32px;
971 | opacity: .16;
972 | }
973 |
974 | .satus-slider__slice::after {
975 | position: absolute;
976 | top: 50%;
977 | right: 0;
978 | display: block;
979 | width: 10px;
980 | height: 10px;
981 | content: '';
982 | transition: width 200ms, height 200ms;
983 | transform: translate(50%, -50%);
984 | border-radius: 50%;
985 | background: var(--satus-primary);
986 | }
987 |
988 | .satus-slider__track:focus .satus-slider__slice::after {
989 | width: 12px;
990 | height: 12px;
991 | }*/
992 | /*--------------------------------------------------------------
993 | >>> SHORTCUT:
994 | ----------------------------------------------------------------
995 | #
996 | --------------------------------------------------------------*/
997 |
998 | .satus-shortcut__value {
999 | font-size: 11px;
1000 |
1001 | display: flex;
1002 |
1003 | margin-left: 16px;
1004 |
1005 | text-transform: uppercase;
1006 |
1007 | align-items: center;
1008 | flex: 1;
1009 | justify-content: flex-end;
1010 | }
1011 |
1012 | .satus-shortcut__actions {
1013 | display: flex;
1014 |
1015 | justify-content: flex-end;
1016 | }
1017 |
1018 | .satus-shortcut__actions .satus-button {
1019 | height: 32px;
1020 | margin: 8px 4px 0;
1021 |
1022 | border-radius: 8px;
1023 | background: rgba(0, 0, 0, .15);
1024 | }
1025 |
1026 | .satus-shortcut__actions .satus-button:hover {
1027 | background: rgba(0, 0, 0, .25);
1028 | }
1029 |
1030 | .satus-shortcut__primary {
1031 | display: flex;
1032 |
1033 | box-sizing: border-box;
1034 | width: 100%;
1035 | height: 68px;
1036 | padding: 16px;
1037 |
1038 | background: rgba(0, 0, 0, .16);
1039 |
1040 | align-items: center;
1041 | }
1042 |
1043 | .satus-shortcut__key {
1044 | display: flex;
1045 |
1046 | box-sizing: border-box;
1047 | min-width: 32px;
1048 | height: 32px;
1049 | padding: 4px 8px;
1050 |
1051 | border-radius: 4px;
1052 | background: #fff;
1053 | box-shadow: 0 1px 3px rgba(0, 0, 0, .15), inset 0 -3px 0 rgba(0, 0, 0, .1);
1054 |
1055 | align-items: center;
1056 | justify-content: center;
1057 | }
1058 |
1059 | .satus-shortcut__value>.satus-shortcut__key {
1060 | font-size: 14px;
1061 |
1062 | min-width: 24px;
1063 | height: 24px;
1064 | }
1065 |
1066 | .satus-shortcut__plus {
1067 | position: relative;
1068 |
1069 | width: 12px;
1070 | height: 12px;
1071 | margin: 8px;
1072 | }
1073 |
1074 | .satus-shortcut__plus::before {
1075 | position: absolute;
1076 | top: 0;
1077 | left: 5px;
1078 |
1079 | width: 2px;
1080 | height: 12px;
1081 |
1082 | content: '';
1083 |
1084 | background-color: #aaa;
1085 | }
1086 |
1087 | .satus-shortcut__plus::after {
1088 | position: absolute;
1089 | top: 5px;
1090 | left: 0;
1091 |
1092 | width: 12px;
1093 | height: 2px;
1094 |
1095 | content: '';
1096 |
1097 | background-color: #aaa;
1098 | }
1099 |
1100 | .satus-shortcut__mouse {
1101 | position: relative;
1102 |
1103 | display: flex;
1104 |
1105 | width: 28px;
1106 | height: 36px;
1107 |
1108 | border-radius: 50%;
1109 | border-top-left-radius: 12px;
1110 | border-top-right-radius: 12px;
1111 | background: #fff;
1112 | box-shadow: 0 1px 3px rgba(0, 0, 0, .15), inset 0 -3px 0 rgba(0, 0, 0, .1);
1113 | }
1114 |
1115 | .satus-shortcut__value>.satus-shortcut__mouse {
1116 | width: 22px;
1117 | height: 28px;
1118 | }
1119 |
1120 | .satus-shortcut__mouse>div {
1121 | position: absolute;
1122 | top: 0;
1123 | left: calc(50% - 1px);
1124 |
1125 | width: 2px;
1126 | height: 11px;
1127 |
1128 | border-radius: 2px;
1129 | background: #ccc;
1130 | }
1131 |
1132 | .satus-shortcut__mouse::before {
1133 | position: absolute;
1134 | top: -16%;
1135 | right: 14%;
1136 |
1137 | width: 2px;
1138 | height: 60%;
1139 |
1140 | content: '';
1141 |
1142 | background: #f96754;
1143 | }
1144 |
1145 | .satus-shortcut__mouse.false::before {
1146 | top: -6%;
1147 | }
1148 |
1149 | .satus-shortcut__mouse.false::after {
1150 | position: absolute;
1151 | top: -20%;
1152 | right: calc(14% - 4px);
1153 |
1154 | width: 0;
1155 | height: 0;
1156 |
1157 | content: '';
1158 |
1159 | border-right: 5px solid transparent;
1160 | border-bottom: 8px solid #f96754;
1161 | border-left: 5px solid transparent;
1162 | }
1163 |
1164 | .satus-shortcut__mouse.true::after {
1165 | position: absolute;
1166 | top: 40%;
1167 | right: calc(14% - 4px);
1168 |
1169 | width: 0;
1170 | height: 0;
1171 |
1172 | content: '';
1173 |
1174 | border-top: 8px solid #f96754;
1175 | border-right: 5px solid transparent;
1176 | border-left: 5px solid transparent;
1177 | }
1178 |
1179 | .satus-shortcut__mouse.click::before {
1180 | position: absolute;
1181 | top: 0;
1182 | left: -1px;
1183 |
1184 | width: 10px;
1185 | height: 10px;
1186 |
1187 | content: '';
1188 |
1189 | border-radius: 50%;
1190 | background: #f96754;
1191 | }
1192 |
1193 | .satus-shortcut__mouse.middle::before {
1194 | position: absolute;
1195 | z-index: 1;
1196 | top: 0;
1197 | left: 50%;
1198 |
1199 | width: 10px;
1200 | height: 10px;
1201 |
1202 | content: '';
1203 | transform: translateX(-50%);
1204 |
1205 | border-radius: 50%;
1206 | background: #f96754;
1207 | }
1208 |
1209 | .satus-shortcut__mouse.context::before {
1210 | position: absolute;
1211 | top: 0;
1212 | left: 15px;
1213 |
1214 | width: 10px;
1215 | height: 10px;
1216 |
1217 | content: '';
1218 |
1219 | border-radius: 50%;
1220 | background: #f96754;
1221 | }
1222 |
1223 | .satus-section_shortcut {
1224 | width: 100%;
1225 | margin: 8px 0 0;
1226 |
1227 | justify-content: flex-end;
1228 | }
1229 |
1230 | .satus-button_shortcut {
1231 | font-weight: 500;
1232 |
1233 | overflow: hidden;
1234 |
1235 | height: 28px;
1236 | min-height: 28px;
1237 | margin-right: 2px;
1238 | padding: 4px 8px;
1239 |
1240 | text-transform: uppercase;
1241 |
1242 | color: #f96754;
1243 | border-radius: 4px;
1244 | }
1245 | /*--------------------------------------------------------------
1246 | >>> CHECKBOX
1247 | --------------------------------------------------------------*/
1248 |
1249 | .satus-checkbox {
1250 | position: relative;
1251 | font: inherit;
1252 | display: flex;
1253 | color: inherit;
1254 | border: none;
1255 | background: transparent;
1256 | appearance: none;
1257 | align-items: center;
1258 | justify-content: flex-start;
1259 | }
1260 |
1261 | .satus-checkbox:hover {
1262 | cursor: pointer;
1263 | background-color: var(--satus-hover);
1264 | }
1265 |
1266 | .satus-checkbox:focus {
1267 | outline: none;
1268 | }
1269 |
1270 | .satus-checkbox__content {
1271 | display: block;
1272 | white-space: nowrap;
1273 | text-overflow: ellipsis;
1274 | overflow: hidden;
1275 | }
1276 |
1277 | .satus-checkbox::before {
1278 | display: flex;
1279 | min-width: 16px;
1280 | width: 16px;
1281 | height: 16px;
1282 | margin: 0 12px 0 0;
1283 | content: '';
1284 | border: 1px solid var(--satus-checkbox--border);
1285 | border-radius: 6px;
1286 | background: var(--satus-checkbox--background);
1287 | align-items: center;
1288 | justify-content: center;
1289 | }
1290 |
1291 | .satus-checkbox[data-value=true]::before {
1292 | background: var(--satus-primary);
1293 | }
1294 |
1295 | .satus-checkbox[data-value=true]::after {
1296 | position: absolute;
1297 | top: 20px;
1298 | left: 20px;
1299 | width: 8px;
1300 | height: 4px;
1301 | content: '';
1302 | transform: rotate(-45deg);
1303 | border: 2px solid var(--satus-checkbox--mark);
1304 | border-top: none;
1305 | border-right: none;
1306 | }
1307 | /*--------------------------------------------------------------
1308 | >>> SWITCH
1309 | ----------------------------------------------------------------
1310 | # Container
1311 | # Track
1312 | # Thumb
1313 | --------------------------------------------------------------*/
1314 |
1315 |
1316 | /*--------------------------------------------------------------
1317 | # CONTAINER
1318 | --------------------------------------------------------------*/
1319 |
1320 | .satus-switch {
1321 | font: inherit;
1322 | display: flex;
1323 | transition: background-color 75ms;
1324 | color: inherit;
1325 | border: none;
1326 | outline: none;
1327 | background-color: transparent;
1328 | justify-content: space-between;
1329 | align-items: center;
1330 | }
1331 |
1332 | .satus-switch:hover {
1333 | cursor: pointer;
1334 | }
1335 |
1336 | .satus-switch__content {
1337 | display: flex;
1338 | align-items: center;
1339 | }
1340 |
1341 | .satus-switch__content>svg {
1342 | width: 20px;
1343 | height: 18px;
1344 | margin: 0 14px 0 0;
1345 | opacity: .75;
1346 | }
1347 |
1348 |
1349 | /*--------------------------------------------------------------
1350 | # TRACK
1351 | --------------------------------------------------------------*/
1352 |
1353 | .satus-switch>i {
1354 | width: 32px;
1355 | height: 18px;
1356 | transition: background-color 150ms;
1357 | border-radius: 18px;
1358 | background-color: var(--satus-switch-track);
1359 | flex: 0 0 32px;
1360 | }
1361 |
1362 | .satus-section--card .satus-switch>i {
1363 | margin-left: 16px;
1364 | }
1365 |
1366 | .satus-switch[data-value='true']>i {
1367 | background-color: var(--satus-primary);
1368 | }
1369 |
1370 |
1371 | /*--------------------------------------------------------------
1372 | # THUMB
1373 | --------------------------------------------------------------*/
1374 |
1375 | .satus-switch>i::before {
1376 | display: block;
1377 | width: 14px;
1378 | height: 14px;
1379 | margin: 2px;
1380 | content: '';
1381 | transition: transform 150ms cubic-bezier(.4, 0, .2, 1);
1382 | border-radius: 50%;
1383 | background-color: var(--satus-switch-thumb);
1384 | will-change: transform;
1385 | }
1386 |
1387 | .satus-switch[data-value='true']>i::before {
1388 | transform: translateX(14px);
1389 | }
1390 |
--------------------------------------------------------------------------------
/assets/satus/satus.js:
--------------------------------------------------------------------------------
1 | /*--------------------------------------------------------------
2 | >>> CORE
3 | ----------------------------------------------------------------
4 | # Global variable
5 | # Append
6 | # Attr
7 | # Camelize
8 | # Class
9 | # Create element
10 | # CSS
11 | # Empty
12 | # Events
13 | # Get property
14 | # Is
15 | # On
16 | # Render
17 | # Storage
18 | # Clear
19 | # Get
20 | # Import
21 | # Set
22 | # Remove
23 | # Localization
24 | # Log
25 | # Text
26 | --------------------------------------------------------------*/
27 |
28 | /*--------------------------------------------------------------
29 | # GLOBAL VARIABLE
30 | --------------------------------------------------------------*/
31 |
32 | var satus = {
33 | components: {},
34 | events: {
35 | data: {}
36 | },
37 | locale: {
38 | data: {}
39 | },
40 | storage: {
41 | data: {},
42 | type: 'extension'
43 | }
44 | };
45 |
46 |
47 | /*--------------------------------------------------------------
48 | # APPEND
49 | --------------------------------------------------------------*/
50 |
51 | satus.append = function (child, parent) {
52 | (parent || document.body).appendChild(child);
53 | };
54 |
55 |
56 | /*--------------------------------------------------------------
57 | # ATTR
58 | --------------------------------------------------------------*/
59 |
60 | satus.attr = function (element, attributes) {
61 | if (attributes) {
62 | for (var name in attributes) {
63 | var value = attributes[name];
64 |
65 | if (typeof value === 'function') {
66 | value = value();
67 | }
68 |
69 | if (element.namespaceURI) {
70 | if (value === false) {
71 | element.removeAttributeNS(null, name);
72 | } else {
73 | element.setAttributeNS(null, name, value);
74 | }
75 | } else {
76 | if (value === false) {
77 | element.removeAttribute(name);
78 | } else {
79 | element.setAttribute(name, value);
80 | }
81 | }
82 | }
83 | }
84 | };
85 |
86 |
87 | /*--------------------------------------------------------------
88 | # CAMELIZE
89 | --------------------------------------------------------------*/
90 |
91 | satus.camelize = function (string) {
92 | var result = '';
93 |
94 | for (var i = 0, l = string.length; i < l; i++) {
95 | var character = string[i];
96 |
97 | if (character === '-') {
98 | i++;
99 |
100 | result += string[i].toUpperCase();
101 | } else {
102 | result += character;
103 | }
104 | }
105 |
106 | return result;
107 | };
108 |
109 |
110 | /*--------------------------------------------------------------
111 | # CLASS
112 | --------------------------------------------------------------*/
113 |
114 | satus.class = function (element, className) {
115 | if (className) {
116 | element.classList.add(className);
117 | }
118 | };
119 |
120 |
121 | /*--------------------------------------------------------------
122 | # CREATE ELEMENT
123 | --------------------------------------------------------------*/
124 |
125 | satus.createElement = function (tagName, componentName, namespaceURI) {
126 | var camelizedTagName = this.camelize(tagName),
127 | className = 'satus-' + (componentName || tagName),
128 | element,
129 | match = className.match(/__[^__]+/g);
130 |
131 | if (!namespaceURI) {
132 | if (tagName === 'svg') {
133 | namespaceURI = 'http://www.w3.org/2000/svg';
134 | }
135 | }
136 |
137 | if (namespaceURI) {
138 | element = document.createElementNS(namespaceURI, tagName);
139 | } else if (this.components[camelizedTagName]) {
140 | element = document.createElement('div');
141 | } else {
142 | element = document.createElement(tagName);
143 | }
144 |
145 | if (match && match.length > 1) {
146 | className = className.slice(0, className.indexOf('__')) + match[match.length - 1];
147 | }
148 |
149 | element.componentName = componentName;
150 | element.className = className;
151 |
152 | element.createChildElement = function (tagName, componentName, namespaceURI) {
153 | var element = satus.createElement(tagName, this.componentName + '__' + (componentName || tagName), namespaceURI);
154 |
155 | this.appendChild(element);
156 |
157 | return element;
158 | };
159 |
160 | return element;
161 | };
162 |
163 |
164 | /*--------------------------------------------------------------
165 | # CSS
166 | --------------------------------------------------------------*/
167 |
168 | satus.css = function (element, property) {
169 | return window.getComputedStyle(element).getPropertyValue(property);
170 | };
171 |
172 |
173 | /*--------------------------------------------------------------
174 | # DATA
175 | --------------------------------------------------------------*/
176 |
177 | satus.data = function (element, data) {
178 | if (data) {
179 | for (var key in data) {
180 | element.dataset[key] = data[key];
181 | }
182 | }
183 | };
184 |
185 |
186 | /*--------------------------------------------------------------
187 | # EMPTY
188 | --------------------------------------------------------------*/
189 |
190 | satus.empty = function (element, exclude = []) {
191 | for (var i = element.childNodes.length - 1; i > -1; i--) {
192 | var child = element.childNodes[i];
193 |
194 | if (exclude.indexOf(child) === -1) {
195 | child.remove();
196 | }
197 | }
198 | };
199 |
200 |
201 | /*--------------------------------------------------------------
202 | # EVENTS
203 | --------------------------------------------------------------*/
204 |
205 | /*--------------------------------------------------------------
206 | # ON
207 | --------------------------------------------------------------*/
208 |
209 | satus.events.on = function (type, handler) {
210 | if (!this.data[type]) {
211 | this.data[type] = [];
212 | }
213 |
214 | this.data[type].push(handler);
215 | };
216 |
217 |
218 | /*--------------------------------------------------------------
219 | # TRIGGER
220 | --------------------------------------------------------------*/
221 |
222 | satus.events.trigger = function (type) {
223 | var handlers = this.data[type];
224 |
225 | if (handlers) {
226 | for (var i = 0, l = handlers.length; i < l; i++) {
227 | handlers[i]();
228 | }
229 | }
230 | };
231 |
232 |
233 | /*--------------------------------------------------------------
234 | # FETCH
235 | --------------------------------------------------------------*/
236 |
237 | satus.fetch = function (url, success, error) {
238 | fetch(url).then(function (response) {
239 | if (response.ok) {
240 | response.json().then(success);
241 | } else {
242 | error();
243 | }
244 | }).catch(function () {
245 | error(success);
246 | });
247 | };
248 |
249 |
250 | /*--------------------------------------------------------------
251 | # GET PROPERTY
252 | --------------------------------------------------------------*/
253 |
254 | satus.getProperty = function (object, string) {
255 | var properties = string.split('.');
256 |
257 | for (var i = 0, l = properties.length; i < l; i++) {
258 | var property = properties[i];
259 |
260 | console.log(object);
261 |
262 | if (object = object[property]) {
263 | if (i === l - 1) {
264 | return object;
265 | }
266 | } else {
267 | return false;
268 | }
269 | }
270 | };
271 |
272 |
273 | /*--------------------------------------------------------------
274 | # ISSET
275 | --------------------------------------------------------------*/
276 |
277 | satus.isset = function (variable) {
278 | if (variable === null || variable === undefined) {
279 | return false;
280 | }
281 |
282 | return true;
283 | };
284 |
285 |
286 | /*--------------------------------------------------------------
287 | # IS
288 | --------------------------------------------------------------*/
289 |
290 | satus.isArray = function (array) {
291 | if (Array.isArray(array)) {
292 | return true;
293 | } else {
294 | return false;
295 | }
296 | };
297 |
298 | satus.isElement = function (object) {
299 | return object instanceof Element || object instanceof HTMLDocument;
300 | };
301 |
302 | satus.isNumber = function (number) {
303 | if (typeof number === 'number' && isNaN(number) === false) {
304 | return true;
305 | } else {
306 | return false;
307 | }
308 | };
309 |
310 | satus.isObject = function (object) {
311 | return object instanceof Object;
312 | };
313 |
314 |
315 | /*--------------------------------------------------------------
316 | # ON
317 | --------------------------------------------------------------*/
318 |
319 | satus.on = function (element, listeners) {
320 | if (listeners) {
321 | for (var type in listeners) {
322 | var listener = listeners[type],
323 | listener_type = typeof listener;
324 |
325 | if (type === 'selectionchange') {
326 | element = document;
327 | }
328 |
329 | if (listener_type === 'function') {
330 | element.addEventListener(type, listener);
331 | } else if (listener_type === 'object') {
332 | element.addEventListener(type, function (event) {
333 | var target = this.skeleton.on[event.type],
334 | parent = this.parentNode;
335 |
336 | target.parentSkeleton = this.skeleton;
337 | target.parentElement = this;
338 |
339 | while (parent.componentName !== 'layers' && parent.componentName !== 'base' && parent !== document.body && parent.parentNode) {
340 | parent = parent.parentNode;
341 | }
342 |
343 | if (parent.componentName === 'layers' && target.component !== 'modal') {
344 | parent.open(target);
345 | } else if (this.baseProvider && this.baseProvider.layers.length === 1) {
346 | satus.render(target, this.baseProvider.layers[0]);
347 | } else {
348 | satus.render(target, this.baseProvider);
349 | }
350 | });
351 | } else if (listener_type === 'string') {
352 | element.addEventListener(type, function () {
353 | var match = this.skeleton.on[event.type].match(/(["'`].+["'`]|[^.()]+)/g),
354 | target = this.baseProvider;
355 |
356 | for (var i = 0, l = match.length; i < l; i++) {
357 | var key = match[i];
358 |
359 | if (target.skeleton[key]) {
360 | target = target.skeleton[key];
361 | } else {
362 | if (typeof target[key] === 'function') {
363 | target[key]();
364 | } else {
365 | target = target[key];
366 | }
367 | }
368 |
369 | if (target.rendered) {
370 | target = target.rendered;
371 | }
372 | }
373 | });
374 | }
375 | }
376 | }
377 | };
378 |
379 |
380 | /*--------------------------------------------------------------
381 | # PARENTIFY
382 | --------------------------------------------------------------*/
383 |
384 | satus.parentify = function (parentObject, exclude) {
385 | for (var key in parentObject) {
386 | if (exclude.indexOf(key) === -1) {
387 | var child = parentObject[key];
388 |
389 | child.parentObject = parentObject;
390 |
391 | if (typeof child === 'object' && child.component !== 'shortcut') {
392 | this.parentify(child, exclude);
393 | }
394 | }
395 | }
396 | };
397 |
398 |
399 | /*--------------------------------------------------------------
400 | # PREPEND
401 | --------------------------------------------------------------*/
402 |
403 | satus.prepend = function (child, parent) {
404 | if (this.isElement(child)) {
405 | parent.prepend(child);
406 | } else if (this.isObject(child)) {
407 | this.render(child, parent, undefined, undefined, true);
408 | }
409 | };
410 |
411 |
412 | /*--------------------------------------------------------------
413 | # PROPERTIES
414 | --------------------------------------------------------------*/
415 |
416 | satus.properties = function (element, properties) {
417 | if (properties) {
418 | for (var key in properties) {
419 | var property = properties[key];
420 |
421 | if (['placeholder', 'title'].indexOf(key) !== -1) {
422 | property = satus.locale.get(property);
423 | }
424 |
425 | element[key] = property;
426 | }
427 | }
428 | };
429 |
430 |
431 | /*--------------------------------------------------------------
432 | # RENDER
433 | --------------------------------------------------------------*/
434 |
435 | satus.render = function (skeleton, container, property, childrenOnly, prepend) {
436 | var element;
437 |
438 | if (skeleton.component && childrenOnly !== true) {
439 | var tagName = skeleton.component,
440 | camelizedTagName = this.camelize(tagName),
441 | namespaceURI = skeleton.namespaceURI;
442 |
443 | if (!namespaceURI) {
444 | if (tagName === 'svg') {
445 | namespaceURI = 'http://www.w3.org/2000/svg';
446 | } else if (skeleton.parentSkeleton && skeleton.parentSkeleton.namespaceURI) {
447 | namespaceURI = skeleton.parentSkeleton.namespaceURI;
448 | }
449 |
450 | skeleton.namespaceURI = namespaceURI;
451 | }
452 |
453 | element = this.createElement(tagName, tagName, namespaceURI);
454 |
455 | skeleton.rendered = element;
456 | element.skeleton = skeleton;
457 | element.childrenContainer = element;
458 | element.componentName = tagName;
459 |
460 | if (skeleton.variant) {
461 | element.className += ' satus-' + tagName + '--' + skeleton.variant;
462 | }
463 |
464 | if (container) {
465 | element.baseProvider = container.baseProvider;
466 | }
467 |
468 | this.attr(element, skeleton.attr);
469 | this.style(element, skeleton.style);
470 | this.data(element, skeleton.data);
471 | this.class(element, skeleton.class);
472 | this.properties(element, skeleton.properties);
473 | this.text(element, skeleton.text);
474 | this.on(element, skeleton.on);
475 | this.prepend(skeleton.before, element);
476 |
477 | if (prepend) {
478 | this.prepend(element, container);
479 | } else {
480 | this.append(element, container);
481 | }
482 |
483 | element.storage = (function () {
484 | var parent = element,
485 | key = skeleton.storage || property || false,
486 | value;
487 |
488 | if (skeleton.storage !== false) {
489 | if (key) {
490 | value = satus.storage.get(key);
491 | }
492 |
493 | if (skeleton.hasOwnProperty('value') && value === undefined) {
494 | value = skeleton.value;
495 | }
496 | }
497 |
498 | return Object.defineProperties({}, {
499 | key: {
500 | get: function () {
501 | return key;
502 | },
503 | set: function (string) {
504 | key = string;
505 | }
506 | },
507 | value: {
508 | get: function () {
509 | return value;
510 | },
511 | set: function (val) {
512 | value = val;
513 |
514 | if (skeleton.storage !== false) {
515 | satus.storage.set(key, val);
516 |
517 | parent.dispatchEvent(new CustomEvent('change'));
518 | }
519 | }
520 | }
521 | });
522 | }());
523 |
524 | if (this.components[camelizedTagName]) {
525 | this.components[camelizedTagName](element, skeleton);
526 | }
527 |
528 | element.dispatchEvent(new CustomEvent('render'));
529 |
530 | container = element.childrenContainer || element;
531 | }
532 |
533 | if (!element || element.renderChildren !== false) {
534 | for (var key in skeleton) {
535 | var item = skeleton[key];
536 |
537 | if (key !== 'parentSkeleton' && key !== 'parentElement' && key !== 'parentObject') {
538 | if (item && item.component) {
539 | item.parentSkeleton = skeleton;
540 |
541 | if (element) {
542 | item.parentElement = element;
543 | }
544 |
545 | this.render(item, container, key, undefined, prepend);
546 | }
547 | }
548 | }
549 | }
550 |
551 | return element;
552 | };
553 |
554 |
555 | /*--------------------------------------------------------------
556 | # STORAGE
557 | --------------------------------------------------------------*/
558 |
559 | /*--------------------------------------------------------------
560 | # CLEAR
561 | --------------------------------------------------------------*/
562 |
563 | satus.storage.clear = function (callback) {
564 | this.data = {};
565 |
566 | chrome.storage.local.clear(function () {
567 | satus.events.trigger('storage-clear');
568 |
569 | if (callback) {
570 | callback();
571 | }
572 | });
573 | };
574 |
575 |
576 | /*--------------------------------------------------------------
577 | # GET
578 | --------------------------------------------------------------*/
579 |
580 | satus.storage.get = function (key, callback) {
581 | var target = this.data;
582 |
583 | if (typeof key !== 'string') {
584 | return;
585 | }
586 |
587 | key = key.split('/').filter(function (value) {
588 | return value != '';
589 | });
590 |
591 | for (var i = 0, l = key.length; i < l; i++) {
592 | if (satus.isset(target[key[i]])) {
593 | target = target[key[i]];
594 | } else {
595 | return undefined;
596 | }
597 | }
598 |
599 | if (typeof target === 'function') {
600 | return target();
601 | } else {
602 | return target;
603 | }
604 | };
605 |
606 |
607 | /*--------------------------------------------------------------
608 | # IMPORT
609 | --------------------------------------------------------------*/
610 |
611 | satus.storage.import = function (keys, callback) {
612 | var self = this;
613 |
614 | if (typeof keys === 'function') {
615 | callback = keys;
616 |
617 | keys = undefined;
618 | }
619 |
620 | chrome.storage.local.get(keys, function (items) {
621 | for (var key in items) {
622 | self.data[key] = items[key];
623 | }
624 |
625 | satus.log('STORAGE: data was successfully imported');
626 |
627 | satus.events.trigger('storage-import');
628 |
629 | if (callback) {
630 | callback(items);
631 | }
632 | });
633 | };
634 |
635 |
636 | /*--------------------------------------------------------------
637 | # REMOVE
638 | --------------------------------------------------------------*/
639 |
640 | satus.storage.remove = function (key) {
641 | delete this.data[key];
642 |
643 | chrome.storage.local.remove(key, function () {
644 | satus.events.trigger('storage-remove');
645 | });
646 | };
647 |
648 |
649 | /*--------------------------------------------------------------
650 | # SET
651 | --------------------------------------------------------------*/
652 |
653 | satus.storage.set = function (key, value, callback) {
654 | var items = {},
655 | target = this.data;
656 |
657 | if (typeof key !== 'string') {
658 | return;
659 | }
660 |
661 | key = key.split('/').filter(function (value) {
662 | return value != '';
663 | });
664 |
665 | for (var i = 0, l = key.length; i < l; i++) {
666 | var item = key[i];
667 |
668 | if (i < l - 1) {
669 |
670 | if (target[item]) {
671 | target = target[item];
672 | } else {
673 | target[item] = {};
674 |
675 | target = target[item];
676 | }
677 | } else {
678 | target[item] = value;
679 | }
680 | }
681 |
682 | for (var key in this.data) {
683 | if (typeof this.data[key] !== 'function') {
684 | items[key] = this.data[key];
685 | }
686 | }
687 |
688 | chrome.storage.local.set(items, function () {
689 | satus.events.trigger('storage-set');
690 |
691 | if (callback) {
692 | callback();
693 | }
694 | });
695 | };
696 |
697 |
698 | /*--------------------------------------------------------------
699 | # LOCALIZATION
700 | --------------------------------------------------------------*/
701 |
702 | /*--------------------------------------------------------------
703 | # GET
704 | --------------------------------------------------------------*/
705 |
706 | satus.locale.get = function (string) {
707 | return this.data[string] || string;
708 | };
709 |
710 |
711 | /*--------------------------------------------------------------
712 | # IMPORT
713 | ----------------------------------------------------------------
714 | satus.locale.import(url, onload, onsuccess);
715 | --------------------------------------------------------------*/
716 |
717 | satus.locale.import = function (code, callback, path) {
718 | var language = code || window.navigator.language;
719 |
720 | if (language.indexOf('en') === 0) {
721 | language = 'en';
722 | }
723 |
724 | if (!path) {
725 | path = '_locales/';
726 | }
727 |
728 | satus.fetch(chrome.runtime.getURL(path + language + '/messages.json'), function (response) {
729 | for (var key in response) {
730 | satus.locale.data[key] = response[key].message;
731 | }
732 |
733 | satus.log('LOCALE: data was successfully imported');
734 |
735 | if (callback) {
736 | callback();
737 | }
738 | }, function (success) {
739 | satus.fetch(chrome.runtime.getURL(path + 'en/messages.json'), success, function () {
740 | success();
741 | });
742 | });
743 | };
744 |
745 |
746 | /*--------------------------------------------------------------
747 | # LOG
748 | --------------------------------------------------------------*/
749 |
750 | satus.log = function () {
751 | console.log.apply(null, arguments);
752 | };
753 |
754 |
755 | /*--------------------------------------------------------------
756 | # STYLE
757 | --------------------------------------------------------------*/
758 |
759 | satus.style = function (element, object) {
760 | if (object) {
761 | for (var key in object) {
762 | element.style[key] = object[key];
763 | }
764 | }
765 | };
766 |
767 |
768 | /*--------------------------------------------------------------
769 | # TEXT
770 | --------------------------------------------------------------*/
771 |
772 | satus.text = function (element, value) {
773 | if (value) {
774 | element.appendChild(document.createTextNode(this.locale.get(value)));
775 | }
776 | };
777 | /*--------------------------------------------------------------
778 | >>> MODAL
779 | --------------------------------------------------------------*/
780 |
781 | satus.components.modal = function (component, skeleton) {
782 | component.scrim = component.createChildElement('div', 'scrim');
783 | component.surface = component.createChildElement('div', 'surface');
784 |
785 | component.close = function () {
786 | var component = this;
787 |
788 | this.classList.add('satus-modal--closing');
789 |
790 | setTimeout(function () {
791 | component.remove();
792 |
793 | component.dispatchEvent(new CustomEvent('close'));
794 | }, Number(satus.css(this.surface, 'animation-duration').replace(/[^0-9.]/g, '')) * 1000);
795 | };
796 |
797 | component.scrim.addEventListener('click', function () {
798 | this.parentNode.close();
799 | });
800 |
801 | component.childrenContainer = component.surface;
802 | };
803 | /*--------------------------------------------------------------
804 | >>> GRID
805 | --------------------------------------------------------------*/
806 |
807 | satus.components.grid = function (component, skeleton) {
808 | console.log(component, skeleton);
809 | };
810 | /*--------------------------------------------------------------
811 | >>> TEXT FIELD
812 | --------------------------------------------------------------*/
813 |
814 | satus.components.textField = function (component, skeleton) {
815 | var container = component.createChildElement('div', 'container'),
816 | input = container.createChildElement('input'),
817 | pre = container.createChildElement('pre'),
818 | hiddenValue = container.createChildElement('pre', 'hidden-value'),
819 | selection = container.createChildElement('div', 'selection'),
820 | cursor = container.createChildElement('div', 'cursor');
821 |
822 | component.placeholder = skeleton.placeholder;
823 | component.input = input;
824 | component.pre = pre;
825 | component.hiddenValue = hiddenValue;
826 | component.selection = selection;
827 | component.cursor = cursor;
828 | component.syntax = {
829 | current: 'text',
830 | handlers: {
831 | regex: function (value, target) {
832 | var regex_token = /\[\^?]?(?:[^\\\]]+|\\[\S\s]?)*]?|\\(?:0(?:[0-3][0-7]{0,2}|[4-7][0-7]?)?|[1-9][0-9]*|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}|c[A-Za-z]|[\S\s]?)|\((?:\?[:=!]?)?|(?:[?*+]|\{[0-9]+(?:,[0-9]*)?\})\??|[^.?*+^${[()|\\]+|./g,
833 | char_class_token = /[^\\-]+|-|\\(?:[0-3][0-7]{0,2}|[4-7][0-7]?|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}|c[A-Za-z]|[\S\s]?)/g,
834 | char_class_parts = /^(\[\^?)(]?(?:[^\\\]]+|\\[\S\s]?)*)(]?)$/,
835 | quantifier = /^(?:[?*+]|\{[0-9]+(?:,[0-9]*)?\})\??$/,
836 | matches = value.match(regex_token);
837 |
838 | function create(type, string) {
839 | var span = document.createElement('span');
840 |
841 | span.className = type;
842 | span.textContent = string;
843 |
844 | target.appendChild(span);
845 | }
846 |
847 | for (var i = 0, l = matches.length; i < l; i++) {
848 | var match = matches[i];
849 |
850 | if (match[0] === '[') {
851 | create('character-class', match);
852 | } else if (match[0] === '(') {
853 | create('group', match);
854 | } else if (match[0] === ')') {
855 | create('group', match);
856 | } else if (match[0] === '\\' || match === '^') {
857 | create('anchor', match);
858 | } else if (quantifier.test(match)) {
859 | create('quantifier', match);
860 | } else if (match === '|' || match === '.') {
861 | create('metasequence', match);
862 | } else {
863 | create('text', match);
864 | }
865 | }
866 | }
867 | },
868 | set: function (syntax) {
869 | if (this.handlers[syntax]) {
870 | this.current = syntax;
871 | } else {
872 | this.current = 'text';
873 | }
874 |
875 | pre.update();
876 | }
877 | };
878 | component.focus = function () {
879 | this.input.focus();
880 | };
881 |
882 | Object.defineProperty(component, 'value', {
883 | get: function () {
884 | return this.input.value;
885 | },
886 | set: function (value) {
887 | this.input.value = value;
888 | }
889 | });
890 |
891 | if (skeleton.syntax) {
892 | component.syntax.set(skeleton.syntax);
893 | }
894 |
895 | input.type = 'text';
896 |
897 | selection.setAttribute('disabled', '');
898 |
899 | pre.update = function () {
900 | var component = this.parentNode.parentNode,
901 | handler = component.syntax.handlers[component.syntax.current],
902 | value = component.value || '';
903 |
904 | for (var i = this.childNodes.length - 1; i > -1; i--) {
905 | this.childNodes[i].remove();
906 | }
907 |
908 | if (handler) {
909 | handler(value, this);
910 | } else {
911 | this.textContent = value;
912 | }
913 |
914 | if (value.length === 0) {
915 | var placeholder = component.placeholder;
916 |
917 | if (typeof placeholder === 'function') {
918 | placeholder = component.placeholder();
919 | } else {
920 | placeholder = satus.locale.get(placeholder);
921 | }
922 |
923 | this.textContent = placeholder;
924 | }
925 | };
926 |
927 | cursor.update = function () {
928 | var component = this.parentNode.parentNode,
929 | input = component.input,
930 | start = input.selectionStart,
931 | end = input.selectionEnd,
932 | value = input.value;
933 |
934 | this.style.animation = 'none';
935 |
936 | if (start === end) {
937 | component.selection.setAttribute('disabled', '');
938 | } else {
939 | component.selection.removeAttribute('disabled');
940 |
941 | component.hiddenValue.textContent = value.substring(0, start);
942 |
943 | component.selection.style.left = component.hiddenValue.offsetWidth - input.scrollLeft + 'px';
944 |
945 | component.hiddenValue.textContent = value.substring(start, end);
946 |
947 | component.selection.style.width = component.hiddenValue.offsetWidth + 'px';
948 | }
949 |
950 | if (input.selectionDirection === 'forward') {
951 | component.hiddenValue.textContent = value.substring(0, end);
952 | } else {
953 | component.hiddenValue.textContent = value.substring(0, start);
954 | }
955 |
956 | this.style.left = component.hiddenValue.offsetWidth - input.scrollLeft + 'px';
957 |
958 | this.style.animation = '';
959 |
960 | component.hiddenValue.textContent = '';
961 | };
962 |
963 | document.addEventListener('selectionchange', function (event) {
964 | component.pre.update();
965 | component.cursor.update();
966 | });
967 |
968 | input.addEventListener('input', function () {
969 | var component = this.parentNode.parentNode;
970 |
971 | component.storage.value = this.value;
972 |
973 | component.pre.update();
974 | component.cursor.update();
975 | });
976 |
977 | input.addEventListener('scroll', function (event) {
978 | var component = this.parentNode.parentNode;
979 |
980 | component.pre.style.left = -this.scrollLeft + 'px';
981 |
982 | component.pre.update();
983 | component.cursor.update();
984 | });
985 |
986 | component.addEventListener('change', function () {
987 | this.pre.update();
988 | this.cursor.update();
989 | });
990 |
991 | component.value = component.storage.value || '';
992 |
993 | component.addEventListener('render', function () {
994 | component.pre.update();
995 | component.cursor.update();
996 | });
997 |
998 | if (skeleton.on) {
999 | for (var type in skeleton.on) {
1000 | input.addEventListener(type, function (event) {
1001 | this.parentNode.parentNode.dispatchEvent(new Event(event.type));
1002 | });
1003 | }
1004 | }
1005 | };
1006 | /*--------------------------------------------------------------
1007 | >>> SELECT
1008 | --------------------------------------------------------------*/
1009 |
1010 | satus.components.select = function (component, skeleton) {
1011 | var component_content = document.createElement('span'),
1012 | component_value = document.createElement('span'),
1013 | component_select = document.createElement('select');
1014 |
1015 | for (var i = 0, l = skeleton.options.length; i < l; i++) {
1016 | var option = document.createElement('option');
1017 |
1018 | option.value = skeleton.options[i].value;
1019 |
1020 | satus.text(option, skeleton.options[i].text);
1021 |
1022 | component_select.appendChild(option);
1023 | }
1024 |
1025 | component.inner = component_content;
1026 | component.select = component_select;
1027 |
1028 | Object.defineProperty(component, 'value', {
1029 | get() {
1030 | return this.select.value;
1031 | },
1032 | set(value) {
1033 | this.select.value = value;
1034 | }
1035 | });
1036 |
1037 | component.render = function () {
1038 | var value_element = this.children[2];
1039 |
1040 | satus.empty(value_element);
1041 |
1042 | satus.text(value_element, this.select.options[this.select.selectedIndex].text);
1043 |
1044 | this.dataset.value = this.value;
1045 | };
1046 |
1047 | component.addEventListener('render', function () {
1048 | this.value = this.storage.value || this.skeleton.options[0].value;
1049 |
1050 | this.render();
1051 | });
1052 |
1053 | component_select.addEventListener('change', function () {
1054 | var component = this.parentNode;
1055 |
1056 | component.storage.value = this.value;
1057 |
1058 | component.render();
1059 | });
1060 |
1061 | component.appendChild(component_select);
1062 | component.appendChild(component_content);
1063 | component.appendChild(component_value);
1064 | };
1065 | /*--------------------------------------------------------------
1066 | >>> BASE
1067 | --------------------------------------------------------------*/
1068 |
1069 | satus.components.base = function (component) {
1070 | component.baseProvider = component;
1071 | component.layers = [];
1072 | };
1073 | /*--------------------------------------------------------------
1074 | >>> SIDEBAR
1075 | --------------------------------------------------------------*/
1076 |
1077 | satus.components.sidebar = function (component, skeleton) {};
1078 | /*--------------------------------------------------------------
1079 | >>> LAYERS
1080 | --------------------------------------------------------------*/
1081 |
1082 | satus.components.layers = function (component, skeleton) {
1083 | component.path = [];
1084 | component.renderChildren = false;
1085 | component.baseProvider.layers.push(component);
1086 |
1087 | component.back = function () {
1088 | if (this.path.length > 1) {
1089 | this.path.pop();
1090 |
1091 | this.open(this.path[this.path.length - 1], false);
1092 | }
1093 | };
1094 |
1095 | component.open = function (skeleton, history) {
1096 | satus.empty(this);
1097 |
1098 | var layer = this.createChildElement('div', 'layer');
1099 |
1100 | if (history !== false) {
1101 | this.path.push(skeleton);
1102 | }
1103 |
1104 | layer.skeleton = skeleton;
1105 | layer.baseProvider = this.baseProvider;
1106 |
1107 | satus.render(skeleton, layer, undefined, skeleton.component === 'layers');
1108 |
1109 | this.dispatchEvent(new Event('open'));
1110 | };
1111 |
1112 | component.update = function () {
1113 | var layer = this.querySelector('.satus-layers__layer');
1114 |
1115 | satus.empty(layer);
1116 | satus.render(layer.skeleton, layer);
1117 | };
1118 |
1119 | component.open(skeleton);
1120 | };
1121 | /*--------------------------------------------------------------
1122 | >>> LIST
1123 | --------------------------------------------------------------*/
1124 |
1125 | satus.components.list = function (component, skeleton) {
1126 | for (var i = 0, l = skeleton.items.length; i < l; i++) {
1127 | var li = component.createChildElement('div', 'item'),
1128 | item = skeleton.items[i];
1129 |
1130 | for (var j = 0, k = item.length; j < k; j++) {
1131 | var child = item[j];
1132 |
1133 | if (typeof child === 'string') {
1134 | var span = li.createChildElement('span');
1135 |
1136 | span.textContent = satus.locale.get(child);
1137 | } else {
1138 | satus.render(child, li);
1139 | }
1140 | }
1141 | }
1142 | };
1143 | /*--------------------------------------------------------------
1144 | >>> COLOR PICKER
1145 | --------------------------------------------------------------*/
1146 |
1147 | satus.components.colorPicker = function (component, skeleton) {
1148 | var component_label = component.createChildElement('span', 'label'),
1149 | component_value = component.createChildElement('span', 'value');
1150 |
1151 | component.inner = component_label;
1152 | component.valueElement = component_value;
1153 |
1154 | component.className = 'satus-button';
1155 |
1156 | component.addEventListener('click', function () {
1157 | var rgb = this.rgb,
1158 | hsl = satus.color.rgbToHsl(rgb),
1159 | s = hsl[1] / 100,
1160 | l = hsl[2] / 100;
1161 |
1162 | s *= l < .5 ? l : 1 - l;
1163 |
1164 | var v = l + s;
1165 |
1166 | s = 2 * s / (l + s);
1167 |
1168 | satus.render({
1169 | component: 'modal',
1170 | variant: 'color-picker',
1171 | value: hsl,
1172 | parentElement: this,
1173 |
1174 | palette: {
1175 | component: 'div',
1176 | class: 'satus-color-picker__palette',
1177 | style: {
1178 | 'backgroundColor': 'hsl(' + hsl[0] + 'deg, 100%, 50%)'
1179 | },
1180 | on: {
1181 | mousedown: function () {
1182 | var palette = this,
1183 | rect = this.getBoundingClientRect(),
1184 | cursor = this.children[0];
1185 |
1186 | function mousemove(event) {
1187 | var hsl = palette.skeleton.parentSkeleton.storage.value,
1188 | x = event.clientX - rect.left,
1189 | y = event.clientY - rect.top,
1190 | s;
1191 |
1192 | x = Math.min(Math.max(x, 0), rect.width) / (rect.width / 100);
1193 | y = Math.min(Math.max(y, 0), rect.height) / (rect.height / 100);
1194 |
1195 | var v = 100 - y,
1196 | l = (2 - x / 100) * v / 2;
1197 |
1198 | hsl[1] = x * v / (l < 50 ? l * 2 : 200 - l * 2);
1199 | hsl[2] = l;
1200 |
1201 | cursor.style.left = x + '%';
1202 | cursor.style.top = y + '%';
1203 |
1204 | palette.nextSibling.children[0].style.backgroundColor = 'hsl(' + hsl[0] + 'deg,' + hsl[1] + '%, ' + hsl[2] + '%)';
1205 |
1206 | event.preventDefault();
1207 | }
1208 |
1209 | function mouseup() {
1210 | window.removeEventListener('mousemove', mousemove);
1211 | window.removeEventListener('mouseup', mouseup);
1212 | }
1213 |
1214 | window.addEventListener('mousemove', mousemove);
1215 | window.addEventListener('mouseup', mouseup);
1216 | }
1217 | },
1218 |
1219 | cursor: {
1220 | component: 'div',
1221 | class: 'satus-color-picker__cursor',
1222 | style: {
1223 | 'left': s * 100 + '%',
1224 | 'top': 100 - v * 100 + '%'
1225 | }
1226 | }
1227 | },
1228 | section: {
1229 | component: 'section',
1230 | variant: 'color',
1231 |
1232 | color: {
1233 | component: 'div',
1234 | class: 'satus-color-picker__color',
1235 | style: {
1236 | 'backgroundColor': 'rgb(' + this.rgb.join(',') + ')'
1237 | }
1238 | },
1239 | hue: {
1240 | component: 'slider',
1241 | class: 'satus-color-picker__hue',
1242 | storage: false,
1243 | value: hsl[0],
1244 | max: 360,
1245 | on: {
1246 | change: function () {
1247 | var modal = this.skeleton.parentSkeleton.parentSkeleton,
1248 | hsl = modal.storage.value;
1249 |
1250 | hsl[0] = this.values[0];
1251 |
1252 | this.previousSibling.style.backgroundColor = 'hsl(' + hsl[0] + 'deg,' + hsl[1] + '%, ' + hsl[2] + '%)';
1253 | this.parentSkeletonNode.previousSibling.style.backgroundColor = 'hsl(' + hsl[0] + 'deg, 100%, 50%)';
1254 | }
1255 | }
1256 | }
1257 | },
1258 | actions: {
1259 | component: 'section',
1260 | variant: 'actions',
1261 |
1262 | reset: {
1263 | component: 'button',
1264 | text: 'reset',
1265 | on: {
1266 | click: function () {
1267 | var modal = this.skeleton.parentSkeleton.parentSkeleton,
1268 | component = modal.parentSkeleton;
1269 |
1270 | component.rgb = component.skeleton.value;
1271 |
1272 | component.storage.value = component.rgb;
1273 |
1274 | component.valueElement.style.backgroundColor = 'rgb(' + component.rgb.join(',') + ')';
1275 |
1276 | modal.rendered.close();
1277 | }
1278 | }
1279 | },
1280 | cancel: {
1281 | component: 'button',
1282 | text: 'cancel',
1283 | on: {
1284 | click: function () {
1285 | this.skeleton.parentSkeleton.parentSkeleton.rendered.close();
1286 | }
1287 | }
1288 | },
1289 | ok: {
1290 | component: 'button',
1291 | text: 'OK',
1292 | on: {
1293 | click: function () {
1294 | var modal = this.skeleton.parentSkeleton.parentSkeleton,
1295 | component = modal.parentSkeleton;
1296 |
1297 | component.rgb = satus.color.hslToRgb(modal.storage.value);
1298 |
1299 | component.storage.value = component.rgb;
1300 |
1301 | component.valueElement.style.backgroundColor = 'rgb(' + component.rgb.join(',') + ')';
1302 |
1303 | modal.rendered.close();
1304 | }
1305 | }
1306 | }
1307 | }
1308 | }, this.baseProvider.layers[0]);
1309 | });
1310 |
1311 | component.addEventListener('render', function () {
1312 | component.rgb = this.storage.value || [0, 100, 50];
1313 |
1314 | component_value.style.backgroundColor = 'rgb(' + component.rgb.join(',') + ')';
1315 | });
1316 | };
1317 |
1318 | satus.components.colorPicker = function (component, skeleton) {
1319 | component.color = (function (element) {
1320 | var array;
1321 |
1322 | Object.defineProperty(element, 'value', {
1323 | get: function () {
1324 | return array;
1325 | },
1326 | set: function (value) {
1327 | array = value;
1328 |
1329 | this.parentNode.storage.value = array;
1330 |
1331 | element.style.backgroundColor = 'rgb(' + value.join(',') + ')';
1332 | }
1333 | });
1334 |
1335 | element.value = component.storage.value || component.skeleton.value || [0, 0, 0];
1336 |
1337 | return element;
1338 | })(component.createChildElement('span', 'value'));
1339 |
1340 | component.addEventListener('click', function () {
1341 | var hsl = satus.color.rgbToHsl(this.color.value),
1342 | s = hsl[1] / 100,
1343 | l = hsl[2] / 100;
1344 |
1345 | s *= l < .5 ? l : 1 - l;
1346 |
1347 | var v = l + s;
1348 |
1349 | s = 2 * s / (l + s);
1350 |
1351 | satus.render({
1352 | component: 'modal',
1353 | variant: 'color-picker',
1354 | value: hsl,
1355 | parentElement: this,
1356 |
1357 | palette: {
1358 | component: 'div',
1359 | class: 'satus-color-picker__palette',
1360 | style: {
1361 | 'backgroundColor': 'hsl(' + hsl[0] + 'deg, 100%, 50%)'
1362 | },
1363 | on: {
1364 | mousedown: function (event) {
1365 | if (event.button !== 0) {
1366 | return false;
1367 | }
1368 |
1369 | var palette = this,
1370 | rect = this.getBoundingClientRect(),
1371 | cursor = this.children[0];
1372 |
1373 | function mousemove(event) {
1374 | var hsl = palette.skeleton.parentSkeleton.value,
1375 | x = event.clientX - rect.left,
1376 | y = event.clientY - rect.top,
1377 | s;
1378 |
1379 | x = Math.min(Math.max(x, 0), rect.width) / (rect.width / 100);
1380 | y = Math.min(Math.max(y, 0), rect.height) / (rect.height / 100);
1381 |
1382 | var v = 100 - y,
1383 | l = (2 - x / 100) * v / 2;
1384 |
1385 | hsl[1] = x * v / (l < 50 ? l * 2 : 200 - l * 2);
1386 | hsl[2] = l;
1387 |
1388 | cursor.style.left = x + '%';
1389 | cursor.style.top = y + '%';
1390 |
1391 | palette.nextSibling.children[0].style.backgroundColor = 'hsl(' + hsl[0] + 'deg,' + hsl[1] + '%, ' + hsl[2] + '%)';
1392 |
1393 | event.preventDefault();
1394 | }
1395 |
1396 | function mouseup() {
1397 | window.removeEventListener('mousemove', mousemove);
1398 | window.removeEventListener('mouseup', mouseup);
1399 | }
1400 |
1401 | window.addEventListener('mousemove', mousemove);
1402 | window.addEventListener('mouseup', mouseup);
1403 | }
1404 | },
1405 |
1406 | cursor: {
1407 | component: 'div',
1408 | class: 'satus-color-picker__cursor',
1409 | style: {
1410 | 'left': s * 100 + '%',
1411 | 'top': 100 - v * 100 + '%'
1412 | }
1413 | }
1414 | },
1415 | section: {
1416 | component: 'section',
1417 | variant: 'color',
1418 |
1419 | color: {
1420 | component: 'div',
1421 | class: 'satus-color-picker__color',
1422 | style: {
1423 | 'backgroundColor': 'rgb(' + this.color.value.join(',') + ')'
1424 | }
1425 | },
1426 | hue: {
1427 | component: 'slider',
1428 | class: 'satus-color-picker__hue',
1429 | storage: false,
1430 | value: hsl[0],
1431 | max: 360,
1432 | on: {
1433 | input: function () {
1434 | var modal = this.skeleton.parentSkeleton.parentSkeleton,
1435 | hsl = modal.value;
1436 |
1437 | hsl[0] = this.storage.value;
1438 |
1439 | this.previousSibling.style.backgroundColor = 'hsl(' + hsl[0] + 'deg,' + hsl[1] + '%, ' + hsl[2] + '%)';
1440 | this.parentNode.previousSibling.style.backgroundColor = 'hsl(' + hsl[0] + 'deg, 100%, 50%)';
1441 | }
1442 | }
1443 | }
1444 | },
1445 | actions: {
1446 | component: 'section',
1447 | variant: 'actions',
1448 |
1449 | reset: {
1450 | component: 'button',
1451 | text: 'reset',
1452 | on: {
1453 | click: function () {
1454 | var modal = this.skeleton.parentSkeleton.parentSkeleton,
1455 | component = modal.parentElement;
1456 |
1457 | component.color.value = component.skeleton.value || [0, 0, 0];
1458 |
1459 | modal.rendered.close();
1460 | }
1461 | }
1462 | },
1463 | cancel: {
1464 | component: 'button',
1465 | text: 'cancel',
1466 | on: {
1467 | click: function () {
1468 | this.skeleton.parentSkeleton.parentSkeleton.rendered.close();
1469 | }
1470 | }
1471 | },
1472 | ok: {
1473 | component: 'button',
1474 | text: 'OK',
1475 | on: {
1476 | click: function () {
1477 | var modal = this.skeleton.parentSkeleton.parentSkeleton,
1478 | component = modal.parentElement;
1479 |
1480 | component.color.value = satus.color.hslToRgb(modal.value);
1481 |
1482 | modal.rendered.close();
1483 | }
1484 | }
1485 | }
1486 | }
1487 | }, this.baseProvider.layers[0]);
1488 | });
1489 | };
1490 | /*--------------------------------------------------------------
1491 | >>> RADIO
1492 | --------------------------------------------------------------*/
1493 |
1494 | satus.components.radio = function (component, skeleton) {
1495 | var content = document.createElement('span'),
1496 | radio = document.createElement('input');
1497 |
1498 | component.inner = content;
1499 |
1500 | radio.type = 'radio';
1501 |
1502 | if (skeleton.group) {
1503 | component.storage.key = skeleton.group;
1504 | radio.name = skeleton.group;
1505 | }
1506 |
1507 | if (skeleton.value) {
1508 | radio.value = skeleton.value;
1509 | }
1510 |
1511 | component.addEventListener('render', function () {
1512 | this.storage.value = satus.storage.get(this.storage.key);
1513 |
1514 | if (satus.isset(this.storage.value)) {
1515 | radio.checked = this.storage.value === skeleton.value;
1516 | } else if (skeleton.checked) {
1517 | radio.checked = true;
1518 | }
1519 | });
1520 |
1521 | radio.addEventListener('change', function () {
1522 | this.parentNode.storage.value = this.value;
1523 | });
1524 |
1525 | component.appendChild(content);
1526 | component.appendChild(radio);
1527 | };
1528 | /*--------------------------------------------------------------
1529 | >>> SLIDER
1530 | --------------------------------------------------------------*/
1531 |
1532 | satus.components.slider = function (component, skeleton) {
1533 | var label = component.createChildElement('div', 'label');
1534 |
1535 | component.min = skeleton.min || 0;
1536 | component.max = skeleton.max || 1;
1537 | component.step = skeleton.step || 1;
1538 | component.percentageStep = 100 / ((component.max - component.min) / component.step);
1539 | component.precision = String(component.step).replace(/[0-9]./, '').length;
1540 | component.inner = label.createChildElement('div', 'inner');
1541 | component.track = component.createChildElement('div', 'track');
1542 | component.track.tabIndex = 0;
1543 | component.slice = component.track.createChildElement('div', 'slice');
1544 |
1545 | component.valueElement = satus.render({
1546 | component: 'input',
1547 | type: 'number',
1548 | properties: {
1549 | min: component.min,
1550 | max: component.max,
1551 | step: component.step
1552 | },
1553 | on: {
1554 | input: function () {
1555 | var component = this.parentNode.parentNode;
1556 |
1557 | component.storage.value = Math.min(component.max, Math.max(this.value, component.min));
1558 |
1559 | component.update();
1560 | }
1561 | }
1562 | }, label);
1563 |
1564 | if (satus.isset(skeleton.value)) {
1565 | component.storage.value = skeleton.value;
1566 | } else {
1567 | component.storage.value = (component.max < component.min) ? component.min : component.min + (component.max - component.min) / 2;
1568 | }
1569 |
1570 | component.update = function () {
1571 | this.dataset.value = this.value;
1572 |
1573 | this.valueElement.value = this.value;
1574 |
1575 | this.slice.style.width = (this.value - this.min) / ((this.max - this.min) / 100) + '%';
1576 | };
1577 |
1578 | component.move = function (event) {
1579 | var track = this.track.getBoundingClientRect(),
1580 | x = Math.min(track.width, Math.max(event.clientX - track.left, 0));
1581 |
1582 | this.value = x / track.width * 100 / this.percentageStep * this.step + this.min;
1583 | this.value = Math.round(this.value / this.step) * this.step;
1584 | this.value = Number(this.value.toFixed(this.precision));
1585 |
1586 | this.storage.value = this.value;
1587 |
1588 | this.update();
1589 | };
1590 |
1591 | component.track.addEventListener('keydown', function (event) {
1592 | if (event.keyCode === 37) {
1593 | this.value -= this.step;
1594 | } else if (event.keyCode === 39) {
1595 | this.value += this.step;
1596 | }
1597 |
1598 | this.value = Math.min(this.max, Math.max(this.value, this.min));
1599 |
1600 | this.storage.value = this.value;
1601 |
1602 | this.update();
1603 | });
1604 |
1605 | component.track.addEventListener('mousedown', function (event) {
1606 | if (event.button === 0) {
1607 | var component = this.parentNode;
1608 |
1609 | component.move(event);
1610 |
1611 | function mousemove(event) {
1612 | event.preventDefault();
1613 | event.stopPropagation();
1614 |
1615 | component.move(event);
1616 |
1617 | return false;
1618 | }
1619 |
1620 | function mouseup() {
1621 | window.removeEventListener('mousemove', mousemove);
1622 | window.removeEventListener('mouseup', mouseup);
1623 | }
1624 |
1625 | window.addEventListener('mousemove', mousemove);
1626 | window.addEventListener('mouseup', mouseup);
1627 | }
1628 | });
1629 |
1630 | component.update();
1631 | };
1632 |
1633 |
1634 | satus.components.slider = function (component, skeleton) {
1635 | var track = component.createChildElement('div', 'track'),
1636 | range = track.createChildElement('input', 'range');
1637 |
1638 | range.type = 'range';
1639 | range.min = skeleton.min || 0;
1640 | range.max = skeleton.max || 1;
1641 | range.step = skeleton.step || 1;
1642 | range.value = component.storage.value || skeleton.value;
1643 |
1644 | range.addEventListener('input', function () {
1645 | component.storage.value = Number(this.value);
1646 | });
1647 |
1648 | if (skeleton.on) {
1649 | for (var type in skeleton.on) {
1650 | range.addEventListener(type, function (event) {
1651 | this.parentNode.dispatchEvent(new Event(event.type));
1652 | });
1653 | }
1654 | }
1655 | };
1656 | /*--------------------------------------------------------------
1657 | >>> SHORTCUT
1658 | --------------------------------------------------------------*/
1659 |
1660 | satus.components.shortcut = function (component, skeleton) {
1661 | var content = document.createElement('span'),
1662 | value = document.createElement('div');
1663 |
1664 | component.inner = content;
1665 |
1666 | component.className = 'satus-button';
1667 | value.className = 'satus-shortcut__value';
1668 |
1669 | component.render = function (parent) {
1670 | var self = this,
1671 | parent = parent || self.primary,
1672 | children = parent.children;
1673 |
1674 | satus.empty(parent);
1675 |
1676 | function createElement(name) {
1677 | var element = document.createElement('div');
1678 |
1679 | element.className = 'satus-shortcut__' + name;
1680 |
1681 | parent.appendChild(element);
1682 |
1683 | return element;
1684 | }
1685 |
1686 | if (this.data.alt) {
1687 | createElement('key').textContent = 'Alt';
1688 | }
1689 |
1690 | if (this.data.ctrl) {
1691 | if (children.length && children[children.length - 1].className.indexOf('plus') === -1) {
1692 | createElement('plus');
1693 | }
1694 |
1695 | createElement('key').textContent = 'Ctrl';
1696 | }
1697 |
1698 | if (this.data.shift) {
1699 | if (children.length && children[children.length - 1].className.indexOf('plus') === -1) {
1700 | createElement('plus');
1701 | }
1702 |
1703 | createElement('key').textContent = 'Shift';
1704 | }
1705 |
1706 | for (var code in this.data.keys) {
1707 | var key = this.data.keys[code].key,
1708 | arrows = ['ArrowUp', 'ArrowRight', 'ArrowDown', 'ArrowLeft'],
1709 | index = arrows.indexOf(key);
1710 |
1711 | if (children.length && children[children.length - 1].className.indexOf('plus') === -1) {
1712 | createElement('plus');
1713 | }
1714 |
1715 | if (index !== -1) {
1716 | createElement('key').textContent = ['↑', '→', '↓', '←'][index];
1717 | } else if (key === ' ') {
1718 | createElement('key').textContent = '␣';
1719 | } else if (key) {
1720 | createElement('key').textContent = key.toUpperCase();
1721 | }
1722 | }
1723 |
1724 | if (this.data.wheel) {
1725 | if (children.length && children[children.length - 1].className.indexOf('plus') === -1) {
1726 | createElement('plus');
1727 | }
1728 |
1729 | var mouse = createElement('mouse'),
1730 | div = document.createElement('div');
1731 |
1732 | mouse.appendChild(div);
1733 |
1734 | mouse.className += ' ' + (this.data.wheel > 0);
1735 | }
1736 |
1737 | if (this.data.click) {
1738 | if (children.length && children[children.length - 1].className.indexOf('plus') === -1) {
1739 | createElement('plus');
1740 | }
1741 |
1742 | var mouse = createElement('mouse'),
1743 | div = document.createElement('div');
1744 |
1745 | mouse.appendChild(div);
1746 |
1747 | mouse.className += ' click';
1748 | }
1749 |
1750 | if (this.data.middle) {
1751 | if (children.length && children[children.length - 1].className.indexOf('plus') === -1) {
1752 | createElement('plus');
1753 | }
1754 |
1755 | var mouse = createElement('mouse'),
1756 | div = document.createElement('div');
1757 |
1758 | mouse.appendChild(div);
1759 |
1760 | mouse.className += ' middle';
1761 | }
1762 |
1763 | if (this.data.context) {
1764 | if (children.length && children[children.length - 1].className.indexOf('plus') === -1) {
1765 | createElement('plus');
1766 | }
1767 |
1768 | var mouse = createElement('mouse'),
1769 | div = document.createElement('div');
1770 |
1771 | mouse.appendChild(div);
1772 |
1773 | mouse.className += ' context';
1774 | }
1775 | };
1776 |
1777 | component.valueElement = value;
1778 |
1779 | component.appendChild(content);
1780 | component.appendChild(value);
1781 |
1782 | component.keydown = function (event) {
1783 | event.preventDefault();
1784 | event.stopPropagation();
1785 |
1786 | component.data = {
1787 | alt: event.altKey,
1788 | ctrl: event.ctrlKey,
1789 | shift: event.shiftKey,
1790 | keys: {}
1791 | };
1792 |
1793 | if (['control', 'alt', 'altgraph', 'shift'].indexOf(event.key.toLowerCase()) === -1) {
1794 | component.data.keys[event.keyCode] = {
1795 | code: event.code,
1796 | key: event.key
1797 | };
1798 | }
1799 |
1800 | component.data.wheel = 0;
1801 |
1802 | component.render();
1803 |
1804 | return false;
1805 | };
1806 |
1807 | if (skeleton.wheel !== false) {
1808 | component.mousewheel = function (event) {
1809 | event.stopPropagation();
1810 |
1811 | if (
1812 | (
1813 | component.data.wheel === 0 &&
1814 | (
1815 | Object.keys(component.data.keys).length === 0 &&
1816 | component.data.alt === false &&
1817 | component.data.ctrl === false &&
1818 | component.data.shift === false
1819 | )
1820 | ) ||
1821 | component.data.wheel < 0 && event.deltaY > 0 ||
1822 | component.data.wheel > 0 && event.deltaY < 0) {
1823 | component.data = {
1824 | alt: false,
1825 | ctrl: false,
1826 | shift: false,
1827 | keys: {}
1828 | };
1829 | }
1830 |
1831 | component.data.wheel = event.deltaY < 0 ? -1 : 1;
1832 |
1833 | component.render();
1834 |
1835 | return false;
1836 | };
1837 | }
1838 |
1839 | component.addEventListener('click', function () {
1840 | satus.render({
1841 | component: 'modal',
1842 | properties: {
1843 | parent: this
1844 | },
1845 | on: {
1846 | close: function () {
1847 | window.removeEventListener('keydown', component.keydown);
1848 | window.removeEventListener('wheel', component.mousewheel);
1849 | }
1850 | },
1851 |
1852 | primary: {
1853 | component: 'div',
1854 | class: 'satus-shortcut__primary',
1855 | on: {
1856 | render: function () {
1857 | component.primary = this;
1858 |
1859 | if (component.skeleton.mouseButtons === true) {
1860 | this.addEventListener('mousedown', function (event) {
1861 | if (
1862 | component.data.click && event.button === 0 ||
1863 | component.data.middle && event.button === 1
1864 | ) {
1865 | component.data = {
1866 | alt: false,
1867 | ctrl: false,
1868 | shift: false,
1869 | keys: {}
1870 | };
1871 | }
1872 |
1873 | component.data.click = false;
1874 | component.data.middle = false;
1875 | component.data.context = false;
1876 |
1877 | if (event.button === 0) {
1878 | component.data.click = true;
1879 |
1880 | component.render();
1881 | } else if (event.button === 1) {
1882 | component.data.middle = true;
1883 |
1884 | component.render();
1885 | }
1886 | });
1887 |
1888 | this.addEventListener('contextmenu', function (event) {
1889 | event.preventDefault();
1890 | event.stopPropagation();
1891 |
1892 | if (component.data.context) {
1893 | component.data = {
1894 | alt: false,
1895 | ctrl: false,
1896 | shift: false,
1897 | keys: {}
1898 | };
1899 | }
1900 |
1901 | component.data.context = true;
1902 | component.data.middle = false;
1903 | component.data.click = false;
1904 |
1905 | component.render();
1906 |
1907 | return false;
1908 | });
1909 | }
1910 |
1911 | component.render();
1912 | }
1913 | }
1914 | },
1915 | actions: {
1916 | component: 'section',
1917 | variant: 'actions',
1918 |
1919 | reset: {
1920 | component: 'button',
1921 | text: 'reset',
1922 | on: {
1923 | click: function () {
1924 | var component = this.parentNode.parentNode.parentNode.parent;
1925 |
1926 | component.data = component.skeleton.value || {};
1927 |
1928 | component.render(component.valueElement);
1929 |
1930 | satus.storage.remove(component.storage);
1931 |
1932 | this.parentNode.parentNode.parentNode.close();
1933 |
1934 | window.removeEventListener('keydown', component.keydown);
1935 | window.removeEventListener('wheel', component.mousewheel);
1936 | }
1937 | }
1938 | },
1939 | cancel: {
1940 | component: 'button',
1941 | text: 'cancel',
1942 | on: {
1943 | click: function () {
1944 | component.data = satus.storage.get(component.storage) || component.skeleton.value || {};
1945 |
1946 | component.render(component.valueElement);
1947 |
1948 | this.parentNode.parentNode.parentNode.close();
1949 |
1950 | window.removeEventListener('keydown', component.keydown);
1951 | window.removeEventListener('wheel', component.mousewheel);
1952 | }
1953 | }
1954 | },
1955 | save: {
1956 | component: 'button',
1957 | text: 'save',
1958 | on: {
1959 | click: function () {
1960 | component.storage.value = component.data;
1961 |
1962 | component.render(component.valueElement);
1963 |
1964 | this.parentNode.parentNode.parentNode.close();
1965 |
1966 | window.removeEventListener('keydown', component.keydown);
1967 | window.removeEventListener('wheel', component.mousewheel);
1968 | }
1969 | }
1970 | }
1971 | }
1972 | }, this.baseProvider);
1973 |
1974 | window.addEventListener('keydown', this.keydown);
1975 | window.addEventListener('wheel', this.mousewheel);
1976 | });
1977 |
1978 | component.data = component.storage.value || {
1979 | alt: false,
1980 | ctrl: false,
1981 | shift: false,
1982 | keys: {},
1983 | wheel: 0
1984 | };
1985 |
1986 | component.render(component.valueElement);
1987 | };
1988 | /*--------------------------------------------------------------
1989 | >>> CHECKBOX
1990 | --------------------------------------------------------------*/
1991 |
1992 | satus.components.checkbox = function (component, skeleton) {
1993 | var content = component.add('span', 'checkbox__content');
1994 |
1995 | component.inner = content;
1996 |
1997 | component.addEventListener('click', function () {
1998 | if (this.dataset.value === 'true') {
1999 | this.storage.value = false;
2000 | this.dataset.value = 'false';
2001 | } else {
2002 | this.storage.value = true;
2003 | this.dataset.value = 'true';
2004 | }
2005 | });
2006 |
2007 | component.addEventListener('render', function () {
2008 | this.dataset.value = this.storage.value;
2009 | });
2010 | };
2011 | /*--------------------------------------------------------------
2012 | >>> SWITCH
2013 | --------------------------------------------------------------*/
2014 |
2015 | satus.components.switch = function (component, skeleton) {
2016 | var component_thumb = document.createElement('i');
2017 |
2018 | component.addEventListener('click', function () {
2019 | if (this.dataset.value === 'true') {
2020 | this.storage.value = false;
2021 | this.dataset.value = 'false';
2022 | } else {
2023 | this.storage.value = true;
2024 | this.dataset.value = 'true';
2025 | }
2026 | }, true);
2027 |
2028 | component.addEventListener('render', function () {
2029 | this.dataset.value = this.storage.value;
2030 | });
2031 |
2032 | component.appendChild(component_thumb);
2033 | };
2034 | /*--------------------------------------------------------------
2035 | >>> COLOR:
2036 | ----------------------------------------------------------------
2037 | # RGB to HSL
2038 | # HUE to RGB
2039 | # HSL to RGB
2040 | --------------------------------------------------------------*/
2041 |
2042 | satus.color = {};
2043 |
2044 |
2045 | /*--------------------------------------------------------------
2046 | # RGB TO HSL
2047 | --------------------------------------------------------------*/
2048 |
2049 | satus.color.rgbToHsl = function (array) {
2050 | var r = array[0] / 255,
2051 | g = array[1] / 255,
2052 | b = array[2] / 255,
2053 | min = Math.min(r, g, b),
2054 | max = Math.max(r, g, b),
2055 | h = 0,
2056 | s = 0,
2057 | l = (min + max) / 2;
2058 |
2059 | if (min === max) {
2060 | h = 0;
2061 | s = 0;
2062 | } else {
2063 | var delta = max - min;
2064 |
2065 | s = l <= 0.5 ? delta / (max + min) : delta / (2 - max - min);
2066 |
2067 | if (max === r) {
2068 | h = (g - b) / delta + (g < b ? 6 : 0);
2069 | } else if (max === g) {
2070 | h = (b - r) / delta + 2;
2071 | } else if (max === b) {
2072 | h = (r - g) / delta + 4;
2073 | }
2074 |
2075 | h /= 6;
2076 | }
2077 |
2078 | h *= 360;
2079 | s *= 100;
2080 | l *= 100;
2081 |
2082 | if (array.length === 3) {
2083 | return [h, s, l];
2084 | } else {
2085 | return [h, s, l, array[3]];
2086 | }
2087 | };
2088 |
2089 |
2090 | /*--------------------------------------------------------------
2091 | # HUE TO RGB
2092 | --------------------------------------------------------------*/
2093 |
2094 | satus.color.hueToRgb = function (array) {
2095 | var t1 = array[0],
2096 | t2 = array[1],
2097 | hue = array[2];
2098 |
2099 | if (hue < 0) {
2100 | hue += 6;
2101 | }
2102 |
2103 | if (hue >= 6) {
2104 | hue -= 6;
2105 | }
2106 |
2107 | if (hue < 1) {
2108 | return (t2 - t1) * hue + t1;
2109 | } else if (hue < 3) {
2110 | return t2;
2111 | } else if (hue < 4) {
2112 | return (t2 - t1) * (4 - hue) + t1;
2113 | } else {
2114 | return t1;
2115 | }
2116 | };
2117 |
2118 |
2119 | /*--------------------------------------------------------------
2120 | # HSL TO RGB
2121 | --------------------------------------------------------------*/
2122 |
2123 | satus.color.hslToRgb = function (array) {
2124 | var h = array[0] / 360,
2125 | s = array[1] / 100,
2126 | l = array[2] / 100,
2127 | r, g, b;
2128 |
2129 | if (s == 0) {
2130 | r = g = b = l;
2131 | } else {
2132 | var hue2rgb = function hue2rgb(p, q, t) {
2133 | if (t < 0) t += 1;
2134 | if (t > 1) t -= 1;
2135 | if (t < 1 / 6) return p + (q - p) * 6 * t;
2136 | if (t < 1 / 2) return q;
2137 | if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
2138 | return p;
2139 | }
2140 |
2141 | var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
2142 | var p = 2 * l - q;
2143 | r = hue2rgb(p, q, h + 1 / 3);
2144 | g = hue2rgb(p, q, h);
2145 | b = hue2rgb(p, q, h - 1 / 3);
2146 | }
2147 |
2148 | return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
2149 | };
2150 | /*--------------------------------------------------------------
2151 | >>> USER
2152 | --------------------------------------------------------------*/
2153 |
2154 | satus.user = function () {
2155 | /*--------------------------------------------------------------
2156 | 1.0 VARIABLES
2157 | --------------------------------------------------------------*/
2158 |
2159 | var user_agent = navigator.userAgent,
2160 | random_cookie = 'ta{t`nX6cMXK,Wsc',
2161 | video = document.createElement('video'),
2162 | video_formats = {
2163 | ogg: 'video/ogg; codecs="theora"',
2164 | h264: 'video/mp4; codecs="avc1.42E01E"',
2165 | webm: 'video/webm; codecs="vp8, vorbis"',
2166 | vp9: 'video/webm; codecs="vp9"',
2167 | hls: 'application/x-mpegURL; codecs="avc1.42E01E"'
2168 | },
2169 | audio = document.createElement('audio'),
2170 | audio_formats = {
2171 | mp3: 'audio/mpeg',
2172 | mp4: 'audio/mp4',
2173 | aif: 'audio/x-aiff'
2174 | },
2175 | cvs = document.createElement('canvas'),
2176 | ctx = cvs.getContext('webgl'),
2177 | data = {
2178 | browser: {
2179 | audio: null,
2180 | cookies: null,
2181 | flash: null,
2182 | java: null,
2183 | languages: null,
2184 | name: null,
2185 | platform: null,
2186 | version: null,
2187 | video: null,
2188 | webgl: null
2189 | },
2190 | os: {
2191 | name: null,
2192 | type: null
2193 | },
2194 | device: {
2195 | connection: {
2196 | type: null,
2197 | speed: null
2198 | },
2199 | cores: null,
2200 | gpu: null,
2201 | max_touch_points: null,
2202 | ram: null,
2203 | screen: null,
2204 | touch: null
2205 | }
2206 | };
2207 |
2208 |
2209 | /*--------------------------------------------------------------
2210 | 2.0 SOFTWARE
2211 | --------------------------------------------------------------*/
2212 |
2213 | /*--------------------------------------------------------------
2214 | 2.1.0 OS
2215 | --------------------------------------------------------------*/
2216 |
2217 | /*--------------------------------------------------------------
2218 | 2.1.1 NAME
2219 | --------------------------------------------------------------*/
2220 |
2221 | if (navigator.appVersion.indexOf('Win') !== -1) {
2222 | if (navigator.appVersion.match(/(Windows 10.0|Windows NT 10.0)/)) {
2223 | data.os.name = 'Windows 10';
2224 | } else if (navigator.appVersion.match(/(Windows 8.1|Windows NT 6.3)/)) {
2225 | data.os.name = 'Windows 8.1';
2226 | } else if (navigator.appVersion.match(/(Windows 8|Windows NT 6.2)/)) {
2227 | data.os.name = 'Windows 8';
2228 | } else if (navigator.appVersion.match(/(Windows 7|Windows NT 6.1)/)) {
2229 | data.os.name = 'Windows 7';
2230 | } else if (navigator.appVersion.match(/(Windows NT 6.0)/)) {
2231 | data.os.name = 'Windows Vista';
2232 | } else if (navigator.appVersion.match(/(Windows NT 5.1|Windows XP)/)) {
2233 | data.os.name = 'Windows XP';
2234 | } else {
2235 | data.os.name = 'Windows';
2236 | }
2237 | } else if (navigator.appVersion.indexOf('(iPhone|iPad|iPod)') !== -1) {
2238 | data.os.name = 'iOS';
2239 | } else if (navigator.appVersion.indexOf('Mac') !== -1) {
2240 | data.os.name = 'macOS';
2241 | } else if (navigator.appVersion.indexOf('Android') !== -1) {
2242 | data.os.name = 'Android';
2243 | } else if (navigator.appVersion.indexOf('OpenBSD') !== -1) {
2244 | data.os.name = 'OpenBSD';
2245 | } else if (navigator.appVersion.indexOf('SunOS') !== -1) {
2246 | data.os.name = 'SunOS';
2247 | } else if (navigator.appVersion.indexOf('Linux') !== -1) {
2248 | data.os.name = 'Linux';
2249 | } else if (navigator.appVersion.indexOf('X11') !== -1) {
2250 | data.os.name = 'UNIX';
2251 | }
2252 |
2253 | /*--------------------------------------------------------------
2254 | 2.1.2 TYPE
2255 | --------------------------------------------------------------*/
2256 |
2257 | if (navigator.appVersion.match(/(Win64|x64|x86_64|WOW64)/)) {
2258 | data.os.type = '64-bit';
2259 | } else {
2260 | data.os.type = '32-bit';
2261 | }
2262 |
2263 |
2264 | /*--------------------------------------------------------------
2265 | 2.2.0 BROWSER
2266 | --------------------------------------------------------------*/
2267 |
2268 | /*--------------------------------------------------------------
2269 | 2.2.1 NAME
2270 | --------------------------------------------------------------*/
2271 |
2272 | if (user_agent.indexOf('Opera') !== -1) {
2273 | data.browser.name = 'Opera';
2274 | } else if (user_agent.indexOf('Vivaldi') !== -1) {
2275 | data.browser.name = 'Vivaldi';
2276 | } else if (user_agent.indexOf('Edge') !== -1) {
2277 | data.browser.name = 'Edge';
2278 | } else if (user_agent.indexOf('Chrome') !== -1) {
2279 | data.browser.name = 'Chrome';
2280 | } else if (user_agent.indexOf('Safari') !== -1) {
2281 | data.browser.name = 'Safari';
2282 | } else if (user_agent.indexOf('Firefox') !== -1) {
2283 | data.browser.name = 'Firefox';
2284 | } else if (user_agent.indexOf('MSIE') !== -1) {
2285 | data.browser.name = 'IE';
2286 | }
2287 |
2288 |
2289 | /*--------------------------------------------------------------
2290 | 2.2.2 VERSION
2291 | --------------------------------------------------------------*/
2292 |
2293 | var browser_version = user_agent.match(new RegExp(data.browser.name + '/([0-9.]+)'));
2294 |
2295 | if (browser_version[1]) {
2296 | data.browser.version = browser_version[1];
2297 | }
2298 |
2299 |
2300 | /*--------------------------------------------------------------
2301 | 2.2.3 PLATFORM
2302 | --------------------------------------------------------------*/
2303 |
2304 | data.browser.platform = navigator.platform || null;
2305 |
2306 |
2307 | /*--------------------------------------------------------------
2308 | 2.2.4 LANGUAGES
2309 | --------------------------------------------------------------*/
2310 |
2311 | data.browser.languages = navigator.languages || null;
2312 |
2313 |
2314 | /*--------------------------------------------------------------
2315 | 2.2.5 COOKIES
2316 | --------------------------------------------------------------*/
2317 |
2318 | if (document.cookie) {
2319 | document.cookie = random_cookie;
2320 |
2321 | if (document.cookie.indexOf(random_cookie) !== -1) {
2322 | data.browser.cookies = true;
2323 | }
2324 | }
2325 |
2326 |
2327 | /*--------------------------------------------------------------
2328 | 2.2.6 FLASH
2329 | --------------------------------------------------------------*/
2330 |
2331 | try {
2332 | if (new ActiveXObject('ShockwaveFlash.ShockwaveFlash')) {
2333 | data.browser.flash = true;
2334 | }
2335 | } catch (e) {
2336 | if (navigator.mimeTypes['application/x-shockwave-flash']) {
2337 | data.browser.flash = true;
2338 | }
2339 | }
2340 |
2341 |
2342 | /*--------------------------------------------------------------
2343 | 2.2.7 JAVA
2344 | --------------------------------------------------------------*/
2345 |
2346 | if (typeof navigator.javaEnabled === 'function' && navigator.javaEnabled()) {
2347 | data.browser.java = true;
2348 | }
2349 |
2350 |
2351 | /*--------------------------------------------------------------
2352 | 2.2.8 VIDEO FORMATS
2353 | --------------------------------------------------------------*/
2354 |
2355 | if (typeof video.canPlayType === 'function') {
2356 | data.browser.video = {};
2357 |
2358 | for (var i in video_formats) {
2359 | var can_play_type = video.canPlayType(video_formats[i]);
2360 |
2361 | if (can_play_type === '') {
2362 | data.browser.video[i] = false;
2363 | } else {
2364 | data.browser.video[i] = can_play_type;
2365 | }
2366 | }
2367 | }
2368 |
2369 |
2370 | /*--------------------------------------------------------------
2371 | 2.2.9 AUDIO FORMATS
2372 | --------------------------------------------------------------*/
2373 |
2374 | if (typeof audio.canPlayType === 'function') {
2375 | data.browser.audio = {};
2376 |
2377 | for (var i in audio_formats) {
2378 | var can_play_type = audio.canPlayType(audio_formats[i]);
2379 |
2380 | if (can_play_type == '') {
2381 | data.browser.audio[i] = false;
2382 | } else {
2383 | data.browser.audio[i] = can_play_type;
2384 | }
2385 | }
2386 | }
2387 |
2388 |
2389 | /*--------------------------------------------------------------
2390 | 2.2.10 WEBGL
2391 | --------------------------------------------------------------*/
2392 |
2393 | if (ctx && ctx instanceof WebGLRenderingContext) {
2394 | data.browser.webgl = true;
2395 | }
2396 |
2397 |
2398 | /*--------------------------------------------------------------
2399 | 3.0 HARDWARE
2400 | --------------------------------------------------------------*/
2401 |
2402 | /*--------------------------------------------------------------
2403 | 3.1 SCREEN
2404 | --------------------------------------------------------------*/
2405 |
2406 | if (screen) {
2407 | data.device.screen = screen.width + 'x' + screen.height;
2408 | }
2409 |
2410 |
2411 | /*--------------------------------------------------------------
2412 | 3.2 RAM
2413 | --------------------------------------------------------------*/
2414 |
2415 | if ('deviceMemory' in navigator) {
2416 | data.device.ram = navigator.deviceMemory + ' GB';
2417 | }
2418 |
2419 |
2420 | /*--------------------------------------------------------------
2421 | 3.3 GPU
2422 | --------------------------------------------------------------*/
2423 |
2424 | if (
2425 | ctx &&
2426 | ctx instanceof WebGLRenderingContext &&
2427 | 'getParameter' in ctx &&
2428 | 'getExtension' in ctx
2429 | ) {
2430 | var info = ctx.getExtension('WEBGL_debug_renderer_info');
2431 |
2432 | if (info) {
2433 | data.device.gpu = ctx.getParameter(info.UNMASKED_RENDERER_WEBGL);
2434 | }
2435 | }
2436 |
2437 |
2438 | /*--------------------------------------------------------------
2439 | 3.4 CORES
2440 | --------------------------------------------------------------*/
2441 |
2442 | if (navigator.hardwareConcurrency) {
2443 | data.device.cores = navigator.hardwareConcurrency;
2444 | }
2445 |
2446 |
2447 | /*--------------------------------------------------------------
2448 | 3.5 TOUCH
2449 | --------------------------------------------------------------*/
2450 |
2451 | if (
2452 | window.hasOwnProperty('ontouchstart') ||
2453 | window.DocumentTouch && document instanceof window.DocumentTouch ||
2454 | navigator.maxTouchPoints > 0 ||
2455 | window.navigator.msMaxTouchPoints > 0
2456 | ) {
2457 | data.device.touch = true;
2458 | data.device.max_touch_points = navigator.maxTouchPoints;
2459 | }
2460 |
2461 |
2462 | /*--------------------------------------------------------------
2463 | 3.6 CONNECTION
2464 | --------------------------------------------------------------*/
2465 |
2466 | if (typeof navigator.connection === 'object') {
2467 | data.device.connection.type = navigator.connection.effectiveType || null;
2468 |
2469 | if (navigator.connection.downlink) {
2470 | data.device.connection.speed = navigator.connection.downlink + ' Mbps';
2471 | }
2472 | }
2473 |
2474 |
2475 | /*--------------------------------------------------------------
2476 | 4.0 CLEARING
2477 | --------------------------------------------------------------*/
2478 |
2479 | video.remove();
2480 | audio.remove();
2481 | cvs.remove();
2482 |
2483 |
2484 | return data;
2485 | };
2486 | /*--------------------------------------------------------------
2487 | # SEARCH
2488 | --------------------------------------------------------------*/
2489 |
2490 | satus.search = function (query, object, callback) {
2491 | var elements = ['switch', 'select', 'slider', 'shortcut', 'radio', 'color-picker'],
2492 | threads = 0,
2493 | results = {},
2494 | excluded = [
2495 | 'baseProvider',
2496 | 'childrenContainer',
2497 | 'parentElement',
2498 | 'parentObject',
2499 | 'parentSkeleton',
2500 | 'rendered',
2501 | 'namespaceURI'
2502 | ];
2503 |
2504 | query = query.toLowerCase();
2505 |
2506 | function parse(items, parent) {
2507 | threads++;
2508 |
2509 | for (var key in items) {
2510 | if (excluded.indexOf(key) === -1) {
2511 | var item = items[key];
2512 |
2513 | if (item.component) {
2514 | //console.log(key, item.component);
2515 |
2516 | if (elements.indexOf(item.component) !== -1 && key.indexOf(query) !== -1) {
2517 | results[key] = Object.assign({}, item);
2518 | }
2519 | }
2520 |
2521 | if (typeof item === 'object') {
2522 | parse(item, items);
2523 | }
2524 | }
2525 | }
2526 |
2527 | threads--;
2528 |
2529 | if (threads === 0) {
2530 | callback(results);
2531 | }
2532 | }
2533 |
2534 | parse(object);
2535 | };
2536 |
--------------------------------------------------------------------------------