long list of timezones
This commit is contained in:
		
							parent
							
								
									4c986119f9
								
							
						
					
					
						commit
						0c6003a894
					
				
							
								
								
									
										13
									
								
								public/ajquery.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								public/ajquery.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | ||||
| 'use strict'; | ||||
| 
 | ||||
| var $ = function(sel, el) { | ||||
| 	return (el || window.document).querySelector(sel); | ||||
| }; | ||||
| $.create = function(html) { | ||||
| 	var div = document.createElement('div'); | ||||
| 	div.innerHTML = html; | ||||
| 	return div; | ||||
| }; | ||||
| var $$ = function(sel, el) { | ||||
| 	return (el || window.document).querySelectorAll(sel); | ||||
| }; | ||||
							
								
								
									
										301
									
								
								public/hooks.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										301
									
								
								public/hooks.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,301 @@ | ||||
| (function() { | ||||
| 	'use strict'; | ||||
| 
 | ||||
| 	// AJ Query
 | ||||
| 	var $ = window.$; | ||||
| 	var $$ = window.$$; | ||||
| 
 | ||||
| 	var state = {}; | ||||
| 
 | ||||
| 	var $grantTpl; | ||||
| 	var $devTpl; | ||||
| 	var $updateTpl; | ||||
| 	var $headerTpl; | ||||
| 	var $webhookTpl; | ||||
| 	var $webhookHeaderTpl; | ||||
| 
 | ||||
| 	// TODO add offset based on date selected (i.e. MDT -0500)
 | ||||
| 	var tzdb = [ | ||||
| 		'America/New_York', | ||||
| 		'America/Chicago', | ||||
| 		'America/Denver', | ||||
| 		'America/Phoenix', | ||||
| 		'America/Los_Angeles', | ||||
| 		'America/Sao_Paulo', | ||||
| 		'Europe/London', | ||||
| 		'Europe/Berlin', | ||||
| 		'Europe/Moscow', | ||||
| 		'Asia/Dubai', | ||||
| 		'Asia/Kolkata', | ||||
| 		'Asia/Hong_Kong', | ||||
| 		'Asia/Tokyo', | ||||
| 		'Pacific/Auckland', | ||||
| 		'Australia/Sydney' | ||||
| 	]; | ||||
| 
 | ||||
| 	function run() { | ||||
| 		$headerTpl = $('.js-new-webhook .js-header').outerHTML; | ||||
| 
 | ||||
| 		$webhookHeaderTpl = $('.js-schedule .js-webhook .js-header').outerHTML; | ||||
| 		$('.js-schedule .js-webhooks .js-headers').innerHTML = ''; | ||||
| 		$webhookTpl = $('.js-schedule .js-webhook').outerHTML; | ||||
| 		$('.js-schedule .js-webhooks').innerHTML = ''; | ||||
| 
 | ||||
| 		// after blanking all inner templates
 | ||||
| 		$devTpl = $('.js-schedule').outerHTML; | ||||
| 
 | ||||
| 		console.log('hello'); | ||||
| 
 | ||||
| 		$('body').addEventListener('click', function(ev) { | ||||
| 			if (ev.target.matches('.js-new-header')) { | ||||
| 				newWebhookHeader(ev.target); | ||||
| 			} else if (ev.target.matches('.js-rm-header')) { | ||||
| 				rmWebhookHeader(ev.target); | ||||
| 			} else if ( | ||||
| 				ev.target.matches('.js-delete') && | ||||
| 				ev.target.closest('.js-grant') | ||||
| 			) { | ||||
| 				deleteGrant(ev.target.closest('.js-grant')); | ||||
| 			} else if ( | ||||
| 				ev.target.matches('.js-delete') && | ||||
| 				ev.target.closest('.js-webhook') | ||||
| 			) { | ||||
| 				deleteWebhook(ev.target.closest('.js-webhook')); | ||||
| 			} else { | ||||
| 				return; | ||||
| 			} | ||||
| 			ev.preventDefault(); | ||||
| 			ev.stopPropagation(); | ||||
| 		}); | ||||
| 
 | ||||
| 		$('body').addEventListener('submit', function(ev) { | ||||
| 			if (ev.target.matches('.js-new-schedule')) { | ||||
| 				newSchedule(ev.target); | ||||
| 			} else { | ||||
| 				return; | ||||
| 			} | ||||
| 			ev.preventDefault(); | ||||
| 			ev.stopPropagation(); | ||||
| 		}); | ||||
| 	} | ||||
| 
 | ||||
| 	function newSchedule() { | ||||
| 		var $hook = $('.js-new-webhook'); | ||||
| 		var deviceId = $hook.closest('.js-schedule').querySelector('.js-id').value; | ||||
| 		var hook = { | ||||
| 			comment: $('.js-comment', $hook).value, | ||||
| 			method: $('.js-method', $hook).value, | ||||
| 			url: $('.js-url', $hook).value, | ||||
| 			headers: {} | ||||
| 		}; | ||||
| 		$$('.js-header', $hook).forEach(function($head) { | ||||
| 			var key = $('.js-key', $head).value; | ||||
| 			var val = $('.js-value', $head).value; | ||||
| 			if (key && val) { | ||||
| 				hook.headers[key] = val; | ||||
| 			} | ||||
| 		}); | ||||
| 		hook.body = $('.js-body-template', $hook).value; | ||||
| 		// TODO update on template change and show preview
 | ||||
| 
 | ||||
| 		var opts = { | ||||
| 			method: 'POST', | ||||
| 			headers: { | ||||
| 				Accept: 'application/json', | ||||
| 				Authorization: JSON.parse(localStorage.getItem('session')).access_token, | ||||
| 				'Content-Type': 'application/json' | ||||
| 			}, | ||||
| 			body: JSON.stringify(hook), | ||||
| 			cors: true | ||||
| 		}; | ||||
| 
 | ||||
| 		/* | ||||
|                 state.account.devices | ||||
|                         .filter(function(d) { | ||||
|                                 return d.accessToken == deviceId; | ||||
|                         })[0] | ||||
|                         .webhooks.push(hook); | ||||
| 
 | ||||
|                 displayAccount(state.account); | ||||
|                 return; | ||||
|     */ | ||||
| 
 | ||||
| 		window | ||||
| 			.fetch('/api/iot/devices/' + deviceId + '/webhooks', opts) | ||||
| 			.then(function(resp) { | ||||
| 				return resp | ||||
| 					.json() | ||||
| 					.then(function(data) { | ||||
| 						if (!data.webhook) { | ||||
| 							throw new Error('something bad happened'); | ||||
| 							return; | ||||
| 						} | ||||
| 
 | ||||
| 						state.account.devices | ||||
| 							.filter(function(d) { | ||||
| 								return d.accessToken == deviceId; | ||||
| 							})[0] | ||||
| 							.webhooks.push(resp.data.webhook); | ||||
| 
 | ||||
| 						displayAccount(state.account); | ||||
| 					}) | ||||
| 					.catch(function(e) { | ||||
| 						window.alert(e.message); | ||||
| 					}); | ||||
| 			}); | ||||
| 	} | ||||
| 
 | ||||
| 	function newWebhookHeader($newHeader) { | ||||
| 		var $hs = $newHeader.closest('.js-headers'); | ||||
| 		var $h = $newHeader.closest('.js-header'); | ||||
| 		var $div = document.createElement('div'); | ||||
| 		$div.innerHTML = $headerTpl; | ||||
| 		$hs.append($('.js-header', $div)); | ||||
| 		$newHeader.hidden = true; | ||||
| 		$('.js-rm-header', $h).hidden = false; | ||||
| 		$('.js-key', $h).required = 'required'; | ||||
| 		$('.js-value', $h).required = 'required'; | ||||
| 	} | ||||
| 
 | ||||
| 	function rmWebhookHeader($rmHeader) { | ||||
| 		var $h = $rmHeader.closest('.js-header'); | ||||
| 		$h.parentElement.removeChild($h); | ||||
| 	} | ||||
| 	function deleteWebhook($hook) { | ||||
| 		var deviceId = $hook.closest('.js-schedule').querySelector('.js-id').value; | ||||
| 		var id = $('.js-id', $hook).innerText; | ||||
| 		var opts = { | ||||
| 			method: 'DELETE', | ||||
| 			headers: { | ||||
| 				Accept: 'application/json', | ||||
| 				Authorization: JSON.parse(localStorage.getItem('session')).access_token | ||||
| 			}, | ||||
| 			cors: true | ||||
| 		}; | ||||
| 		window | ||||
| 			.fetch('/api/iot/devices/' + deviceId + '/webhooks/' + id, opts) | ||||
| 			.then(function(resp) { | ||||
| 				return resp.json().then(function(result) { | ||||
| 					if (!result.webhook) { | ||||
| 						console.error(result); | ||||
| 						window.alert('something went wrong: ' + JSON.stringify(result)); | ||||
| 						return; | ||||
| 					} | ||||
| 					var index = -1; | ||||
| 					var dev = state.account.devices.filter(function(d, i) { | ||||
| 						return d.accessToken == deviceId; | ||||
| 					})[0]; | ||||
| 					dev.webhooks.some(function(g, i) { | ||||
| 						if (g.id === id) { | ||||
| 							index = i; | ||||
| 							return true; | ||||
| 						} | ||||
| 					}); | ||||
| 					if (index > -1) { | ||||
| 						dev.webhooks.splice(index, 1); | ||||
| 						displayAccount(state.account); | ||||
| 					} | ||||
| 				}); | ||||
| 			}); | ||||
| 	} | ||||
| 
 | ||||
| 	function displayAccount(data) { | ||||
| 		state.account = data; | ||||
| 		console.log('[debug] Display Account:'); | ||||
| 		console.log(data); | ||||
| 		var $devs = $('.js-schedules'); | ||||
| 		$devs.innerHTML = ''; | ||||
| 		data.devices.forEach(function(d) { | ||||
| 			var $dev = $.create($devTpl); | ||||
| 			$('.js-ieme', $dev).innerText = d.id; | ||||
| 			$('.js-id', $dev).value = d.accessToken; | ||||
| 			$('.js-update-url', $dev).innerText = d.updateUrl; | ||||
| 			d.webhooks.forEach(function(h) { | ||||
| 				var $hook = $.create($webhookTpl); | ||||
| 				$('.js-id', $hook).innerText = h.id; | ||||
| 				$('.js-comment', $hook).innerText = h.comment; | ||||
| 				$('.js-method', $hook).innerText = h.method; | ||||
| 				$('.js-url', $hook).innerText = h.url; | ||||
| 				Object.keys(h.headers).forEach(function(k) { | ||||
| 					var $header = $.create($webhookHeaderTpl); | ||||
| 					var v = h.headers[k]; | ||||
| 					$('.js-key', $header).innerText = k; | ||||
| 					$('.js-value', $header).innerText = v; | ||||
| 					$('.js-headers', $hook).innerHTML += $header.innerHTML; | ||||
| 				}); | ||||
| 				$('.js-body-template', $hook).innerText = h.body; | ||||
| 				$('.js-webhooks', $dev).innerHTML += $hook.innerHTML; | ||||
| 			}); | ||||
| 			d.grants.forEach(function(g) { | ||||
| 				var $grant = $.create($grantTpl); | ||||
| 				$('.js-id', $grant).innerText = g.id; | ||||
| 				$('.js-comment', $grant).innerText = g.comment; | ||||
| 				$('.js-token', $grant).innerText = g.token; | ||||
| 				//TODO Math.floor(Date.now() / 1000);
 | ||||
| 				var url = | ||||
| 					'https://test.therootcompany.com/api/v1/devices/' + | ||||
| 					d.accessToken + | ||||
| 					'/updates?since=' + | ||||
| 					0; | ||||
| 				$('.js-example-curl .js-example-url', $grant).innerText = url; | ||||
| 				$('.js-example-curl .js-example-token', $grant).innerText = g.token; | ||||
| 				$('.js-example-js .js-example-url', $grant).innerText = url; | ||||
| 				$('.js-example-js .js-example-id', $grant).innerText = d.accessToken; | ||||
| 				$('.js-example-js .js-example-token', $grant).innerText = g.token; | ||||
| 				$('.js-grants', $dev).innerHTML += $grant.innerHTML; | ||||
| 			}); | ||||
| 			d.updates.slice(0, 10).forEach(function(u) { | ||||
| 				var $update = $.create($updateTpl); | ||||
| 				$('.js-update-details', $update).innerText = JSON.stringify(u); | ||||
| 				$('.js-updates', $dev).innerHTML += $update.innerHTML; | ||||
| 			}); | ||||
| 			$devs.innerHTML += $dev.innerHTML; | ||||
| 		}); | ||||
| 	} | ||||
| 
 | ||||
| 	console.info('[tzdb] requesting'); | ||||
| 	window.fetch('./tzdb.json').then(function(resp) { | ||||
| 		return resp.json().then(function(tzdb) { | ||||
| 			console.info('[tzdb] received'); | ||||
| 			var tz = Intl.DateTimeFormat().resolvedOptions().timeZone; | ||||
| 			var options = $$('.js-schedule-tz option'); | ||||
| 			var valOpt = options[0].outerHTML; // UTC
 | ||||
| 			var spaceOpt = options[1].outerHTML; // ----
 | ||||
| 			var innerHTML = $('.js-schedule-tz').innerHTML; | ||||
| 			innerHTML = | ||||
| 				'<option selected value="' + | ||||
| 				tz + | ||||
| 				'">    ' + | ||||
| 				tz + | ||||
| 				'</option>' + | ||||
| 				spaceOpt + | ||||
| 				innerHTML.replace(/>UTC/, '>    UTC'); | ||||
| 			//$('.js-schedule-tz').innerHTML += spaceOpt;
 | ||||
| 			//$('.js-schedule-tz').innerHTML += valOpt.replace(/UTC/g, 'custom');
 | ||||
| 			Object.keys(tzdb) | ||||
| 				.sort() | ||||
| 				.forEach(function(k) { | ||||
| 					var parts = k.split(' '); | ||||
| 					//var sep = '── ' + parts[0];
 | ||||
| 					var sep = parts[0]; | ||||
| 					if (parts[0] !== parts[1]) { | ||||
| 						sep += ' / ' + parts[1] + ' (DST)'; | ||||
| 					} | ||||
| 					//innerHTML += '<option disabled>' + sep + '</option>';
 | ||||
| 					innerHTML += '<optgroup label="' + sep + '">'; | ||||
| 					var areas = tzdb[k]; | ||||
| 					areas.forEach(function(_tz) { | ||||
| 						if (tz !== _tz) { | ||||
| 							innerHTML += valOpt.replace(/UTC/g, _tz); | ||||
| 						} | ||||
| 					}); | ||||
| 					innerHTML += '</optgroup>'; | ||||
| 				}); | ||||
| 			$('.js-schedule-tz').innerHTML = innerHTML; | ||||
| 
 | ||||
| 			console.info('[tzdb] loaded'); | ||||
| 			run(); | ||||
| 		}); | ||||
| 	}); | ||||
| 	//window.addEventListener('load', run);
 | ||||
| })(); | ||||
| @ -4,7 +4,9 @@ | ||||
| 		<title>Go Again</title> | ||||
| 	</head> | ||||
| 	<body> | ||||
| 		<h1>Hello, World!</h1> | ||||
| 		<h1>Go Again</h1> | ||||
| 		<h2>Webhooks, on time!</h2> | ||||
| 
 | ||||
| 		<form class="js-schedules-list"> | ||||
| 			<label | ||||
| 				>Token: | ||||
| @ -12,33 +14,153 @@ | ||||
| 			</label> | ||||
| 			<button>See Schedules</button> | ||||
| 		</form> | ||||
| 		<pre><code class="js-schedules"> </code></pre> | ||||
| 
 | ||||
| 		<pre><code class="js-schedules-output"> </code></pre> | ||||
| 
 | ||||
| 		<div class="js-schedules"> | ||||
| 			<h2>Schedules</h2> | ||||
| 			<div class="js-schedule"> | ||||
| 				<form class="js-new-schedule"> | ||||
| 					<label>Date: <input type="date" required/></label> | ||||
| 					<br /> | ||||
| 					<label>Time: <input type="time" step="60" required/></label> | ||||
| 					<br /> | ||||
| 					<!-- TODO combo box --> | ||||
| 					<select class="js-schedule-tz"> | ||||
| 						<option value="UTC">UTC</option> | ||||
| 						<option disabled>──────────</option> | ||||
| 					</select> | ||||
| 					<br /> | ||||
| 
 | ||||
| 					<div class="doc-webhooks-container"> | ||||
| 						<h3>Webhook</h3> | ||||
| 						<div class="js-webhooks"> | ||||
| 							<div class="js-webhook"> | ||||
| 								<h4> | ||||
| 									<span class="js-comment"></span | ||||
| 									><button class="js-delete" type="button">Delete</button> | ||||
| 								</h4> | ||||
| 								<span class="js-id" hidden></span> | ||||
| 								<span class="js-method"></span> | ||||
| 								<span class="js-url"></span> | ||||
| 								<br /> | ||||
| 								<div class="js-headers"> | ||||
| 									<div class="js-header"> | ||||
| 										<span class="js-key"></span> | ||||
| 										<span class="js-value"></span> | ||||
| 									</div> | ||||
| 								</div> | ||||
| 								<pre><code class="js-body-template"></code></pre> | ||||
| 							</div> | ||||
| 						</div> | ||||
| 						<div class="js-new-webhook"> | ||||
| 							<select class="js-template"> | ||||
| 								<option value="" selected>Custom</option> | ||||
| 								<option value="dweet-v2">Dweet v2</option> | ||||
| 							</select> | ||||
| 							<br /> | ||||
| 							<input | ||||
| 								class="js-comment" | ||||
| 								type="text" | ||||
| 								placeholder="Webhook Name" | ||||
| 								required | ||||
| 							/> | ||||
| 							<br /> | ||||
| 							<select class="js-method"> | ||||
| 								<option value="POST" selected>POST</option> | ||||
| 								<option value="PUT">PUT</option> | ||||
| 							</select> | ||||
| 							<input | ||||
| 								placeholder="https://example.com/api/v1/updates" | ||||
| 								class="js-url" | ||||
| 								type="url" | ||||
| 								required | ||||
| 							/> | ||||
| 							<div class="js-headers"> | ||||
| 								<div class="js-header"> | ||||
| 									<input placeholder="Header" class="js-key" type="text" /> | ||||
| 									<input placeholder="Value" class="js-value" type="text" /> | ||||
| 									<button type="button" class="js-rm-header" hidden>[x]</button> | ||||
| 									<button type="button" class="js-new-header">[+]</button> | ||||
| 								</div> | ||||
| 							</div> | ||||
| 							<div class="js-body"> | ||||
| 								<textarea | ||||
| 									placeholder="Body template, use '{{ keyname }}' for template values." | ||||
| 									class="js-body-template" | ||||
| 								></textarea> | ||||
| 								<!-- TODO preview template --> | ||||
| 							</div> | ||||
| 						</div> | ||||
| 					</div> | ||||
| 
 | ||||
| 					<br /> | ||||
| 					<button class="js-create">Save Schedule</button> | ||||
| 				</form> | ||||
| 			</div> | ||||
| 		</div> | ||||
| 
 | ||||
| 		<script src="./ajquery.js"></script> | ||||
| 		<script> | ||||
| 			'use strict'; | ||||
| 
 | ||||
| 			var allSchedules = []; | ||||
| 			document.body.addEventListener('submit', function(ev) { | ||||
| 				if (ev.target.matches('.js-schedules-list')) { | ||||
| 					ev.preventDefault(); | ||||
| 					ev.stopPropagation(); | ||||
| 					getSchedules(); | ||||
| 					return; | ||||
| 				} else if (ev.target.matches('.js-schedules-new')) { | ||||
| 					ev.preventDefault(); | ||||
| 					ev.stopPropagation(); | ||||
| 					scheduleTask(); | ||||
| 					return; | ||||
| 				} | ||||
| 			}); | ||||
| 
 | ||||
| 			function getToken() { | ||||
| 				return document.querySelector('.js-auth-token').value; | ||||
| 			} | ||||
| 
 | ||||
| 			function getSchedules() { | ||||
| 				var token = document.querySelector('.js-auth-token').value; | ||||
| 				window | ||||
| 				return window | ||||
| 					.fetch('/api/schedules', { | ||||
| 						headers: { Authorization: token } | ||||
| 						headers: { Authorization: getToken() } | ||||
| 					}) | ||||
| 					.then(function(resp) { | ||||
| 						return resp.json().then(function(schedules) { | ||||
| 							document.querySelector( | ||||
| 								'.js-schedules' | ||||
| 							).innerText = JSON.stringify(schedules, null, 2); | ||||
| 							allSchedules = schedules; | ||||
| 							renderSchedules(schedules); | ||||
| 						}); | ||||
| 					}); | ||||
| 			} | ||||
| 
 | ||||
| 			function renderSchedules(schedules) { | ||||
| 				document.querySelector( | ||||
| 					'.js-schedules-output' | ||||
| 				).innerText = JSON.stringify(schedules, null, 2); | ||||
| 			} | ||||
| 
 | ||||
| 			function scheduleTask() { | ||||
| 				return window | ||||
| 					.fetch('/api/schedules/new', { | ||||
| 						method: 'POST', | ||||
| 						headers: { | ||||
| 							Authorization: getToken(), | ||||
| 							'Content-Type': 'application/json' | ||||
| 						}, | ||||
| 						body: JSON.stringify(task) | ||||
| 					}) | ||||
| 					.then(function(resp) { | ||||
| 						return resp.json().then(function(schedule) { | ||||
| 							console.log('New Schedule:', schedule); | ||||
| 							allSchedules.push(schedule); | ||||
| 							renderSchedules(allSchedules); | ||||
| 						}); | ||||
| 					}); | ||||
| 				return; | ||||
| 			} | ||||
| 		</script> | ||||
| 		<script src="./hooks.js"></script> | ||||
| 	</body> | ||||
| </html> | ||||
|  | ||||
							
								
								
									
										54
									
								
								public/tzdb.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								public/tzdb.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,54 @@ | ||||
| {"+00:00 +00:00":["Africa/Abidjan","Africa/Accra","Africa/Bissau","Africa/Monrovia","America/Danmarkshavn","Atlantic/Reykjavik"], | ||||
| "+01:00 +01:00":["Africa/Algiers","Africa/Casablanca","Africa/Lagos","Africa/Ndjamena","Africa/Tunis"], | ||||
| "+02:00 +02:00":["Africa/Cairo","Africa/Johannesburg","Africa/Khartoum","Africa/Maputo","Africa/Tripoli","Africa/Windhoek","Asia/Famagusta","Europe/Kaliningrad"], | ||||
| "+01:00 +02:00":["Africa/Ceuta","Europe/Amsterdam","Europe/Andorra","Europe/Belgrade","Europe/Berlin","Europe/Brussels","Europe/Budapest","Europe/Copenhagen","Europe/Gibraltar","Europe/Luxembourg","Europe/Madrid","Europe/Malta","Europe/Monaco","Europe/Oslo","Europe/Paris","Europe/Prague","Europe/Rome","Europe/Stockholm","Europe/Tirane","Europe/Vienna","Europe/Warsaw","Europe/Zurich"], | ||||
| "+00:00 +01:00":["Africa/El_Aaiun","Atlantic/Canary","Atlantic/Faroe","Atlantic/Madeira","Europe/Dublin","Europe/Lisbon","Europe/London"], | ||||
| "+03:00 +03:00":["Africa/Juba","Africa/Nairobi","Antarctica/Syowa","Asia/Baghdad","Asia/Qatar","Asia/Riyadh","Europe/Istanbul","Europe/Kirov","Europe/Minsk","Europe/Moscow","Europe/Simferopol"], | ||||
| "−10:00 −09:00":["America/Adak"], | ||||
| "−09:00 −08:00":["America/Anchorage","America/Juneau","America/Metlakatla","America/Nome","America/Sitka","America/Yakutat"], | ||||
| "−03:00 −03:00":["America/Araguaina","America/Argentina/Buenos_Aires","America/Argentina/Catamarca","America/Argentina/Cordoba","America/Argentina/Jujuy","America/Argentina/La_Rioja","America/Argentina/Mendoza","America/Argentina/Rio_Gallegos","America/Argentina/Salta","America/Argentina/San_Juan","America/Argentina/San_Luis","America/Argentina/Tucuman","America/Argentina/Ushuaia","America/Bahia","America/Belem","America/Cayenne","America/Fortaleza","America/Maceio","America/Montevideo","America/Paramaribo","America/Punta_Arenas","America/Recife","America/Santarem","Antarctica/Palmer","Antarctica/Rothera","Atlantic/Stanley"], | ||||
| "−04:00 −03:00":["America/Asuncion","America/Campo_Grande","America/Cuiaba","America/Glace_Bay","America/Goose_Bay","America/Halifax","America/Moncton","America/Santiago","America/Thule","Atlantic/Bermuda"], | ||||
| "−05:00 −05:00":["America/Atikokan","America/Bogota","America/Cancun","America/Eirunepe","America/Guayaquil","America/Jamaica","America/Lima","America/Panama","America/Rio_Branco"], | ||||
| "−06:00 −05:00":["America/Bahia_Banderas","America/Chicago","America/Indiana/Knox","America/Indiana/Tell_City","America/Matamoros","America/Menominee","America/Merida","America/Mexico_City","America/Monterrey","America/North_Dakota/Beulah","America/North_Dakota/Center","America/North_Dakota/New_Salem","America/Rainy_River","America/Rankin_Inlet","America/Resolute","America/Winnipeg","Pacific/Easter"], | ||||
| "−04:00 −04:00":["America/Barbados","America/Blanc-Sablon","America/Boa_Vista","America/Caracas","America/Curacao","America/Guyana","America/La_Paz","America/Manaus","America/Martinique","America/Port_of_Spain","America/Porto_Velho","America/Puerto_Rico","America/Santo_Domingo"], | ||||
| "−06:00 −06:00":["America/Belize","America/Costa_Rica","America/El_Salvador","America/Guatemala","America/Managua","America/Regina","America/Swift_Current","America/Tegucigalpa","Pacific/Galapagos"], | ||||
| "−07:00 −06:00":["America/Boise","America/Cambridge_Bay","America/Chihuahua","America/Denver","America/Edmonton","America/Inuvik","America/Mazatlan","America/Ojinaga","America/Yellowknife"], | ||||
| "−07:00 −07:00":["America/Creston","America/Dawson_Creek","America/Fort_Nelson","America/Hermosillo","America/Phoenix"], | ||||
| "−08:00 −07:00":["America/Dawson","America/Los_Angeles","America/Tijuana","America/Vancouver","America/Whitehorse"], | ||||
| "−05:00 −04:00":["America/Detroit","America/Grand_Turk","America/Havana","America/Indiana/Indianapolis","America/Indiana/Marengo","America/Indiana/Petersburg","America/Indiana/Vevay","America/Indiana/Vincennes","America/Indiana/Winamac","America/Iqaluit","America/Kentucky/Louisville","America/Kentucky/Monticello","America/Nassau","America/New_York","America/Nipigon","America/Pangnirtung","America/Port-au-Prince","America/Thunder_Bay","America/Toronto"], | ||||
| "−03:00 −02:00":["America/Godthab","America/Miquelon","America/Sao_Paulo"], | ||||
| "−02:00 −02:00":["America/Noronha","Atlantic/South_Georgia"], | ||||
| "−01:00 +00:00":["America/Scoresbysund","Atlantic/Azores"], | ||||
| "−03:30 −02:30":["America/St_Johns"], | ||||
| "+11:00 +11:00":["Antarctica/Casey","Antarctica/Macquarie","Asia/Magadan","Asia/Sakhalin","Asia/Srednekolymsk","Pacific/Bougainville","Pacific/Efate","Pacific/Guadalcanal","Pacific/Kosrae","Pacific/Norfolk","Pacific/Noumea","Pacific/Pohnpei"], | ||||
| "+07:00 +07:00":["Antarctica/Davis","Asia/Bangkok","Asia/Barnaul","Asia/Ho_Chi_Minh","Asia/Hovd","Asia/Jakarta","Asia/Krasnoyarsk","Asia/Novokuznetsk","Asia/Novosibirsk","Asia/Pontianak","Asia/Tomsk","Indian/Christmas"], | ||||
| "+10:00 +10:00":["Antarctica/DumontDUrville","Asia/Ust-Nera","Asia/Vladivostok","Australia/Brisbane","Australia/Lindeman","Pacific/Chuuk","Pacific/Guam","Pacific/Port_Moresby"], | ||||
| "+05:00 +05:00":["Antarctica/Mawson","Asia/Aqtau","Asia/Aqtobe","Asia/Ashgabat","Asia/Atyrau","Asia/Dushanbe","Asia/Karachi","Asia/Oral","Asia/Qyzylorda","Asia/Samarkand","Asia/Tashkent","Asia/Yekaterinburg","Indian/Kerguelen","Indian/Maldives"], | ||||
| "+00:00 +02:00":["Antarctica/Troll"], | ||||
| "+06:00 +06:00":["Antarctica/Vostok","Asia/Almaty","Asia/Bishkek","Asia/Dhaka","Asia/Omsk","Asia/Thimphu","Asia/Urumqi","Indian/Chagos"], | ||||
| "+02:00 +03:00":["Asia/Amman","Asia/Beirut","Asia/Damascus","Asia/Gaza","Asia/Hebron","Asia/Jerusalem","Europe/Athens","Europe/Bucharest","Europe/Chisinau","Europe/Helsinki","Europe/Kiev","Asia/Nicosia","Europe/Riga","Europe/Sofia","Europe/Tallinn","Europe/Uzhgorod","Europe/Vilnius","Europe/Zaporozhye"], | ||||
| "+12:00 +12:00":["Asia/Anadyr","Asia/Kamchatka","Pacific/Funafuti","Pacific/Kwajalein","Pacific/Majuro","Pacific/Nauru","Pacific/Tarawa","Pacific/Wake","Pacific/Wallis"], | ||||
| "+04:00 +04:00":["Asia/Baku","Asia/Dubai","Asia/Tbilisi","Asia/Yerevan","Europe/Astrakhan","Europe/Samara","Europe/Saratov","Europe/Ulyanovsk","Europe/Volgograd","Indian/Mahe","Indian/Mauritius","Indian/Reunion"], | ||||
| "+08:00 +08:00":["Asia/Brunei","Asia/Choibalsan","Asia/Hong_Kong","Asia/Irkutsk","Asia/Kuala_Lumpur","Asia/Kuching","Asia/Macau","Asia/Makassar","Asia/Manila","Asia/Shanghai","Asia/Singapore","Asia/Taipei","Asia/Ulaanbaatar","Australia/Perth"], | ||||
| "+09:00 +09:00":["Asia/Chita","Asia/Dili","Asia/Jayapura","Asia/Khandyga","Asia/Pyongyang","Asia/Seoul","Asia/Tokyo","Asia/Yakutsk","Pacific/Palau"], | ||||
| "+05:30 +05:30":["Asia/Colombo","Asia/Kolkata"], | ||||
| "+04:30 +04:30":["Asia/Kabul"], | ||||
| "+05:45 +05:45":["Asia/Kathmandu"], | ||||
| "+03:30 +04:30":["Asia/Tehran"], | ||||
| "+06:30 +06:30":["Asia/Yangon","Indian/Cocos"], | ||||
| "−01:00 −01:00":["Atlantic/Cape_Verde"], | ||||
| "+09:30 +10:30":["Australia/Adelaide","Australia/Broken_Hill"], | ||||
| "+10:00 +11:00":["Australia/Currie","Australia/Hobart","Australia/Melbourne","Australia/Sydney"], | ||||
| "+09:30 +09:30":["Australia/Darwin"], | ||||
| "+08:45 +08:45":["Australia/Eucla"], | ||||
| "+10:30 +11:00":["Australia/Lord_Howe"], | ||||
| "+13:00 +14:00":["Pacific/Apia","Pacific/Tongatapu"], | ||||
| "+12:00 +13:00":["Pacific/Auckland","Pacific/Fiji"], | ||||
| "+12:45 +13:45":["Pacific/Chatham"], | ||||
| "+13:00 +13:00":["Pacific/Enderbury","Pacific/Fakaofo"], | ||||
| "−09:00 −09:00":["Pacific/Gambier"], | ||||
| "−10:00 −10:00":["Pacific/Honolulu","Pacific/Rarotonga","Pacific/Tahiti"], | ||||
| "+14:00 +14:00":["Pacific/Kiritimati"], | ||||
| "−09:30 −09:30":["Pacific/Marquesas"], | ||||
| "−11:00 −11:00":["Pacific/Niue","Pacific/Pago_Pago"], | ||||
| "−08:00 −08:00":["Pacific/Pitcairn"]} | ||||
							
								
								
									
										31
									
								
								public/tzdb/scrape-wikipedia.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								public/tzdb/scrape-wikipedia.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,31 @@ | ||||
| // https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
 | ||||
| 
 | ||||
| var zones = []; | ||||
| var zoneMap = {}; | ||||
| var all = document.body | ||||
| 	.querySelector('.wikitable.sortable.jquery-tablesorter') | ||||
| 	.querySelectorAll('tr'); | ||||
| all = [].slice.call(all, 1); // remove header
 | ||||
| 
 | ||||
| all.forEach(function(el) { | ||||
| 	if (/Alias|Deprecated|Etc\//.test(el.outerText)) { | ||||
| 		$(el).remove(); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	var fields = [].slice.call(el.querySelectorAll('td')); | ||||
| 	var f = fields.map(function(td) { | ||||
| 		return td.innerText.trim(); | ||||
| 	}); | ||||
| 	var id = f[5] + ' ' + f[6]; | ||||
| 	if (!zoneMap[id]) { | ||||
| 		zones.push([f[2], f[5], f[6]]); | ||||
| 	} | ||||
| 	zoneMap[id] = zoneMap[id] || []; | ||||
| 	zoneMap[id].push(f[2]); | ||||
| }); | ||||
| 
 | ||||
| // console.log(JSON.stringify(zones));
 | ||||
| console.log('Total:', all.length); | ||||
| console.log('Unique:', Object.keys(zoneMap).length); | ||||
| console.log(zoneMap); | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user