├── .eslintrc.json ├── .gitattributes ├── .github └── workflows │ ├── issue_stale.yml │ └── lint.yml ├── .gitignore ├── .husky └── pre-commit ├── .npmrc ├── .nvmrc ├── .prettierrc.json ├── CHANGELOG.md ├── LICENSE ├── README.md ├── assets ├── images │ ├── timer.png │ └── timer_long.png └── js │ ├── service.js │ └── syotimer.examples.js ├── build ├── jquery.syotimer.d.ts ├── jquery.syotimer.js ├── jquery.syotimer.min.js └── jquery.syotimer.min.js.map ├── index.d.ts ├── index.html ├── package-lock.json ├── package.json ├── resources └── default.css ├── rollup.config.mjs ├── source ├── SyoTimer.ts ├── constants.ts ├── index.ts ├── localization.ts ├── types.ts ├── utils.spec.ts └── utils.ts ├── tsconfig.json ├── tsconfig.lib.json ├── tsconfig.spec.json └── vite.config.ts /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es2021": true, 5 | "jquery": true 6 | }, 7 | "extends": ["airbnb-base", "airbnb-typescript/base", "prettier"], 8 | "parser": "@typescript-eslint/parser", 9 | "parserOptions": { 10 | "ecmaVersion": 12, 11 | "sourceType": "module", 12 | "project": "./tsconfig.*?.json" 13 | }, 14 | "plugins": ["@typescript-eslint", "prettier"], 15 | "rules": { 16 | "prettier/prettier": "error" 17 | }, 18 | "overrides": [ 19 | { 20 | "files": "{rollup.config.mjs,vite.config.ts}", 21 | "rules": { 22 | "import/no-extraneous-dependencies": [ 23 | "error", 24 | { 25 | "devDependencies": true, 26 | "optionalDependencies": false 27 | } 28 | ] 29 | } 30 | } 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | 3 | build/* text -diff 4 | yarn.lock text -diff 5 | package-lock.json text -diff 6 | -------------------------------------------------------------------------------- /.github/workflows/issue_stale.yml: -------------------------------------------------------------------------------- 1 | name: Stale 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | # This runs every day 20 minutes before midnight: https://crontab.guru/#40_23_*_*_* 7 | - cron: '40 23 * * *' 8 | 9 | jobs: 10 | stale: 11 | runs-on: ubuntu-latest 12 | if: github.repository_owner == 'mrfratello' 13 | permissions: 14 | issues: write 15 | pull-requests: write 16 | 17 | steps: 18 | - uses: actions/stale@v9 19 | name: 'Close stale issues' 20 | with: 21 | stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days.' 22 | stale-pr-message: 'This PR is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days.' 23 | close-issue-message: 'This issue was closed because it has been stalled for 7 days with no activity.' 24 | close-pr-message: 'This PR was closed because it has been stalled for 7 days with no activity.' 25 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | 9 | jobs: 10 | main: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: get sources 14 | uses: actions/checkout@v4 15 | with: 16 | fetch-depth: 0 17 | - name: node version 18 | id: node_info 19 | run: echo "version=$(cat .nvmrc)" >> $GITHUB_OUTPUT 20 | shell: bash 21 | - name: setup node lts version 22 | uses: actions/setup-node@v3 23 | with: 24 | node-version: '${{ steps.node_info.outputs.version }}' 25 | - name: install dependencies 26 | run: npm ci 27 | shell: bash 28 | 29 | - name: lint 30 | run: npm run lint 31 | - name: test 32 | run: npm run test 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | Thumbs.db 3 | node_modules/ 4 | .idea/ 5 | npm-debug.log 6 | tmp/ -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npm run lint 5 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | save-exact=true 2 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | lts/hydrogen -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/prettierrc", 3 | "printWidth": 100, 4 | "singleQuote": true, 5 | "trailingComma": "all" 6 | } 7 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | ### [3.1.2](https://github.com/mrfratello/SyoTimer/compare/v3.1.1...v3.1.2) (2024-02-25) 6 | 7 | ### [3.1.1](https://github.com/mrfratello/SyoTimer/compare/v3.1.0...v3.1.1) (2021-09-15) 8 | 9 | ## [3.1.0](https://github.com/mrfratello/SyoTimer/compare/v3.0.0...v3.1.0) (2021-09-10) 10 | 11 | 12 | ### Features 13 | 14 | * add typescript and refactor source structure ([b1398c5](https://github.com/mrfratello/SyoTimer/commit/b1398c59978a2c91ae13f6aff29feade7b5d527f)) 15 | 16 | 17 | ### Bug Fixes 18 | 19 | * use correct font types in default styles ([ffb3a78](https://github.com/mrfratello/SyoTimer/commit/ffb3a78f435bb3c764d39dbf80fe954200353958)) 20 | 21 | ## [3.0.0](https://github.com/mrfratello/SyoTimer/compare/v2.1.3...v3.0.0) (2021-08-31) 22 | 23 | 24 | ### ⚠ BREAKING CHANGES 25 | 26 | * `$.syotimerLang[lang].handler` must be function with two arguments 27 | * API Changed: 28 | 29 | * use date (number, Date) property instead year, month, day, hour, minute, second props 30 | * remove properties timeZone and ignoreTransferTime 31 | 32 | ### Features 33 | 34 | * change api, update exaples ([d1abea1](https://github.com/mrfratello/SyoTimer/commit/d1abea14432e6fb4e86cbf8cc2499dc0eeb17e67)) 35 | * change localization api ([cdd3436](https://github.com/mrfratello/SyoTimer/commit/cdd34366b18564f1880f53f3479f51cbd764e1ce)) 36 | 37 | ### [2.1.1](https://github.com/mrfratello/SyoTimer/compare/v2.0.0...v2.1.1) (2019-10-17) 38 | 39 | ### Features 40 | 41 | * publish on npm 42 | * used universal module definition 43 | * added default CSS styles 44 | 45 | ### [2.0.0](https://github.com/mrfratello/SyoTimer/compare/v1.1.0...v2.0.0) (2017-06-24) 46 | 47 | ### Features 48 | 49 | * redesigned the structure of a plugin 50 | * `effectType` applies to all units 51 | * added possibility to sets an order of layout of units of the timer 52 | * added possibility to add new language 53 | * rename CSS classes by BEM methodology 54 | 55 | ### 1.1.0 (2016-07-30) 56 | 57 | ### Features 58 | 59 | * added time zone support 60 | * added support of the time transfer on summer/winter time 61 | * added methods support 62 | * added method of set value to option 63 | * added minified version of plugin 64 | 65 | ### 1.0.1 (2015-02-24) 66 | 67 | ### Features 68 | 69 | * added option for change effect of counting 70 | * added documentation 71 | * added examples 72 | 73 | ### 1.0.0 (2014-12-10) 74 | 75 | ### Features 76 | 77 | * first use timer on real web-site 78 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [year] [fullname] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jQuery SyoTimer Plugin 2 | 3 | jQuery plugin of countdown on html page 4 | 5 | ## Demo 6 | 7 | [Examples of usage jQuery SyoTimer Plugin](https://mrfratello.github.io/SyoTimer) 8 | 9 | ## Features 10 | 11 | - Periodic counting with the specified period 12 | - Effects of change of indications of the countdown 13 | - The correct declension of nouns next to numeral numerals 14 | - An opportunity to add the language of countdown signatures which isn't included in the standard version of the plugin 15 | - Callback after the end of the countdown timer with the possibility of changing the structure of the timer 16 | - Custom formatting and styling timer 17 | 18 | ## Installing 19 | 20 | In a browser. Need download the [latest release](https://github.com/mrfratello/syotimer/releases/latest). And include the JavaScript file which you can find in the `build` folder: 21 | 22 | ```html 23 | 24 | 25 | ``` 26 | 27 | Using npm: 28 | 29 | ``` 30 | $ npm install jquery-syotimer 31 | ``` 32 | 33 | Using yarn: 34 | 35 | ``` 36 | $ yarn add jquery-syotimer 37 | ``` 38 | 39 | ## Usage 40 | 41 | Syotimer plugin can be integrated with plain JavaScript or with different module loaders. 42 | 43 | Script Tag: 44 | 45 | ```html 46 | 51 | ``` 52 | 53 | Common JS: 54 | 55 | ```javascript 56 | const $ = require("jquery"); 57 | require("jquery-syotimer"); 58 | 59 | $(".selector_to_countdown").syotimer(); 60 | ``` 61 | 62 | Bundlers (Webpack, etc): 63 | 64 | ```javascript 65 | import $ from "jquery"; 66 | import "jquery-syotimer"; 67 | 68 | $(".selector_to_countdown").syotimer(); 69 | ``` 70 | 71 | ## Markup 72 | 73 | Classes is named by [BEM methodology](https://en.bem.info/methodology/naming-convention/) 74 | 75 | ```html 76 |
The countdown is finished 00:00 2000.12.31
'); 21 | syotimer.headBlock.html('The countdown is finished!
'); 96 | }, 97 | itemTypes: ['day', 'hour', 'minute', 'second'], 98 | itemsHas: $$1.extend({}, defaultItemsHas), 99 | }; 100 | 101 | /** 102 | * Determine a unit of period in milliseconds 103 | */ 104 | function getPeriodUnit(periodUnit) { 105 | switch (periodUnit) { 106 | case 'd': 107 | case DAY: 108 | return DAY_IN_SEC; 109 | case 'h': 110 | case HOUR: 111 | return HOUR_IN_SEC; 112 | case 'm': 113 | case MINUTE: 114 | return MINUTE_IN_SEC; 115 | case 's': 116 | case SECOND: 117 | default: 118 | return 1; 119 | } 120 | } 121 | /** 122 | * Formation of numbers with leading zeros 123 | */ 124 | function format2(numb, isUse) { 125 | return numb <= 9 && !!isUse ? "0".concat(numb) : String(numb); 126 | } 127 | function getItemTypesByLayout(layout) { 128 | var itemTypes = []; 129 | for (var i = 0; i < layout.length; i += 1) { 130 | itemTypes.push(LAYOUT_TYPES[layout[i]]); 131 | } 132 | return itemTypes; 133 | } 134 | /** 135 | * Getting count of units to deadline 136 | */ 137 | function getUnitsToDeadLine(secondsToDeadLine) { 138 | var remainsSeconds = secondsToDeadLine; 139 | var unit = DAY; 140 | var unitsToDeadLine = { 141 | day: 0, 142 | hour: 0, 143 | minute: 0, 144 | second: 0, 145 | }; 146 | do { 147 | var unitInMilliSec = getPeriodUnit(unit); 148 | unitsToDeadLine[unit] = Math.floor(remainsSeconds / unitInMilliSec); 149 | remainsSeconds %= unitInMilliSec; 150 | // eslint-disable-next-line no-cond-assign 151 | } while ((unit = unitLinkedList.prev(unit))); 152 | return unitsToDeadLine; 153 | } 154 | /** 155 | * Return once cell DOM of countdown: day, hour, minute, second 156 | */ 157 | function getTimerItem() { 158 | var timerCellValue = $('', { 159 | class: 'syotimer-cell__value', 160 | text: '0', 161 | }); 162 | var timerCellUnit = $('', { class: 'syotimer-cell__unit' }); 163 | var timerCell = $('', { class: 'syotimer-cell' }); 164 | timerCell.append(timerCellValue).append(timerCellUnit); 165 | return timerCell; 166 | } 167 | /** 168 | * Getting count of seconds to deadline 169 | */ 170 | function getSecondsToDeadLine(differenceInMilliSec, options) { 171 | var differenceInSeconds = differenceInMilliSec / 1000; 172 | differenceInSeconds = Math.floor(differenceInSeconds); 173 | if (!options.periodic) 174 | return differenceInSeconds; 175 | var differenceInUnit; 176 | var periodUnitInSeconds = getPeriodUnit(options.periodUnit); 177 | var fullTimeUnitsBetween = differenceInMilliSec / (periodUnitInSeconds * 1000); 178 | fullTimeUnitsBetween = Math.ceil(fullTimeUnitsBetween); 179 | fullTimeUnitsBetween = Math.abs(fullTimeUnitsBetween); 180 | if (differenceInSeconds >= 0) { 181 | differenceInUnit = fullTimeUnitsBetween % options.periodInterval; 182 | differenceInUnit = differenceInUnit === 0 ? options.periodInterval : differenceInUnit; 183 | differenceInUnit -= 1; 184 | } 185 | else { 186 | differenceInUnit = options.periodInterval - (fullTimeUnitsBetween % options.periodInterval); 187 | } 188 | var additionalInUnit = differenceInSeconds % periodUnitInSeconds; 189 | // fix когда дедлайн раньше текущей даты, 190 | // возникает баг с неправильным расчетом интервала при different пропорциональной periodUnit 191 | if (additionalInUnit === 0 && differenceInSeconds < 0) { 192 | differenceInUnit -= 1; 193 | } 194 | var secondsToDeadLine = Math.abs(differenceInUnit * periodUnitInSeconds + additionalInUnit); 195 | return secondsToDeadLine; 196 | } 197 | /** 198 | * Universal function for get correct inducement of nouns after a numeral (`number`) 199 | */ 200 | var universal = function (n, words) { return (n === 1 ? words[0] : words[1]); }; 201 | /** 202 | * Getting the correct declension of words after numerals 203 | */ 204 | function getNumeral(n, lang, unit) { 205 | var handler = $.syotimerLang[lang].handler || universal; 206 | var words = $.syotimerLang[lang][unit]; 207 | return handler(n, words); 208 | } 209 | 210 | var SyoTimer = /** @class */ (function () { 211 | function SyoTimer(element, options) { 212 | this.element = $$1(element); 213 | this.element.data('syotimer-options', options); 214 | this.render(); 215 | } 216 | /** 217 | * Rendering base elements of countdown 218 | * @private 219 | */ 220 | SyoTimer.prototype.render = function () { 221 | var options = this.element.data('syotimer-options'); 222 | var timerItem = getTimerItem(); 223 | var headBlock = $$1('', { class: 'syotimer__head' }).html(options.headTitle); 224 | var bodyBlock = $$1('', { class: 'syotimer__body' }); 225 | var footBlock = $$1('', { class: 'syotimer__footer' }).html(options.footTitle); 226 | var itemBlocks = {}; 227 | for (var i = 0; i < options.itemTypes.length; i += 1) { 228 | var item = timerItem.clone(); 229 | item.addClass("syotimer-cell_type_".concat(options.itemTypes[i])); 230 | bodyBlock.append(item); 231 | itemBlocks[options.itemTypes[i]] = item; 232 | } 233 | var timerBlocks = { headBlock: headBlock, bodyBlock: bodyBlock, footBlock: footBlock }; 234 | this.element 235 | .data('syotimer-blocks', timerBlocks) 236 | .data('syotimer-items', itemBlocks) 237 | .addClass('syotimer') 238 | .append(headBlock) 239 | .append(bodyBlock) 240 | .append(footBlock); 241 | }; 242 | /** 243 | * Handler called per seconds while countdown is not over 244 | */ 245 | SyoTimer.prototype.tick = function () { 246 | var options = this.element.data('syotimer-options'); 247 | $$1('.syotimer-cell > .syotimer-cell__value', this.element).css('opacity', 1); 248 | var currentTime = new Date().getTime(); 249 | var deadLineTime = options.date instanceof Date ? options.date.getTime() : options.date; 250 | var differenceInMilliSec = deadLineTime - currentTime; 251 | var secondsToDeadLine = getSecondsToDeadLine(differenceInMilliSec, options); 252 | if (secondsToDeadLine >= 0) { 253 | this.refreshUnitsDom(secondsToDeadLine); 254 | this.applyEffectSwitch(options.effectType); 255 | } 256 | else { 257 | var elementBox = $$1.extend(this.element, this.element.data('syotimer-blocks')); 258 | options.afterDeadline(elementBox); 259 | } 260 | }; 261 | /** 262 | * Refresh unit DOM of countdown 263 | * @private 264 | */ 265 | SyoTimer.prototype.refreshUnitsDom = function (secondsToDeadLine) { 266 | var options = this.element.data('syotimer-options'); 267 | var itemBlocks = this.element.data('syotimer-items'); 268 | var unitList = options.itemTypes; 269 | var unitsToDeadLine = getUnitsToDeadLine(secondsToDeadLine); 270 | if (!options.itemsHas.day) { 271 | unitsToDeadLine.hour += unitsToDeadLine.day * 24; 272 | } 273 | if (!options.itemsHas.hour) { 274 | unitsToDeadLine.minute += unitsToDeadLine.hour * 60; 275 | } 276 | if (!options.itemsHas.minute) { 277 | unitsToDeadLine.second += unitsToDeadLine.minute * 60; 278 | } 279 | for (var i = 0; i < unitList.length; i += 1) { 280 | var unit = unitList[i]; 281 | var unitValue = unitsToDeadLine[unit]; 282 | var itemBlock = itemBlocks[unit]; 283 | itemBlock.data('syotimer-unit-value', unitValue); 284 | $$1('.syotimer-cell__value', itemBlock).html(format2(unitValue, unit !== DAY ? options.doubleNumbers : false)); 285 | $$1('.syotimer-cell__unit', itemBlock).html(getNumeral(unitValue, options.lang, unit)); 286 | } 287 | }; 288 | /** 289 | * Applying effect of changing numbers 290 | * @private 291 | */ 292 | SyoTimer.prototype.applyEffectSwitch = function (effectType, unit) { 293 | var _this = this; 294 | if (unit === void 0) { unit = SECOND; } 295 | switch (effectType) { 296 | case 'opacity': { 297 | var itemBlocks = this.element.data('syotimer-items'); 298 | var unitItemBlock = itemBlocks[unit]; 299 | if (unitItemBlock) { 300 | var nextUnit = unitLinkedList.next(unit); 301 | var unitValue = unitItemBlock.data('syotimer-unit-value'); 302 | $$1('.syotimer-cell__value', unitItemBlock).animate({ opacity: 0.1 }, 1000, 'linear', function () { 303 | return _this.tick(); 304 | }); 305 | if (nextUnit && unitValue === 0) { 306 | this.applyEffectSwitch(effectType, nextUnit); 307 | } 308 | } 309 | return; 310 | } 311 | case 'none': 312 | default: { 313 | setTimeout(function () { return _this.tick(); }, 1000); 314 | } 315 | } 316 | }; 317 | return SyoTimer; 318 | }()); 319 | function mapSyoTimer(elements, inputOptions) { 320 | var options = $$1.extend({}, defaultOptions, inputOptions || {}); 321 | options.itemTypes = getItemTypesByLayout(options.layout); 322 | options.itemsHas = $$1.extend({}, defaultItemsHas); 323 | for (var i = 0; i < options.itemTypes.length; i += 1) { 324 | options.itemsHas[options.itemTypes[i]] = true; 325 | } 326 | return elements.each(function init() { 327 | var timer = new SyoTimer(this, options); 328 | timer.tick(); 329 | }); 330 | } 331 | 332 | var methods = { 333 | setOption: function (name, value) { 334 | var elementBox = $$1(this); 335 | var options = elementBox.data('syotimer-options'); 336 | if (Object.prototype.hasOwnProperty.call(options, name)) { 337 | options[name] = value; 338 | elementBox.data('syotimer-options', options); 339 | } 340 | }, 341 | }; 342 | $$1.fn.extend({ 343 | syotimer: function (options, property, value) { 344 | if (typeof options === 'string' && options === 'setOption') { 345 | return this.each(function method() { 346 | methods[options].apply(this, [property, value]); 347 | }); 348 | } 349 | if (options === null || options === undefined || typeof options === 'object') { 350 | return mapSyoTimer(this, options); 351 | } 352 | return $$1.error('SyoTimer. Error in call methods: methods is not exist'); 353 | }, 354 | }); 355 | 356 | })(jQuery); 357 | -------------------------------------------------------------------------------- /build/jquery.syotimer.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * SyoTimer v.3.1.1 | under MIT license 3 | * https://mrfratello.github.io/SyoTimer 4 | */ 5 | !function(e){"use strict";e.syotimerLang={rus:{second:["секунда","секунды","секунд"],minute:["минута","минуты","минут"],hour:["час","часа","часов"],day:["день","дня","дней"],handler:function(e,t){return e%100>4&&e%100<20?t[2]:t[[2,0,1,1,1,2][e%10<5?e%10:5]]}},eng:{second:["second","seconds"],minute:["minute","minutes"],hour:["hour","hours"],day:["day","days"]},por:{second:["segundo","segundos"],minute:["minuto","minutos"],hour:["hora","horas"],day:["dia","dias"]},spa:{second:["segundo","segundos"],minute:["minuto","minutos"],hour:["hora","horas"],day:["día","días"]},heb:{second:["שניה","שניות"],minute:["דקה","דקות"],hour:["שעה","שעות"],day:["יום","ימים"]}};var t="day",i="hour",n="minute",o="second",s=86400,r=3600,a=60,d={d:t,h:i,m:n,s:o},l={list:[o,n,i,t],next:function(e){var t=this.list.indexOf(e);return tThe countdown is finished!
')},itemTypes:["day","hour","minute","second"],itemsHas:e.extend({},u)};function m(e){switch(e){case"d":case t:return s;case"h":case i:return r;case"m":case n:return a;default:return 1}}var h=function(e,t){return 1===e?t[0]:t[1]};function y(e,t,i){return($.syotimerLang[t].handler||h)(e,$.syotimerLang[t][i])}var p=function(){function i(t,i){this.element=e(t),this.element.data("syotimer-options",i),this.render()}return i.prototype.render=function(){for(var t,i,n,o=this.element.data("syotimer-options"),s=(t=$("",{class:"syotimer-cell__value",text:"0"}),i=$("",{class:"syotimer-cell__unit"}),(n=$("",{class:"syotimer-cell"})).append(t).append(i),n),r=e("",{class:"syotimer__head"}).html(o.headTitle),a=e("",{class:"syotimer__body"}),d=e("",{class:"syotimer__footer"}).html(o.footTitle),l={},u=0;uThe countdown is finished!
');\n },\n itemTypes: ['day', 'hour', 'minute', 'second'],\n itemsHas: $.extend({}, defaultItemsHas),\n};\n","import {\n DAY,\n HOUR,\n MINUTE,\n SECOND,\n DAY_IN_SEC,\n HOUR_IN_SEC,\n MINUTE_IN_SEC,\n LAYOUT_TYPES,\n unitLinkedList,\n} from './constants';\nimport type { LanguageHandler, SyoTimerInternalOptions, Unit, UnitLong, UnitShort } from './types';\n\n/**\n * Determine a unit of period in milliseconds\n */\nfunction getPeriodUnit(periodUnit: Unit) {\n switch (periodUnit) {\n case 'd':\n case DAY:\n return DAY_IN_SEC;\n case 'h':\n case HOUR:\n return HOUR_IN_SEC;\n case 'm':\n case MINUTE:\n return MINUTE_IN_SEC;\n case 's':\n case SECOND:\n default:\n return 1;\n }\n}\n\n/**\n * Formation of numbers with leading zeros\n */\nexport function format2(numb: number, isUse?: boolean) {\n return numb <= 9 && !!isUse ? `0${numb}` : String(numb);\n}\n\nexport function getItemTypesByLayout(layout: string) {\n const itemTypes = [] as UnitLong[];\n for (let i = 0; i < layout.length; i += 1) {\n itemTypes.push(LAYOUT_TYPES[layout[i] as UnitShort]);\n }\n return itemTypes;\n}\n\n/**\n * Getting count of units to deadline\n */\nexport function getUnitsToDeadLine(secondsToDeadLine: number) {\n let remainsSeconds = secondsToDeadLine;\n let unit: UnitLong | null = DAY;\n const unitsToDeadLine: Record/* Simple Timer. The countdown to 20:30 2035.05.09 */ 111 | $("#simple-timer").syotimer({ 112 | date: new Date(2035, 4, 9, 20, 30), 113 | }); 114 |115 |
/* Timer with Head and Foot. Countdown is over */ 122 | $("#expired-timer").syotimer({ 123 | date: new Date(1990, 0), 124 | headTitle: "<h3>Timer with header and footer. Countdown is over</h3>", 125 | footTitle: '<i style="color: brown;">Footer of timer.</i>', 126 | }); 127 |128 |
/* Callback after the end of the countdown timer */ 135 | $("#expired-timer_event").syotimer({ 136 | date: new Date(2000, 11, 31), 137 | headTitle: "<h3>Timer with header and footer. Countdown is over</h3>", 138 | footTitle: '<i style="color: brown;">Footer of timer.</i>', 139 | afterDeadline: function (syotimer) { 140 | syotimer.bodyBlock.html( 141 | "<p>The countdown is finished 00:00 2000.12.31</p>" 142 | ); 143 | syotimer.headBlock.html( 144 | "<h3>Callback after the end of the countdown timer</h3>" 145 | ); 146 | syotimer.footBlock.html( 147 | '<em style="color:brown;">' + 148 | "Footer of timer after countdown is finished" + 149 | "</em>" 150 | ); 151 | }, 152 | }); 153 |154 |
/* Periodic Timer. Period is equal 3 minutes. Effect of fading in */ 164 | $("#periodic-timer_period_minutes").syotimer({ 165 | date: new Date(2015, 0, 1), 166 | layout: "hms", 167 | doubleNumbers: false, 168 | effectType: "opacity", 169 | 170 | periodUnit: "m", 171 | periodic: true, 172 | periodInterval: 3, 173 | }); 174 |175 |
The date equal 20:00 2015.01.01
182 | 183 | 184 |/* Periodic Timer. Period is equal 10 days */ 187 | $("#periodic-timer_period_days").syotimer({ 188 | date: new Date(2015, 0, 1, 20), 189 | layout: "hms", 190 | periodic: true, 191 | periodInterval: 10, 192 | periodUnit: "d", 193 | }); 194 |195 |
Demonstrate layout. Period is equal 2 hours.
200 | 201 | 202 |/* Demonstrate layout. Period is equal 2 hours. Display only seconds */ 205 | $("#layout-timer_only-seconds").syotimer({ 206 | layout: "s", 207 | periodic: true, 208 | periodInterval: 2, 209 | periodUnit: "h", 210 | }); 211 |212 |
Demonstrate layout. Period is equal 2 days and 5 hours.
217 | 218 | 219 |/* Demonstrate layout. Period is equal 2 days and 5 hours. 222 | Units of countdown in reverse order */ 223 | $("#layout-timer_reversed-units").syotimer({ 224 | layout: "smhd", 225 | effectType: "opacity", 226 | 227 | periodic: true, 228 | periodInterval: 53, 229 | periodUnit: "h", 230 | }); 231 |232 |
237 | Demonstrate layout. Period is equal 1 days, 5 hours and 37 minutes. 238 |
239 | 240 | 241 |/* Demonstrate layout. Period is equal 2 days and 5 hours. 244 | Display only days and minutes in reverse order */ 245 | $("#layout-timer_mixed-units").syotimer({ 246 | layout: "md", 247 | 248 | periodic: true, 249 | periodInterval: 1777, 250 | periodUnit: "m", 251 | }); 252 |253 |
The deadline is 18:00:00 by the time Rome, Italy (UTC+2)
258 | 259 | 260 |/* Periodic Timer. Countdown timer with given time zone */ 263 | $("#periodic-timer_timezone_given").syotimer({ 264 | date: new Date("2000-07-01T18:00:00.000+02:00"), 265 | layout: "hms", 266 | 267 | periodic: true, 268 | periodInterval: 1, 269 | periodUnit: "d", 270 | }); 271 |272 |
/** 304 | * Periodic Timer. 305 | * Change options: doubleNumbers, effect type, language 306 | */ 307 | var changeOptionsTimer = $('#periodic-timer_change-options'); 308 | var effectTypeEl = $('#select-effect'); 309 | var formatNumberEl = $('#select-format-number'); 310 | var languageEl = $('#select-language'); 311 | 312 | changeOptionsTimer.syotimer({ 313 | periodic: true, 314 | periodInterval: 10, 315 | periodUnit: 'd', 316 | }); 317 | 318 | effectTypeEl.on('change', function () { 319 | var effectType = $('option:selected', this).val(); 320 | changeOptionsTimer.syotimer('setOption', 'effectType', effectType); 321 | }); 322 | 323 | formatNumberEl.on('change', function () { 324 | var formatNumberValue = $('option:selected', this).val(); 325 | var doubleNumbers = formatNumberValue === 'true'; 326 | changeOptionsTimer.syotimer('setOption', 'doubleNumbers', doubleNumbers); 327 | }); 328 | 329 | languageEl.on('change', function () { 330 | var language = $('option:selected', this).val(); 331 | changeOptionsTimer.syotimer('setOption', 'lang', language); 332 | });333 |
Demonstrate adding the new language of signatures.
338 | 339 |340 |357 | 358 |341 | Nenglish is a synthetic language. It is very similar to English but there are significant 342 | differences in the spelling of nouns after numerals. Namely, the difference in the 343 | suffixes of these nouns: 344 |
345 |346 |
356 |- 347 | if the number ends with the digit
350 |1
then to the noun added the suffix "one" 348 | (21 secondone, 1 minuteone, ...); 349 |- 351 | if the number ends with the digit
354 |5
then the suffix is equal "five" (35 352 | hourfive, 5 secondfive); 353 |- otherwise the suffix is equal to "s" (24 minutes, 3 days).
355 |
/** 359 | * Localization in timer. 360 | * Add new language 361 | */ 362 | 363 | // Adding of a words for signatures of countdown 364 | $.syotimerLang.neng = { 365 | second: ["secondone", "secondfive", "seconds"], 366 | minute: ["minuteone", "minutefive", "minutes"], 367 | hour: ["hourone", "hourfive", "hours"], 368 | day: ["dayone", "dayfive", "days"], 369 | // Adding of the handler that selects an index from the list of words 370 | // based on ahead the going number 371 | handler: function nengNumeral(number, words) { 372 | var lastDigit = number % 10; 373 | var index = 2; 374 | if (lastDigit === 1) { 375 | index = 0; 376 | } else if (lastDigit === 5) { 377 | index = 1; 378 | } 379 | return words[index]; 380 | }, 381 | }; 382 | 383 | $("#periodic-timer_localization_new-english").syotimer({ 384 | lang: "neng", 385 | layout: "ms", 386 | 387 | periodic: true, 388 | periodInterval: 6, 389 | periodUnit: "m", 390 | }); 391 |392 |
The countdown is finished!
'); 50 | }, 51 | itemTypes: ['day', 'hour', 'minute', 'second'], 52 | itemsHas: $.extend({}, defaultItemsHas), 53 | }; 54 | -------------------------------------------------------------------------------- /source/index.ts: -------------------------------------------------------------------------------- 1 | import $ from 'jquery'; 2 | import './localization'; 3 | import mapSyoTimer from './SyoTimer'; 4 | import type { 5 | SyoTimerOptions, 6 | SyoTimerMethods, 7 | SyoTimerOptionProps, 8 | SyoTimerOptionValues, 9 | } from './types'; 10 | 11 | const methods: Record