2017-08-22 21:53:36 +03:00
<!DOCTYPE HTML>
< html lang = "en" >
< head >
< meta charset = "utf-8" >
2018-09-19 19:28:47 +03:00
< title > lab< / title >
< link rel = "icon" type = "image/png" href = "favicon.png" / >
2019-02-03 01:29:56 +03:00
< link href = "../inter.css" rel = "stylesheet" >
2017-08-22 21:53:36 +03:00
< script type = "text/javascript" >
2020-04-07 21:07:33 +03:00
// dark color scheme by default?
let defaultColorSceme = "light"
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
defaultColorSceme = "dark"
if (document.location.search.indexOf("invert-colors") == -1) {
document.documentElement.classList.add("color-scheme-dark")
}
}
// Safari?
(function(u){ if (
u.indexOf('Safari/') != -1 & &
u.indexOf('Chrome/') == -1 & &
u.indexOf('Chromium/') == -1
) {
document.documentElement.classList.add('safari')
} })(navigator.userAgent);
2017-08-22 21:53:36 +03:00
< / script >
2021-03-29 22:52:15 +03:00
< script type = "text/javascript" src = "samples.js?v=3.17" > < / script >
< script type = "text/javascript" src = "build-version.js?v=3.17" > < / script >
< script type = "text/javascript" src = "font-files.js?v=3.17" > < / script >
2018-09-06 20:42:43 +03:00
< link href = "lab.css" rel = "stylesheet" >
2020-04-09 04:56:06 +03:00
< link rel = "stylesheet" type = "text/css" href = "https://fonts.googleapis.com/css?family=Roboto:400,400i,500,500i,700,700i,900,900i&subset=cyrillic,cyrillic-ext,greek,greek-ext,latin-ext,vietnamese" >
2017-08-22 21:53:36 +03:00
< / head >
2020-04-07 21:07:33 +03:00
< body class = "init-anim" >
< div id = "sidebar-button" > < / div >
2020-04-09 04:56:06 +03:00
< div class = "options" >
2017-08-22 21:53:36 +03:00
2020-04-07 21:07:33 +03:00
< div class = "flex-x" >
2020-04-09 04:56:06 +03:00
< label title = "Use variable font instead of constant font files" >
< span > VF< / span >
< input type = "checkbox" name = "varfont" >
2018-09-10 20:21:55 +03:00
< / label >
2020-04-09 04:56:06 +03:00
< label class = "italic-setting" title = "Italic" >
< span > I< / span >
2020-04-07 21:07:33 +03:00
< input type = "checkbox" name = "italic" >
2018-09-10 20:21:55 +03:00
< / label >
2020-04-07 21:07:33 +03:00
< label title = "Swap color scheme" >
< b > ☀< / b >
2020-04-09 04:56:06 +03:00
< input type = "checkbox" name = "invert-colors" >
2018-09-10 20:21:55 +03:00
< / label >
2021-04-01 00:34:11 +03:00
< label title = "Draw background behind samples" >
< b > ■< / b >
< input type = "checkbox" name = "draw-sample-bg" >
< / label >
2018-09-10 20:21:55 +03:00
< / div >
< label class = "label-and-value" >
< span > Size:< / span >
2020-08-19 21:54:27 +03:00
< input type = "range" value = "22" step = "1" min = "4" max = "128" name = "_sizeRange" >
2018-10-10 19:16:44 +03:00
< input type = "number" value = "22" step = "1" min = "4" max = "1024" name = "size" >
2020-04-07 21:07:33 +03:00
<!-- <note><span class="unit">dp</span></note> -->
< / label >
<!-- Variable font controls (hidden when not using variable fonts) -->
< label class = "label-and-value varfontControl" >
< span > Weight:< / span >
< input type = "range" value = "400" step = "1" min = "100" max = "900" name = "varWeight" >
< input type = "number" value = "400" step = "1" min = "100" max = "900" name = "varWeightNum" >
< / label >
< label class = "label-and-value varfontControl" >
< span > Slant:< / span >
< input type = "range" value = "0" step = "0.01" min = "0" max = "10" name = "varSlant" >
< input type = "number" value = "0" step = "0.01" min = "0" max = "10" name = "varSlantNum" >
< / label >
< label class = "label-and-value constfontControl" >
< span > Weight:< / span >
< select name = "weight" style = "max-width:100px" >
< option value = "100" > Thin (100)< / option >
< option value = "200" > Extra Light (200)< / option >
< option value = "300" > Light (300)< / option >
< option value = "400" selected > Regular (400)< / option >
< option value = "500" > Medium (500)< / option >
< option value = "600" > Semi Bold (600)< / option >
< option value = "700" > Bold (700)< / option >
< option value = "800" > Extra Bold (800)< / option >
< option value = "900" > Black (900)< / option >
< / select >
2018-09-10 20:21:55 +03:00
< / label >
2020-04-09 04:56:06 +03:00
< label class = "label-and-value" >
< span > Family:< / span >
< select name = "family" >
< option value = "text" selected > Inter< / option >
< option value = "display" > Inter Display< / option >
< / select >
< / label >
2018-09-10 20:21:55 +03:00
< label class = "label-and-value" >
< span > Sample text:< / span >
< select name = "sample" > < / select >
2017-08-22 21:53:36 +03:00
< / label >
2017-10-01 20:57:54 +03:00
< div class = "checkbox-group repertoireControl" >
< label class = "label-and-value" >
< span > Repertoire order:< / span >
< select name = "repertoireOrder" >
< option value = "" selected > Original< / option >
< option value = "u" > Unicode< / option >
< / select >
< / label >
< / div >
2017-08-22 21:53:36 +03:00
< label class = "label-and-value" >
2019-05-28 00:19:08 +03:00
< span > Letter spacing:< / span >
< input type = "number" value = "" placeholder = "" step = "0.1" name = "letterSpacing" >
2020-04-07 21:07:33 +03:00
< note > < span class = "unit" > %< / span > < div class = "img-button reset reset-letter-spacing" tabindex = "0" > < / div >
2019-05-28 00:19:08 +03:00
< / note >
2017-08-22 21:53:36 +03:00
< / label >
< label class = "label-and-value" >
2019-05-28 00:19:08 +03:00
< span > Line height:< / span >
2017-08-22 21:53:36 +03:00
< input type = "number" value = "" placeholder = "" step = "1" min = "0" max = "1000" name = "lineHeight" >
2020-04-07 21:07:33 +03:00
< note > < span class = "unit" > dp< / span > < div class = "img-button reset reset-line-height" tabindex = "0" > < / div >
2019-05-28 00:19:08 +03:00
< / note >
2017-08-22 21:53:36 +03:00
< / label >
< label class = "label-and-value" >
2019-05-28 00:19:08 +03:00
< span > Transform:< / span >
2017-08-22 21:53:36 +03:00
< select name = "text-transform" >
< option value = "none" selected > none< / option >
2020-04-09 04:56:06 +03:00
< option value = "capitalize" > Capitalize< / option >
< option value = "uppercase" > UPPERCASE< / option >
2017-08-22 21:53:36 +03:00
< option value = "lowercase" > lowercase< / option >
< / select > < / label >
< label class = "label-and-value" >
2019-05-28 00:19:08 +03:00
< span > Decoration:< / span >
2018-02-15 20:48:22 +03:00
< select name = "text-decoration" >
< option value = "none" selected > none< / option >
2020-04-09 04:56:06 +03:00
< option value = "underline" style = "text-decoration:underline" > underline< / option >
2018-02-15 20:48:22 +03:00
< option value = "overline" > overline< / option >
< option value = "underline overline" > underline & overline< / option >
< option value = "line-through" > line-through< / option >
< option value = "wavy underline" > wavy underline< / option >
2017-08-22 21:53:36 +03:00
< / select > < / label >
2020-04-07 21:07:33 +03:00
<!-- <h3>Display</h3> -->
2019-05-28 00:19:08 +03:00
< label class = "label-and-value" >
< span > Anti-alias:< / span >
< select name = "antialias" >
< option value = "greyscale" selected > Greyscale< / option >
< option value = "subpixel" > Subpixel< / option >
< option value = "default" > Browser default< / option >
< / select >
< / label >
< label class = "label-and-value" >
< span > Compare:< / span >
< select name = "compare" >
< option value = "-" selected > Nothing< / option >
2020-04-09 04:56:06 +03:00
< option value = "inter-other" > Other Inter family< / option >
2019-05-28 00:19:08 +03:00
< option value = "system" > System font< / option >
< / select >
< / label >
< h3 > Features< / h3 >
2017-08-25 04:27:00 +03:00
< div class = "checkbox-group" >
2020-04-09 04:56:06 +03:00
<!-- case --> < label title = "Upper case adjustments" > < input type = "checkbox" class = "featopt" name = "feat:case" > < span > case (Case alternates)< / span > < / label >
<!-- cpsp --> < label title = 'Capital spacing (adds 16 UPM to each sidebearing)' > < input type = "checkbox" class = "featopt" name = "feat:cpsp" > < span > cpsp (Capital spacing)< / span > < / label >
<!-- dlig --> < label title = "Discretionary ligatures, e.g. !? -> interrobang" > < input type = "checkbox" class = "featopt" name = "feat:dlig" > < span > dlig (Discretionary ligatures)< / span > < / label >
<!-- frac --> < label title = "Contextual automatic fractions" > < input type = "checkbox" class = "featopt" name = "feat:frac" > < span > frac (Auto fractions)< / span > < / label >
<!-- dnom --> < label title = "Convert all numbers to denominators" > < input type = "checkbox" class = "featopt" name = "feat:dnom" > < span > dnom (Denominators)< / span > < / label >
<!-- numr --> < label title = "Convert all numbers to numerators" > < input type = "checkbox" class = "featopt" name = "feat:numr" > < span > numr (Numerators)< / span > < / label >
<!-- salt --> < label title = 'Stylistic Alternates' > < input type = "checkbox" class = "featopt" name = "feat:salt" > < span > salt (Stylistic Alternates)< / span > < / label >
<!-- subs --> < label title = "Subscript" > < input type = "checkbox" class = "featopt" name = "feat:subs" > < span > subs (Subscript)< / span > < / label >
<!-- sups --> < label title = "Superscript" > < input type = "checkbox" class = "featopt" name = "feat:sups" > < span > sups (Superscript)< / span > < / label >
<!-- tnum --> < label title = "Tabular numbers (fixed width)" > < input type = "checkbox" class = "featopt" name = "feat:tnum" > < span > tnum (Tabular numbers)< / span > < / label >
<!-- zero --> < label title = "Slashed zero" > < input type = "checkbox" class = "featopt" name = "feat:zero" > < span > zero (Slashed zero)< / span > < / label >
< label title = 'Stylistic set 1 "Open Digits"' > < input type = "checkbox" class = "featopt" name = "feat:ss01" > < span > ss01 (Open Digits)< / span > < / label >
< label title = 'Stylistic set 2 "Disambiguation"' > < input type = "checkbox" class = "featopt" name = "feat:ss02" > < span > ss02 (Disambiguation)< / span > < / label >
< label title = 'Stylistic set 3 "Lower case r curves into round neighbors"' > < input type = "checkbox" class = "featopt" name = "feat:ss03" > < span > ss03 (Curved r)< / span > < / label >
< label title = 'Stylistic set 4 "Disambiguation without slashed zero"' > < input type = "checkbox" class = "featopt" name = "feat:ss04" > < span > ss04 (Disambiguation w/o zero)< / span > < / label >
< label title = 'Character Variant 1 "Alternate one"' > < input type = "checkbox" class = "featopt" name = "feat:cv01" > < span > cv01 (Alternate one)< / span > < / label >
< label title = 'Character Variant 2 "Open four"' > < input type = "checkbox" class = "featopt" name = "feat:cv02" > < span > cv02 (Open four)< / span > < / label >
< label title = 'Character Variant 3 "Open six"' > < input type = "checkbox" class = "featopt" name = "feat:cv03" > < span > cv03 (Open six)< / span > < / label >
< label title = 'Character Variant 4 "Open nine"' > < input type = "checkbox" class = "featopt" name = "feat:cv04" > < span > cv04 (Open nine)< / span > < / label >
< label title = 'Character Variant 5 "Lower case L with tail")' > < input type = "checkbox" class = "featopt" name = "feat:cv05" > < span > cv05 (Lower case L with tail)< / span > < / label >
< label title = 'Character Variant 6 "Lower case r with curved tail")' > < input type = "checkbox" class = "featopt" name = "feat:cv06" > < span > cv06 (Curved lower case r)< / span > < / label >
< label title = 'Character Variant 7 "Alternate German double-s")' > < input type = "checkbox" class = "featopt" name = "feat:cv07" > < span > cv07 (German double-s)< / span > < / label >
< label title = 'Character Variant 8 "Upper-case i with serif")' > < input type = "checkbox" class = "featopt" name = "feat:cv08" > < span > cv08 (Upper-case i with serif)< / span > < / label >
< label title = 'Character Variant 9 "Flat top three")' > < input type = "checkbox" class = "featopt" name = "feat:cv09" > < span > cv09 (Flat top three)< / span > < / label >
< label title = 'Character Variant 10 "Capital G with spur")' > < input type = "checkbox" class = "featopt" name = "feat:cv10" > < span > cv10 (Capital G with spur)< / span > < / label >
< label title = 'Character Variant 11 "Single-storey a")' > < input type = "checkbox" class = "featopt" name = "feat:cv11" > < span > cv11 (Single-storey a)< / span > < / label >
2018-09-27 03:53:48 +03:00
< / div >
< div class = "checkbox-group" >
< span > Default-on features:< / span >
< label title = "Contextual alternates" > < input type = "checkbox" class = "featopt" name = "feat:calt=0" > Disable calt (Contextual alternates)< / label >
2021-03-30 03:09:05 +03:00
< label title = "Glyph Composition/Decomposition" > < input type = "checkbox" class = "featopt" name = "feat:ccmp=0" > Disable ccmp< / label >
2018-09-27 03:53:48 +03:00
< label title = "Kerning" > < input type = "checkbox" class = "featopt" name = "feat:kern=0" > Disable kern (Kerning)< / label >
2017-08-22 21:53:36 +03:00
< / div >
2019-02-03 22:45:21 +03:00
< div >
< a href = "var.html" > Variable test page< / a >
< / div >
2017-08-22 21:53:36 +03:00
< / div >
< boxes >
2018-12-30 02:58:23 +03:00
< box contenteditable spellcheck = "false" class = "primaryFont " > < span > Rectangle< / span > < / box >
< box contenteditable spellcheck = "false" class = "primaryFont positive" > < span > Rectangle< / span > < / box >
< box contenteditable spellcheck = "false" class = "primaryFont positive tight" > < span > Rectangle< / span > < / box >
< box contenteditable spellcheck = "false" class = "primaryFont centered positive" > < span > Rectangle< / span > < / box >
2019-08-03 20:36:10 +03:00
2017-08-22 21:53:36 +03:00
< sep > < / sep >
2018-12-30 02:58:23 +03:00
< box contenteditable spellcheck = "false" class = "secondaryFont showOnlyWithSecondarySample" > < span > Rectangle< / span > < / box >
< box contenteditable spellcheck = "false" class = "secondaryFont positive showOnlyWithSecondarySample" > < span > Rectangle< / span > < / box >
< box contenteditable spellcheck = "false" class = "secondaryFont positive tight showOnlyWithSecondarySample" > < span > Rectangle< / span > < / box >
< box contenteditable spellcheck = "false" class = "secondaryFont centered positive showOnlyWithSecondarySample" > < span > Rectangle< / span > < / box >
2017-08-22 21:53:36 +03:00
< / boxes >
< div class = "preview" >
< samples >
2019-02-03 01:29:56 +03:00
< sample contenteditable spellcheck = "false" class = "primary inter" > < / sample >
2018-12-30 02:58:23 +03:00
< sample contenteditable spellcheck = "false" class = "secondary" > < / sample >
2017-08-22 21:53:36 +03:00
< / samples >
< / div >
2019-02-03 01:29:56 +03:00
< div id = "measure" class = "inter" > Åj< / div >
2019-05-28 00:19:08 +03:00
< / body >
< script type = "text/javascript" > ( f u n c t i o n ( ) {
2020-04-09 04:56:06 +03:00
function InterDynamicTracking(fontSize, family /* :"text"|"display" */) {
2019-05-28 00:19:08 +03:00
var a = -0.0223, b = 0.185, c = -0.1745;
2020-04-09 04:56:06 +03:00
if (family == "display") {
a = -0.015; b = 0.17; c = -0.12
}
2019-05-28 00:19:08 +03:00
// tracking = a + b * e ^ (c * fontSize)
return a + b * Math.pow(Math.E, c * fontSize)
}
2017-08-22 21:53:36 +03:00
2018-09-27 02:30:15 +03:00
// provide hinted=1 to use TTF hinted fonts.
// not exposed in UI as it only works when serving the site locally
// with fonts in the build/fonts directory.
const hinted = location.search.indexOf('hinted=1') != -1
2019-04-05 03:30:34 +03:00
const familyName = hinted ? fontFamilyNameHinted : fontFamilyName;
2018-09-27 02:30:15 +03:00
2019-04-05 03:30:34 +03:00
if (hinted) {
document.body.classList.add('hinted')
}
document.body.style.fontFamily = familyName
2017-08-22 21:53:36 +03:00
2020-04-07 21:07:33 +03:00
function parseQueryString(qs) {
return new Map(
qs.replace(/^\?+/g,'')
.split('& ')
.filter(s => s.trim())
.map(s => s.split('=').map(decodeURIComponent))
)
}
function fmtQueryString(mapLikeIterable) {
let pairs = []
for (let kv of mapLikeIterable) {
let k = kv[0]
let v = kv[1]
if (v === undefined) {
pairs.push(encodeURIComponent(k))
} else {
v = (v === true) ? 1 : (v === false || v === null) ? 0 : v
pairs.push(encodeURIComponent(k) + '=' + encodeURIComponent(v))
}
}
return pairs.sort().join('& ')
}
function setCurrentQueryString(queryString) {
replaceURL(() => {
if (typeof queryString == "function") {
queryString = queryString()
}
return document.location.pathname + (queryString ? "?" + queryString : "")
})
}
function setCurrentQueryStringParam(key, value, zeroValue) {
setCurrentQueryString(() => {
let qs = parseQueryString(document.location.search)
if (value === undefined || value === zeroValue) {
qs.delete(key)
} else {
qs.set(key, value)
}
return fmtQueryString(qs)
})
}
// replaceURL(url :string|Function, title? :string, meta? :any)
var replaceURL = (()=>{
// We employ some backoff on calling history.replaceState as
// Chrome will start to throttle (meaning ignoring) calls to
// history.replaceState if the frequency gets too high.
// Safari 13 provides a budget of 200 replaceState calls in a 30 second sliding time window.
// Chrome instead uses an IPC message flooding prevention (https://crbug.com/882238)
let timer = null
let queued = null // {url, title, meta} when queued, null when not
2020-04-09 04:56:06 +03:00
let isRetrying = false
2020-04-07 21:07:33 +03:00
function flush() {
2020-04-09 04:56:06 +03:00
clearTimeout(timer)
timer = null
2020-04-07 21:07:33 +03:00
if (queued) {
let url = typeof queued.url == "function" ? queued.url() : queued.url
2020-04-09 04:56:06 +03:00
try {
history.replaceState(queued.meta, queued.title, url)
queued = null
isRetrying = false
} catch (err) {
if (!isRetrying) {
console.warn(String(err))
}
// back off
isRetrying = true
timer = setTimeout(flush, 1000)
}
2020-04-07 21:07:33 +03:00
}
}
return function replaceURL(url, title, meta) {
queued = { url, title, meta }
if (timer === null) {
flush()
timer = setTimeout(flush, 200)
}
}
})()
2017-08-22 21:53:36 +03:00
class BoundVar {
constructor(name, e, valueGetter, valueSetter, parentVars) {
this.name = name
this.e = e
this.valueGetter = valueGetter
this.valueSetter = valueSetter
2020-04-09 04:56:06 +03:00
this.isCheckbox = e.type == 'checkbox'
2020-04-07 21:07:33 +03:00
this.isNumber = e.type == 'number' || e.type == 'range'
2017-08-22 21:53:36 +03:00
this.lastValue = this.getValue()
this.parentVars = parentVars
2019-02-03 10:23:50 +03:00
this.defaultValue = this.lastValue
2019-05-28 00:19:08 +03:00
this._changeCallbacks = []
2020-04-07 21:07:33 +03:00
this._isInitialSetValue = true
2017-08-22 21:53:36 +03:00
}
refreshValue(ev) {
let value = this.getValue(ev)
this.setValue(value)
return value
}
getValue(ev) {
return this.valueGetter ? this.valueGetter(this.e, this.lastValue, ev)
: this.isCheckbox ? (this.e.checked || null)
: this.isNumber ? this.e.valueAsNumber
: this.e.value
}
2019-05-28 00:19:08 +03:00
onChange(callback) {
this._changeCallbacks.push(callback)
}
removeChangeListener(callback) {
let i = 0
for (; i < this._changeCallbacks.length ; i + + ) {
if (this._changeCallbacks[i] === callback) {
this._changeCallbacks.splice(i, 1)
return true
}
}
return false
}
2017-08-22 21:53:36 +03:00
setValue(value) {
if (this.isCheckbox & & typeof value != 'boolean') {
value = parseInt(value)
if (isNaN(value)) {
value = 0
}
}
if (this.valueSetter) {
2020-04-07 21:07:33 +03:00
let isInitial = this._isInitialSetValue
this._isInitialSetValue = false
const v = this.valueSetter(this.e, value, isInitial)
2017-08-22 21:53:36 +03:00
if (v !== undefined) {
value = v
}
}
if (this.isCheckbox) {
2020-04-09 04:56:06 +03:00
if ((this.e.checked = !!value)) {
this.e.setAttribute("checked", "")
} else {
this.e.removeAttribute("checked")
}
2020-04-07 21:07:33 +03:00
} else if (this.isNumber & & typeof value == 'number' & & 'valueAsNumber' in this.e) {
2019-05-28 00:19:08 +03:00
if (isNaN(value)) {
this.e.value = null
2020-04-07 21:07:33 +03:00
} else if (this.e.valueAsNumber != value) {
this.e.valueAsNumber = value
2017-08-22 21:53:36 +03:00
}
} else if (this.e.value != value) {
this.e.value = value
}
this.lastValue = value
2019-05-28 00:19:08 +03:00
for (let f of this._changeCallbacks) {
f(value, this)
}
2017-08-22 21:53:36 +03:00
}
}
class Vars {
constructor(queryString) {
2020-04-07 21:07:33 +03:00
this.values = parseQueryString(queryString)
2017-08-22 21:53:36 +03:00
this.vars = new Map()
2020-04-07 21:07:33 +03:00
// this._historyReplaceStateTimer = null
// this._needsHistoryReplaceState = false
2017-08-22 21:53:36 +03:00
}
getValue(name) {
return this.values.get(name)
}
setValue(name, value) {
let v = this.vars.get(name)
if (!v) {
return null
}
v.setValue(value)
this._storeValue(name, value)
return value
}
_storeValue(name, value) {
// if (this.values.get(name) === value) {
// return
// }
if (value === null || value === undefined) {
this.values.delete(name)
} else {
this.values.set(name, value)
}
2020-04-07 21:07:33 +03:00
setCurrentQueryString(() => this.getQueryString())
2018-09-16 01:05:03 +03:00
}
2020-04-07 21:07:33 +03:00
// _performHistoryReplaceState() {
// // let qs = mergeQueryString(document.location.search, this.getQueryString())
// setCurrentQueryString(this.getQueryString())
// this._needsHistoryReplaceState = false
// }
// setNeedsHistoryReplaceState() {
// // We employ some backoff on calling history.replaceState as
// // Chrome will start to throttle (meaning ignoring) calls to
// // history.replaceState if the frequency gets too high.
// // Safari 13 provides a budget of 200 replaceState calls in a 30 second sliding time window.
// // Chrome instead uses an IPC message flooding prevention (https://crbug.com/882238)
// if (this._historyReplaceStateTimer === null) {
// this._performHistoryReplaceState()
// this._historyReplaceStateTimer = setTimeout(() => {
// this._historyReplaceStateTimer = null
// if (this._needsHistoryReplaceState) {
// this._performHistoryReplaceState()
// }
// }, 200)
// } else {
// this._needsHistoryReplaceState = true
// }
// }
2017-08-22 21:53:36 +03:00
refreshValue(name) {
let v = this.vars.get(name)
return v ? this._refreshValue(v) : null
}
_refreshValue(v, ev) {
let value = v.refreshValue(ev)
this._storeValue(v.name, value)
return value
}
getQueryString() {
2020-04-07 21:07:33 +03:00
let qs = parseQueryString(document.location.search)
// patch qs: set or remove any attributes that are registered in this.values
for (let e of this.vars) {
let k = e[0], vr = e[1], v = this.values.get(k)
if (v === undefined || vr.defaultValue == v || k[0] == '_') {
qs.delete(k)
} else {
qs.set(k, v)
2019-02-03 10:23:50 +03:00
}
2020-04-07 21:07:33 +03:00
}
return fmtQueryString(qs)
2017-08-22 21:53:36 +03:00
}
// bind(name :string,
// sel :Element|string,
2020-04-07 21:07:33 +03:00
// valueSetter? :(e:Element, value:any, isInitial:bool)=>void,
2017-08-22 21:53:36 +03:00
// valueGetter? :(e:Element)=>any)
// bind(name :string,
2020-04-07 21:07:33 +03:00
// valueSetter? :(e:Element, value:any, isInitial:bool)=>void,
2017-08-22 21:53:36 +03:00
// valueGetter? :(e:Element, prevValue:any, ev?:Event)=>any)
bind(name, sel, valueSetter, valueGetter) {
if (typeof sel == 'function' || sel === undefined) {
valueGetter = valueSetter
valueSetter = sel
sel = '[name="'+name+'"]'
}
let e = typeof sel == 'string' ? document.querySelector(sel) : sel;
let v = new BoundVar(name, e, valueGetter, valueSetter, this)
this.vars.set(name, v)
if (v.isNumber) {
// SHIFT-ARROW = 10 increments
// SHIFT-ALT-ARROW = x2 increments
e.addEventListener('keydown', ev => {
if (!ev.shiftKey) {
return
}
switch (ev.key) {
2020-04-07 21:07:33 +03:00
case 'ArrowRight':
2017-08-22 21:53:36 +03:00
case 'ArrowUp': {
2020-04-07 21:07:33 +03:00
if (ev.key == 'ArrowRight' & & e.type != "range") {
return
}
2017-08-22 21:53:36 +03:00
if (ev.altKey) {
ev.target.valueAsNumber *= 2
} else {
ev.target.valueAsNumber += 10
}
ev.preventDefault()
ev.stopPropagation()
this._refreshValue(v, ev)
break
}
2020-04-07 21:07:33 +03:00
case 'ArrowLeft':
2017-08-22 21:53:36 +03:00
case 'ArrowDown': {
2020-04-07 21:07:33 +03:00
if (ev.key == 'ArrowLeft' & & e.type != "range") {
return
}
2017-08-22 21:53:36 +03:00
if (ev.altKey) {
ev.target.valueAsNumber /= 2
} else {
ev.target.valueAsNumber -= 10
}
ev.preventDefault()
ev.stopPropagation()
this._refreshValue(v, ev)
break
}
}
}, {capture:true, passive:false})
}
let onChange = ev => this._refreshValue(v, ev)
e.addEventListener('input', onChange)
if (v.isCheckbox) {
e.addEventListener('change', onChange)
}
let existingValue = this.values.get(name)
if (existingValue !== null & & existingValue !== undefined) {
if (v.isNumber) {
existingValue = parseFloat(existingValue)
} else if (v.isCheckbox) {
existingValue = existingValue != '0' & & existingValue != 'false' & & existingValue != 'off'
}
v.setValue(existingValue)
} else {
onChange(null)
}
return v
}
}
2020-04-07 21:07:33 +03:00
// function mergeQueryString(a, b) {
// a = a.replace(/^[\?\& ]+/, "").split('& ').sort().map(v => v.split('='))
// b = b.replace(/^[\?\& ]+/, "").split('& ').sort().map(v => v.split('='))
// let s = new Map(a)
// for (let kv of b) {
// s.set(kv[0], kv[1])
// }
// return Array.from(s).map(kv => kv[1] ? kv.join('=') : kv[0]).join('& ')
// }
2017-08-22 21:53:36 +03:00
function main() {
const vars = new Vars(document.location.search)
2019-05-28 00:19:08 +03:00
const $ = (q, el) => (el || document).querySelector(q)
const $$ = (q, el) => [].slice.call((el || document).querySelectorAll(q))
2017-08-22 21:53:36 +03:00
2019-05-28 00:19:08 +03:00
let interUISample = $('sample.inter');
let secondarySample = $('sample.secondary');
secondarySample.innerText = interUISample.innerText;
2017-08-22 21:53:36 +03:00
2019-05-28 00:19:08 +03:00
const measureDiv = $('#measure')
2017-08-22 21:53:36 +03:00
2019-05-28 00:19:08 +03:00
const secondaryFontElements = $$('.secondaryFont')
const primaryFontElements = $$('.primaryFont')
2017-08-22 21:53:36 +03:00
2019-05-28 00:19:08 +03:00
const repertoireControl = $('.repertoireControl')
const samplesElement = $('samples')
2020-04-07 21:07:33 +03:00
const boxes = $('boxes')
2020-04-09 04:56:06 +03:00
let keyPressed = ""
2020-04-07 21:07:33 +03:00
let shiftKeyPressed = false
const checkKeys = ev => {
2020-04-09 04:56:06 +03:00
keyPressed = ev.key
2020-04-07 21:07:33 +03:00
shiftKeyPressed = ev.shiftKey
}
window.addEventListener('keydown', checkKeys)
window.addEventListener('keyup', checkKeys)
// sidebar show/hide
const sidebarButton = $("#sidebar-button")
let sidebarMinimized = false
function setSidebarMinimized(minimized) {
sidebarMinimized = minimized
document.body.classList.toggle("sidebar-minimized", sidebarMinimized)
setCurrentQueryStringParam("nosidebar", sidebarMinimized ? 1 : undefined)
sidebarButton.title = sidebarMinimized ? "Show controls" : "Hide controls"
}
sidebarButton.onclick = () => setSidebarMinimized(!sidebarMinimized)
setSidebarMinimized(document.location.search.indexOf('nosidebar') != -1)
// setInterval(()=>{ setSidebarMinimized(!sidebarMinimized) },2000)
2017-08-22 21:53:36 +03:00
2018-09-19 19:28:47 +03:00
// filter paste to match style
2019-05-28 00:19:08 +03:00
$$('[contenteditable]').forEach(el => {
2018-09-19 19:28:47 +03:00
el.addEventListener('paste', ev => {
ev.preventDefault()
let text = ev.clipboardData.getData("text/plain")
document.execCommand("insertHTML", false, text)
}, {capture:true,passive:false})
})
2019-05-28 00:19:08 +03:00
// prevent clicks on img-button from changing focus
$$('.img-button').forEach(el => {
el.addEventListener('pointerdown', ev => {
ev.preventDefault()
}, {passive:false, capture:true})
})
2017-10-01 20:57:54 +03:00
function forEachGlyphlist(fn) {
let elements = samplesElement.querySelectorAll('.glyphlist')
if (elements) {
for (let i = 0; i < elements.length ; + + i ) {
fn(elements[i], i)
}
}
}
function setGlyphlistClass(className, add) {
forEachGlyphlist(gl => {
if (add) {
gl.classList.add(className)
} else {
gl.classList.remove(className)
}
})
}
2017-08-22 21:53:36 +03:00
2019-05-28 00:19:08 +03:00
const lineHeightInput = $('[name="lineHeight"]')
2017-08-22 21:53:36 +03:00
let measurePending = false
const measure = () => {
const r = measureDiv.getBoundingClientRect()
measurePending = false
lineHeightInput.placeholder = r.height
2021-04-01 00:52:41 +03:00
document.documentElement.style.setProperty("--line-height", r.height + "px")
2017-08-22 21:53:36 +03:00
}
window.addEventListener('load', measure)
const cssAffectedElements = [
2017-09-19 01:58:34 +03:00
interUISample,
2017-08-22 21:53:36 +03:00
secondarySample,
measureDiv
].concat(secondaryFontElements).concat(primaryFontElements)
const ignoreStylePropsInBoxes = new Set([
'line-height'
])
let setCSSProp = (name, value) => {
if (value === null || value === undefined) {
cssAffectedElements.forEach(e => e.style.removeProperty(name))
} else {
cssAffectedElements.forEach(e => {
if (e.nodeName != 'BOX' || !ignoreStylePropsInBoxes.has(name)) {
e.style.setProperty(name, value)
}
})
}
if (!measurePending) {
measurePending = true
window.requestAnimationFrame(measure)
}
}
let setVendorPrefixedCSSProp = (name, value) => {
setCSSProp(name, value)
setCSSProp('-webkit-' + name, value)
setCSSProp('-moz-' + name, value)
setCSSProp('-ms-' + name, value)
}
2019-02-04 01:01:11 +03:00
let feats = new Map()
let featVars = new Map()
let updateFeaturesStyleTimer = null
function updateFeaturesStyle() {
let css = Array.from(feats).map(f => `"${f[0]}" ${f[1]}`).join(', ')
setCSSProp('font-feature-settings', css)
}
function scheduleUpdateFeaturesStyle() {
if (updateFeaturesStyleTimer === null) {
updateFeaturesStyleTimer = setTimeout(() => {
updateFeaturesStyleTimer = null
updateFeaturesStyle()
}, 1)
}
}
function setFeature(feat, val, dontUpdateVar/*=false*/) {
if (typeof val == 'boolean') {
val = val ? 1 : 0
}
let prevVal = feats.get(feat)
if (prevVal !== val) {
feats.set(feat, val)
scheduleUpdateFeaturesStyle()
if (!dontUpdateVar) {
let vr = featVars.get(feat)
if (vr) {
vr.setValue(val)
}
}
}
}
// sample text
2019-05-28 00:19:08 +03:00
const samplesSelect = $('select[name="sample"]')
2019-02-04 01:01:11 +03:00
for (let [k,v] of samples) {
const opt = document.createElement('option')
opt.innerText = k
if (v) {
opt.value = k
} else {
opt.disabled = true
}
samplesSelect.appendChild(opt)
}
vars.bind('repertoireOrder', (e, v) => {
let currOrder = repertoireOrder
if (v == 'u') {
repertoireOrder = RepertoireOrderUnicode
} else {
repertoireOrder = RepertoireOrderGlyphList
}
if (sampleVar & & currOrder != repertoireOrder) {
sampleVar.refreshValue(null)
}
})
2020-04-07 21:07:33 +03:00
var sizeVar, varSizeRange
var varSizeSettingValueImpl = false
sizeVar = vars.bind('size', (e, v, isInitial) => {
2017-08-22 21:53:36 +03:00
boxes.style.display = (v > 20) ? 'none' : null
setCSSProp('font-size', v + 'px')
2021-04-01 00:52:41 +03:00
document.documentElement.style.setProperty("--font-size", v + "px")
2017-10-01 20:57:54 +03:00
setGlyphlistClass('hideNames', v < 36 )
2020-04-07 21:07:33 +03:00
if (varSizeRange & & !varSizeSettingValueImpl) {
varSizeSettingValueImpl = true
varSizeRange.setValue(v)
varSizeSettingValueImpl = false
}
2019-05-28 00:19:08 +03:00
return v
2017-08-22 21:53:36 +03:00
})
2020-04-07 21:07:33 +03:00
varSizeRange = vars.bind('_sizeRange', (e, v, isInitial) => {
if (isInitial) {
return sizeVar.getValue()
} else if (!varSizeSettingValueImpl) {
varSizeSettingValueImpl = true
vars.setValue("size", v)
varSizeSettingValueImpl = false
}
2020-04-09 04:56:06 +03:00
}, (e, prevValue, ev) => {
v = e.valueAsNumber
if (shiftKeyPressed & & (keyPressed == "" || keyPressed == "Shift")) {
v = Math.round(v / 8) * 8
}
return v
2020-04-07 21:07:33 +03:00
})
2017-08-22 21:53:36 +03:00
2018-09-10 20:21:55 +03:00
let usingVarFont = false
2020-04-09 04:56:06 +03:00
let usingFontFamily = "text"
2018-09-30 22:34:27 +03:00
var varWeightRange, varSlantRange
2018-09-10 20:21:55 +03:00
var varWeightSettingValueImpl = false
2018-09-30 22:34:27 +03:00
var varSlantSettingValueImpl = false
2018-09-10 20:21:55 +03:00
2020-04-09 04:56:06 +03:00
function getFontFamily(overrideFamily) {
return (
(overrideFamily || usingFontFamily) == "text" ? (
usingVarFont ? (hinted ? fontFamilyNameVarHinted : fontFamilyNameVar) :
hinted ? fontFamilyNameHinted : fontFamilyName
) : (
usingVarFont ? (hinted ? fontFamilyNameDisplayVarHinted : fontFamilyNameDisplayVar) :
hinted ? fontFamilyNameDisplayHinted : fontFamilyNameDisplay
)
)
}
2017-08-22 21:53:36 +03:00
let currentBodyWeightClass = null
2020-04-07 21:07:33 +03:00
let varWeight = vars.bind('weight', (e, v) => {
2017-08-22 21:53:36 +03:00
setCSSProp('font-weight', v)
if (currentBodyWeightClass) {
document.body.classList.remove(currentBodyWeightClass)
}
document.body.classList.add(currentBodyWeightClass = 'font-weight-'+v)
})
2018-09-10 20:21:55 +03:00
var italicVar = vars.bind('italic', (e, on) => {
2017-08-22 21:53:36 +03:00
document.body.classList[on ? 'add' : 'remove']('italic')
2018-09-30 22:34:27 +03:00
if (usingVarFont & & !varSlantSettingValueImpl) {
if (varSlantRange) {
varSlantRange.setValue(on ? 100 : 0)
2018-09-10 20:21:55 +03:00
}
updateVarFont()
}
})
let varState = {
2019-08-03 20:36:10 +03:00
weight: 400, // 400..900
slant: 0, // 0..-10
2018-09-10 20:21:55 +03:00
}
function updateVarFont() {
if (usingVarFont) {
2018-09-30 22:34:27 +03:00
varSlantSettingValueImpl = true
if (varState.slant < = 0.1) {
varState.slant = 0
2018-09-10 20:21:55 +03:00
italicVar.setValue(false)
} else {
italicVar.setValue(true)
}
2018-09-30 22:34:27 +03:00
varSlantSettingValueImpl = false
2018-09-10 20:21:55 +03:00
setCSSProp(
"font-variation-settings",
2019-08-03 20:36:10 +03:00
`"wght" ${varState.weight}, "slnt" ${-varState.slant}`
2018-09-10 20:21:55 +03:00
)
} else {
setCSSProp("font-variation-settings", null)
}
}
2020-04-07 21:07:33 +03:00
vars.bind('varfont', (e, on, isInitial) => {
2018-09-10 20:21:55 +03:00
usingVarFont = on
2020-04-07 21:07:33 +03:00
document.body.classList.toggle('varfont', on)
2018-09-27 02:30:15 +03:00
if (on) {
2020-04-07 21:07:33 +03:00
if (!isInitial) {
// copy value of const weight to var weight
let w = parseInt(varWeight.getValue())
if (!isNaN(w) & & varWeightRange & & !varWeightSettingValueImpl) {
varWeightRange.setValue(w)
}
}
2020-04-09 04:56:06 +03:00
// document.body.style.fontFamily = (
// hinted ? fontFamilyNameVarHinted :
// fontFamilyNameVar
// )
2018-09-27 02:30:15 +03:00
} else {
2020-04-07 21:07:33 +03:00
if (!isInitial & & varWeightRange) {
// copy value of var weight to const weight
let w = varWeightRange.getValue()
if (!isNaN(w)) {
vars.setValue("weight", Math.round(w / 100) * 100)
}
}
2020-04-09 04:56:06 +03:00
// document.body.style.fontFamily = (
// hinted ? fontFamilyNameHinted :
// fontFamilyName
// );
2018-09-27 02:30:15 +03:00
}
2020-04-09 04:56:06 +03:00
document.body.style.fontFamily = getFontFamily()
2018-09-10 20:21:55 +03:00
updateVarFont()
})
let varWeightNum = vars.bind('varWeightNum', (e, v) => {
if (varWeightRange & & !varWeightSettingValueImpl) {
varWeightRange.setValue(v)
}
})
2018-09-30 22:34:27 +03:00
let varSlantNum = vars.bind('varSlantNum', (e, v) => {
if (varSlantRange & & !varSlantSettingValueImpl) {
varSlantRange.setValue(v)
2018-09-10 20:21:55 +03:00
}
})
varWeightRange = vars.bind('varWeight', (e, v) => {
varState.weight = v
varWeightSettingValueImpl = true
varWeightNum.setValue(v)
varWeightSettingValueImpl = false
updateVarFont()
}, (e, prevValue, ev) => {
if (prevValue === undefined) {
return 400
}
2020-04-07 21:07:33 +03:00
v = e.valueAsNumber
2020-04-09 04:56:06 +03:00
if (shiftKeyPressed & & (keyPressed == "" || keyPressed == "Shift")) {
2020-04-07 21:07:33 +03:00
v = Math.round(v / 100) * 100
}
return v
2018-09-10 20:21:55 +03:00
})
2018-09-30 22:34:27 +03:00
varSlantRange = vars.bind('varSlant', (e, v) => {
varState.slant = v
varSlantSettingValueImpl = true
varSlantNum.setValue(v)
varSlantSettingValueImpl = false
2018-09-10 20:21:55 +03:00
updateVarFont()
}, (e, prevValue, ev) => {
if (prevValue === undefined) {
return 0
}
return e.valueAsNumber !== undefined ? e.valueAsNumber : e.value
})
2017-08-22 21:53:36 +03:00
// compare
let secondarySampleClassNameAddition = null
2020-04-09 04:56:06 +03:00
let currentSecondarySampleClassName = null
function updateSecondarySample() {
setSecondarySampleClassName(currentSecondarySampleClassName)
}
2017-08-22 21:53:36 +03:00
const setSecondarySampleClassName = className => {
2020-04-09 04:56:06 +03:00
currentSecondarySampleClassName = className
2017-08-22 21:53:36 +03:00
if (secondarySampleClassNameAddition) {
2020-04-09 04:56:06 +03:00
secondarySample.style.fontFamily = null
2017-08-22 21:53:36 +03:00
secondarySample.classList.remove(secondarySampleClassNameAddition)
secondaryFontElements.forEach(e =>
e.classList.remove(secondarySampleClassNameAddition))
}
if (className) {
2020-04-09 04:56:06 +03:00
let explicitFontFamily = null
if (className == "inter-other-font") {
let otherFamily = usingFontFamily == "text" ? "display" : "text"
explicitFontFamily = getFontFamily(otherFamily)
}
secondarySample.style.fontFamily = explicitFontFamily
2017-08-22 21:53:36 +03:00
secondarySample.classList.add(className)
secondaryFontElements.forEach(e => e.classList.add(className))
}
secondarySampleClassNameAddition = className || null
}
const enableSecondarySample = className => {
setSecondarySampleClassName(className)
secondarySample.style.display = null
document.body.classList.remove('secondarySampleDisabled')
}
const disableSecondarySample = className => {
setSecondarySampleClassName(null)
secondarySample.style.display = 'none'
2020-04-09 04:56:06 +03:00
document.body.classList.add('secondarySampleDisabled')
2017-08-22 21:53:36 +03:00
}
vars.bind('compare', (e, v) => {
disableSecondarySample()
switch (v) {
2020-04-09 04:56:06 +03:00
// case 'roboto': enableSecondarySample('robotoFont'); break
case 'system': enableSecondarySample('systemFont'); break
case 'inter-other': enableSecondarySample('inter-other-font'); break
2017-08-22 21:53:36 +03:00
default: return '-';
}
}, e => (e.value & & e.value != '-') ? e.value : null)
2020-04-09 04:56:06 +03:00
vars.bind('family', (el, family, isInitial) => {
usingFontFamily = family
document.body.style.fontFamily = getFontFamily()
updateSecondarySample()
if (!isInitial) {
updateImplicitLetterSpacing()
}
})
2019-05-28 00:19:08 +03:00
2020-04-07 21:07:33 +03:00
let resetLineHeightButton = $('.reset-line-height')
let resetLetterSpacingButton = $('.reset-letter-spacing')
2020-04-09 04:56:06 +03:00
function calcImplicitLetterSpacing(size, el) {
let t = InterDynamicTracking(size, usingFontFamily)
let v = parseFloat((t * 100).toFixed(1))
;(el || letterSpacingVar.e).placeholder = v
return v
}
let letterSpacingVar = vars.bind('letterSpacing', (el, v) => {
2020-04-07 21:07:33 +03:00
resetLetterSpacingButton.classList.toggle("disabled", !v)
2020-04-09 04:56:06 +03:00
if (v) {
resetLetterSpacingButton.tabIndex = null
} else {
resetLetterSpacingButton.tabIndex = -1
}
2019-05-28 00:19:08 +03:00
if (!v) {
2020-04-09 04:56:06 +03:00
v = calcImplicitLetterSpacing(sizeVar.getValue(), el)
2019-05-28 00:19:08 +03:00
}
setCSSProp('letter-spacing', (v / 100) + 'em')
2020-04-09 04:56:06 +03:00
}, (el, prevValue, ev) => {
2019-05-28 00:19:08 +03:00
if (ev & & !ev.inputType & & !prevValue) {
// step increment/decrement
2020-04-09 04:56:06 +03:00
let delta = el.valueAsNumber == 0 ? -1 : el.valueAsNumber
return parseFloat(el.placeholder) + delta
2019-05-28 00:19:08 +03:00
}
2020-04-09 04:56:06 +03:00
return el.value || ""
2019-05-28 00:19:08 +03:00
})
2020-04-09 04:56:06 +03:00
function updateImplicitLetterSpacing() {
if (!letterSpacingVar.getValue()) {
v = calcImplicitLetterSpacing(sizeVar.getValue())
setCSSProp('letter-spacing', (v / 100) + 'em')
}
}
2019-05-28 00:19:08 +03:00
// update implicit letter spacing when size changes
sizeVar.onChange(size => {
let t = letterSpacingVar.lastValue
if (!t || isNaN(t)) {
2020-04-09 04:56:06 +03:00
updateImplicitLetterSpacing()
2019-05-28 00:19:08 +03:00
}
2017-08-22 21:53:36 +03:00
})
2020-04-07 21:07:33 +03:00
resetLetterSpacingButton.addEventListener('click', ev => {
2019-05-28 00:19:08 +03:00
vars.setValue('letterSpacing', '')
ev.stopPropagation()
ev.preventDefault()
}, {passive:false,capture:true})
2019-08-03 20:36:10 +03:00
2017-08-22 21:53:36 +03:00
vars.bind('lineHeight', lineHeightInput, (e, v) => {
setCSSProp('line-height', v ? v + 'px' : null)
2020-04-07 21:07:33 +03:00
resetLineHeightButton.classList.toggle("disabled", !v)
2020-04-09 04:56:06 +03:00
if (v) {
resetLineHeightButton.tabIndex = null
} else {
resetLineHeightButton.tabIndex = -1
}
2017-08-22 21:53:36 +03:00
}, (e, prevValue, ev) => {
if (ev & & !ev.inputType & & !prevValue) {
// step increment/decrement
let delta = e.valueAsNumber == 0 ? -1 : e.valueAsNumber
return parseFloat(e.placeholder) + delta
}
if (e.valueAsNumber < 0 ) {
return Math.abs(e.valueAsNumber)
}
2019-05-28 00:19:08 +03:00
return e.value || ""
})
2020-04-07 21:07:33 +03:00
resetLineHeightButton.addEventListener('click', ev => {
2019-05-28 00:19:08 +03:00
vars.setValue('lineHeight', '')
ev.stopPropagation()
ev.preventDefault()
}, {passive:false,capture:true})
2020-04-07 21:07:33 +03:00
vars.bind("invert-colors", (e, on) => {
2021-04-01 00:34:11 +03:00
if (defaultColorSceme == "dark")
2020-04-07 21:07:33 +03:00
on = !on
document.documentElement.classList.toggle('color-scheme-dark', on)
2017-08-22 21:53:36 +03:00
})
2021-04-01 00:34:11 +03:00
vars.bind("draw-sample-bg", (e, on) => {
document.documentElement.classList.toggle('draw-sample-background', on)
})
2017-08-22 21:53:36 +03:00
let spaaSelect = vars.bind('antialias', (e, v) => {
switch (v) {
case 'subpixel': {
setCSSProp('-webkit-font-smoothing', 'subpixel-antialiased')
setCSSProp('-moz-osx-font-smoothing', 'auto')
setCSSProp('font-smooth', 'always')
break
}
case 'greyscale': {
setCSSProp('-webkit-font-smoothing', 'antialiased')
setCSSProp('-moz-osx-font-smoothing', 'grayscale')
setCSSProp('font-smooth', null)
break
}
default: {
setCSSProp('-webkit-font-smoothing', 'initial')
setCSSProp('-moz-osx-font-smoothing', 'unset')
setCSSProp('font-smooth', null)
break
}
}
})
const ua = navigator.userAgent.toLowerCase()
if (ua.indexOf('win64') != -1 || ua.indexOf('win32') != -1) {
// Can't disable on Windows
vars.setValue('antialias', 'default')
spaaSelect.e.disabled = true
spaaSelect.e.parentElement.title = 'In Chrome, visit chrome:flags#lcd-text-aa to disable'
}
2018-02-15 20:48:22 +03:00
vars.bind('text-decoration', (e, v) => {
setVendorPrefixedCSSProp('text-decoration', e.value = v)
2017-08-22 21:53:36 +03:00
})
vars.bind('text-transform', (e, v) => {
setCSSProp('text-transform', e.value = v)
})
2019-01-22 03:57:49 +03:00
// vars.bind('variantCaps', (e, v) => {
// setCSSProp('font-variant-caps', e.value = v)
// })
2017-08-22 21:53:36 +03:00
2018-09-27 02:30:15 +03:00
// vars.bind('variantLigatures', (e, v) => {
// setCSSProp('font-variant-ligatures', e.value = v)
// })
// vars.bind('variantNumeric', (e, v) => {
// setCSSProp('font-variant-numeric', e.value = v)
// })
2017-08-22 21:53:36 +03:00
2019-02-04 01:01:11 +03:00
2019-05-28 00:19:08 +03:00
for (let e of $$('input.featopt')) {
2017-08-25 10:44:50 +03:00
let p = e.name.replace(/^feat\:/, '').split('=')
2019-02-04 01:01:11 +03:00
let name = p[0]
let valueOn = parseInt(p[1] || '1')
let valueOff = valueOn == 0 ? 1 : 0
let vr = vars.bind('feat-' + name, e, (e, on) => {
setFeature(name, on ? valueOn : valueOff, /*dontUpdateVar=*/true)
2017-08-22 21:53:36 +03:00
})
2019-02-04 01:01:11 +03:00
featVars.set(name, vr)
2017-08-22 21:53:36 +03:00
}
2019-02-04 01:01:11 +03:00
updateFeaturesStyle()
2017-08-22 21:53:36 +03:00
2019-02-04 01:01:11 +03:00
sampleVar = vars.bind('sample', samplesSelect, (e, v) => {
let sampleText = samples.get(v) || ''+v
if (v == 'Repertoire') {
repertoireControl.style.display = null
} else {
repertoireControl.style.display = 'none'
}
2017-08-22 21:53:36 +03:00
2019-02-04 01:01:11 +03:00
if (typeof sampleText == 'object' & & sampleText.toHTML) {
const html = sampleText.toHTML()
interUISample.innerHTML = html
secondarySample.innerHTML = html
} else {
// look for directive
// #!directive:value
2019-09-08 00:53:33 +03:00
// #!directive
2019-02-04 01:01:11 +03:00
sampleText = String(sampleText).replace(/^[\s\r\n\r]+|[\s\r\n\r]+$/g, '')
2019-09-08 00:53:33 +03:00
let m = /(?:^|\n)#\!([\w_\-]+)(?::(.+)|)(?:\n|$)/.exec(sampleText)
2019-02-04 01:01:11 +03:00
if (m) {
// parse directive
sampleText = (
sampleText.substring(0, m.index) +
sampleText.substr(m.index + m[0].length)
)
let directive = m[1].toLowerCase()
2019-05-28 00:19:08 +03:00
// console.log('dir', m[1], '=>', m[2])
2019-02-04 01:01:11 +03:00
if (directive == 'enablefeatures') {
// #!enableFeatures:tnum,dlig
for (let feat of m[2].toLowerCase().split(/\s*,\s*/)) {
setFeature(feat, 1)
}
2019-09-08 00:53:33 +03:00
} else if (directive == 'notrim') {
// #!notrim
// noop
2019-02-04 01:01:11 +03:00
} else {
console.warn(`ignoring unknown directive ${m[0]} in sample text`)
}
}
if (sampleText) {
interUISample.innerText = sampleText
secondarySample.innerText = sampleText
}
}
2017-08-22 21:53:36 +03:00
2019-02-04 01:01:11 +03:00
if (v == 'Repertoire') {
requestAnimationFrame(() => {
if (sizeVar) {
sizeVar.refreshValue(null)
}
})
2017-08-22 21:53:36 +03:00
}
})
2019-05-28 00:19:08 +03:00
// ESC clears keyboard focus
document.addEventListener('keydown', ev => {
2020-04-09 04:56:06 +03:00
if (ev.key == "Escape") {
2019-05-28 00:19:08 +03:00
document.activeElement.blur()
}
}/*, {capture:true, passive:false}*/)
2020-04-09 04:56:06 +03:00
requestAnimationFrame(()=>{
$$('input').forEach(el => {
if (el.type == "checkbox") {
el.addEventListener("click", ev => {
el.blur()
})
el.addEventListener('keypress', ev => {
if (ev.key == "Enter") {
el.value = !el.checked
el.checked = !el.checked
el.dispatchEvent(new Event("change"))
ev.stopPropagation()
ev.preventDefault()
}
},{passive:false, capture:true})
} else {
// RETURN on control clears keyboard focus
el.addEventListener('keypress', ev => {
if (ev.keyCode == 13) {
document.activeElement.blur()
}
})
}
})
})
2019-05-28 00:19:08 +03:00
// clear keyboard focus when a select control changes
$$('select').forEach(el => el.addEventListener('change', ev => {
document.activeElement.blur()
window.requestAnimationFrame(() => document.activeElement.blur())
}))
2017-08-22 21:53:36 +03:00
}
2019-05-28 00:19:08 +03:00
main();
document.title = (
(new Date()).toTimeString().split(':').slice(0,2).join(':') +
' — ' + (new Date()).toDateString()
);
})();< / script >
2017-08-22 21:53:36 +03:00
< / html >