diff --git a/nacc2/nacc.js b/nacc2/nacc.js
index 61dfcd3..5d0880f 100644
--- a/nacc2/nacc.js
+++ b/nacc2/nacc.js
@@ -1 +1 @@
-var NACC=(function(){var e={en:{section_title:`NA Cleantime Calculator`,prompt:`Please enter your Clean Date`,calculate_button_text:`Calculate`,change_layout_button_text:`Change Tag Layout`,change_use_special_tags_label:`Show Special Tags`,months:[`ERROR`,`January`,`February`,`March`,`April`,`May`,`June`,`July`,`August`,`September`,`October`,`November`,`December`],result_invalid:`Please select a valid clean date!`,result_1_day:`You have been clean for 1 day!`,result_days_format:`You have been clean for %d days!`,result_months_format:`This is %d months.`,result_months_and_1_day_format:`This is %d months and 1 day.`,result_months_and_days_format:`This is %d months and %d days.`,result_1_year:`This is 1 year.`,result_1_year_and_1_day:`This is 1 year and 1 day.`,result_1_year_and_1_month:`This is 1 year and 1 month.`,result_1_year_1_month_and_1_day:`This is 1 year, 1 month and 1 day.`,result_1_year_months_and_1_day_format:`This is 1 year, %d months and 1 day.`,result_1_year_months_and_days_format:`This is 1 year, %d months and %d days.`,result_1_year_days_format:`This is 1 year and %d days.`,result_years_format:`This is %d years.`,result_years_months_format:`This is %d years and %d months.`,result_years_1_month_and_1_day_format:`This is %d years, 1 month and 1 day.`,result_years_months_and_1_day_format:`This is %d years, %d months and 1 day.`,result_years_and_1_month_format:`This is %d years and 1 month.`,result_years_and_1_day_format:`This is %d years and 1 day.`,result_years_and_days_format:`This is %d years and %d days.`,result_years_1_month_and_days_format:`This is %d years, 1 month and %d days.`,result_years_months_and_days_format:`This is %d years, %d months and %d days.`},es:{section_title:`Calculadora de Tiempo Limpio NA`,prompt:`Por favor, entra tu fecha de inicio.`,calculate_button_text:`Calcular`,change_layout_button_text:`Cambiar los llaveros de posición.`,change_use_special_tags_label:`Mostrar Llaveros Especiales.`,months:[`ERROR`,`Enero`,`Febrero`,`Marzo`,`Abril`,`Mayo`,`Junio`,`Julio`,`Agosto`,`Septiembre`,`Octubre`,`Noviembre`,`Diciembre`],result_invalid:`¡Por favor, entra una fecha de inicio válido!`,result_1_day:`¡Has estado limpio por 1 día!`,result_days_format:`¡Has estado limpio por %d días!`,result_months_format:`Esto suma un total de %d meses.`,result_months_and_1_day_format:`Esto suma un total de %d meses y un día.`,result_months_and_days_format:`Esto suma un total de %d meses y %d días.`,result_1_year:`Esto suma un total de 1 año.`,result_1_year_and_1_day:`Esto suma un total de 1 año y 1 día.`,result_1_year_and_1_month:`Esto suma un total de 1 año y 1 mes.`,result_1_year_1_month_and_1_day:`Esto suma un total de 1 año, 1 mes y 1 día.`,result_1_year_months_and_1_day_format:`Esto suma un total de 1 año, %d meses y 1 día.`,result_1_year_months_and_days_format:`Esto suma un total de 1 año, %d meses y %d días.`,result_1_year_days_format:`Esto suma un total de 1 año y %d días.`,result_years_format:`Esto suma un total de %d años.`,result_years_months_format:`Esto suma un total de %d años y %d meses.`,result_years_1_month_and_1_day_format:`Esto suma un total de %d años, 1 mes y 1 día.`,result_years_months_and_1_day_format:`Esto suma un total de %d años, %d meses y 1 día.`,result_years_and_1_month_format:`Esto suma un total de %d años y 1 mes.`,result_years_and_1_day_format:`Esto suma un total de %d años y 1 día.`,result_years_and_days_format:`Esto suma un total de %d años y %d días.`,result_years_1_month_and_days_format:`Esto suma un total de %d años, 1 mes y %d días.`,result_years_months_and_days_format:`Esto suma un total de %d años, %d meses y %d días.`},it:{section_title:`NA Tempo di Pulizia`,prompt:`Inserisci la tua data di pulizia`,calculate_button_text:`Calcola`,change_layout_button_text:`Cambia presentazione dei portachiavi`,change_use_special_tags_label:`Mostra Tag Speciali`,months:[`ERRORE`,`gennaio`,`febbraio`,`marzo`,`aprile`,`maggio`,`giugno`,`luglio`,`agosto`,`settembre`,`ottobre`,`novembre`,`dicembre`],result_invalid:`Si prega di selezionare una data pulita valida!`,result_1_day:`Sei stato pulito per 1 giorno!`,result_days_format:`Sei pulito da %d giorni!`,result_months_format:`%d mesi.`,result_months_and_1_day_format:`%d mesi e 1 giorno.`,result_months_and_days_format:`%d mesi e %d giorni.`,result_1_year:`1 anno.`,result_1_year_and_1_day:`1 anno e 1 giorno.`,result_1_year_and_1_month:`1 anno e 1 mese.`,result_1_year_1_month_and_1_day:`1 anno, 1 mese e 1 giorno.`,result_1_year_months_and_1_day_format:`1 anno, %d mesi e 1 giorno.`,result_1_year_months_and_days_format:`1 anno, %d mesi e %d giorni.`,result_1_year_days_format:`1 year e %d giorni.`,result_years_format:`%d anni.`,result_years_months_format:`%d anni e %d mesi.`,result_years_1_month_and_1_day_format:`%d anni, 1 mese e 1 giorno.`,result_years_months_and_1_day_format:`%d anni, %d mesi e 1 giorno.`,result_years_and_1_month_format:`%d anni e 1 mese.`,result_years_and_1_day_format:`%d anni e 1 giorno.`,result_years_and_days_format:`%d anni e %d giorni.`,result_years_1_month_and_days_format:`%d anni, 1 mese e %d giorni.`,result_years_months_and_days_format:`%d anni, %d mesi e %d giorni.`},pt:{section_title:`Calculadora de Tempo Limpo`,prompt:`Entre com a data que ficou limpo`,calculate_button_text:`Calcular`,change_layout_button_text:`Mudar Layout das Fichas`,change_use_special_tags_label:`Mostrar fichas especiais`,months:[`ERROR`,`Janeiro`,`Fevereiro`,`Março`,`Abril`,`Maio`,`Junho`,`Julho`,`Agosto`,`Setembro`,`Outubro`,`Novembro`,`Dezembro`],result_invalid:`Selecione uma data válida!`,result_1_day:`Você está limpo há 1 dia!`,result_days_format:`Você está limpo %d dias!`,result_months_format:`Que são %d meses.`,result_months_and_1_day_format:`Que são %d meses e 1 dia.`,result_months_and_days_format:`Que são %d meses e %d dias.`,result_1_year:`Que é 1 ano.`,result_1_year_and_1_day:`Que é 1 ano e 1 dia.`,result_1_year_and_1_month:`Que é 1 ano e 1 mês.`,result_1_year_1_month_and_1_day:`Que é 1 ano, 1 mês e 1 dia.`,result_1_year_months_and_1_day_format:`Que é 1 ano, %d meses e 1 dia.`,result_1_year_months_and_days_format:`Que é 1 ano, %d meses e %d dias.`,result_1_year_days_format:`Que é 1 ano e %d dias.`,result_years_format:`Que são %d anos.`,result_years_months_format:`Que são %d anos e %d meses.`,result_years_1_month_and_1_day_format:`Que são %d anos, 1 mês e 1 dia.`,result_years_months_and_1_day_format:`Que são %d anos, %d meses e 1 dia.`,result_years_and_1_month_format:`Que são %d anos e 1 mês.`,result_years_and_1_day_format:`Que são %d anos e 1 dia.`,result_years_and_days_format:`Que são %d anos e %d dias.`,result_years_1_month_and_days_format:`Que são %d anos, 1 mês e %d dias.`,result_years_months_and_days_format:`Que são %d anos, %d meses e %d dias.`},"zh-Hans":{section_title:`NA 清醒时间计算器`,prompt:`请输入您的清醒日期`,calculate_button_text:`计算`,change_layout_button_text:`更改钥匙扣设置`,change_use_special_tags_label:`显示特殊钥匙扣`,months:[`错误`,`1月`,`2月`,`3月`,`4月`,`5月`,`6月`,`7月`,`8月`,`9月`,`10月`,`11月`,`12月`],result_invalid:`请选择一个有效的清醒日期`,result_1_day:`您已经清醒一天了!`,result_days_format:`您已经清醒%d天了!`,result_months_format:`这是%d个月了`,result_months_and_1_day_format:`这是%d个月零一天了.`,result_months_and_days_format:`这是%d个月%d天了.`,result_1_year:`这是一年了.`,result_1_year_and_1_day:`这是一年零一天了.`,result_1_year_and_1_month:`这是一年一个月了.`,result_1_year_1_month_and_1_day:`这是一年一个月零一天了.`,result_1_year_months_and_1_day_format:`这是一年,%d个月零一天了.`,result_1_year_months_and_days_format:`这是一年,%d个月%d天了.`,result_1_year_days_format:`这是一年,%d天了.`,result_years_format:`这是%d年了.`,result_years_months_format:`这是%d年%d月了.`,result_years_1_month_and_1_day_format:`这是%d年,一个月零一天了.`,result_years_months_and_1_day_format:`这是%d年,%d月零一天了.`,result_years_and_1_month_format:`这是%d年一个月了.`,result_years_and_1_day_format:`这是%d年零一天了.`,result_years_and_days_format:`这是%d年%d天了.`,result_years_1_month_and_days_format:`这是%d年,一个月%d天了.`,result_years_months_and_days_format:`这是%d个年,%d个月,%d天了.`},"zh-Hant":{section_title:`NA 清醒時間計算器`,prompt:`請輸入您的清醒日期`,calculate_button_text:`計算`,change_layout_button_text:`更改鑰匙扣設置`,change_use_special_tags_label:`顯示特殊鑰匙扣`,months:[`錯誤`,`1月`,`2月`,`3月`,`4月`,`5月`,`6月`,`7月`,`8月`,`9月`,`10月`,`11月`,`12月`],result_invalid:`請選擇一個有效的清醒日期`,result_1_day:`您已經清醒一天了!`,result_days_format:`您已经清醒%d天了!`,result_months_format:`這是%d個月了`,result_months_and_1_day_format:`這是%d個月零一天了.`,result_months_and_days_format:`這是%d個月%d天了.`,result_1_year:`這是一年了.`,result_1_year_and_1_day:`這是一年零一天了.`,result_1_year_and_1_month:`這是一年一個月了.`,result_1_year_1_month_and_1_day:`這是一年一個月零一天了.`,result_1_year_months_and_1_day_format:`這是一年,%d個月零一天了.`,result_1_year_months_and_days_format:`這是一年,%d個月%d天了.`,result_1_year_days_format:`這是一年,%d天了.`,result_years_format:`這是%d年了.`,result_years_months_format:`這是%d年%d月了.`,result_years_1_month_and_1_day_format:`這是%d年,一個月零一天了.`,result_years_months_and_1_day_format:`這是%d年,%d月零一天了.`,result_years_and_1_month_format:`這是%d年一個月了.`,result_years_and_1_day_format:`這是%d年零一天了.`,result_years_and_days_format:`這是%d年%d天了.`,result_years_1_month_and_days_format:`這是%d年,一個月%d天了.`,result_years_months_and_days_format:`這是%d個年,%d個月,%d天了.`}};function t(e,t=new Date){let n={totalDays:0,years:0,months:0,days:0};if(t<=e)return n;if(n.totalDays=Math.floor((t.getTime()-e.getTime())/864e5),n.years=t.getFullYear()-e.getFullYear(),n.months=t.getMonth()-e.getMonth(),n.days=t.getDate()-e.getDate(),n.days<0){let t=new Date(e.getFullYear(),e.getMonth()+1,0).getDate();--n.months,n.days+=t}return n.months<0&&(n.months+=12,--n.years),n}function n(e,...t){let n=0;return e.replace(/%d/g,()=>{let e=t[n++];return e==null?``:String(Math.floor(Number(e)))})}var r=class r{resultsDiv=null;resultsTextDiv=null;keytagsDiv=null;layoutToggleButton=null;specialTagsCheckbox=null;specialTagsLabel=null;constructor(t,n=null,i=null,a=null,o=!1,s=null){let c=document.getElementById(t);if(!c)throw alert(`NACC ERROR: INVALID CONTAINER ELEMENT ID`),Error(`NACC: no element with id "${t}"`);this.container=c;let l=r.getParameters(),u=l[`NACC-dir-root`]??s??``;u&&!u.endsWith(`/`)&&(u+=`/`),this.directoryRoot=u,this.styleSelector=l[`NACC-style`]??n??null,this.langCode=l[`NACC-lang`]??i??`en`,this.lang=e[this.langCode]??e.en;let d=l[`NACC-tag-layout`]??a;if(d===`linear`||d===`tabular`)this.tagLayout=d;else{let e=localStorage.getItem(`nacc_keytag_layout`);this.tagLayout=e===`tabular`?`tabular`:`linear`}l[`NACC-special-tags`]||o?this.showSpecialTags=!0:this.showSpecialTags=localStorage.getItem(`nacc_keytag_special`)===`true`,this.container.classList.add(`NACC-Instance`),this.styleSelector&&this.container.classList.add(this.styleSelector),this.container.innerHTML=``,this.createHeader(),this.createForm();let f=parseInt(l[`NACC-year`])||0,p=parseInt(l[`NACC-month`])||0,m=parseInt(l[`NACC-day`])||0,h=``;if(f&&p&&m)h=r.formatDate(f,p,m);else{let e=localStorage.getItem(`nacc_clean_date`);e&&/^\d{4}-\d{2}-\d{2}$/.test(e)&&(h=e)}h&&(this.dateInput.value=h,this.doCalculation())}static formatDate(e,t,n){return`${e}-${String(t).padStart(2,`0`)}-${String(n).padStart(2,`0`)}`}static getParameters(){return Object.fromEntries(new URLSearchParams(window.location.search))}doCalculation(){let e=this.dateInput.value;if(!e){this.displayCalculationResults({totalDays:0,years:0,months:0,days:0});return}let[n,r,i]=e.split(`-`).map(e=>parseInt(e,10)),a=t(new Date(n,r-1,i));this.displayCalculationResults(a)}onSubmit(){this.dateInput.value&&localStorage.setItem(`nacc_clean_date`,this.dateInput.value),this.doCalculation()}onToggleLayout(){this.tagLayout=this.tagLayout===`linear`?`tabular`:`linear`,localStorage.setItem(`nacc_keytag_layout`,this.tagLayout),this.doCalculation()}onToggleSpecial(){this.showSpecialTags=!this.showSpecialTags,localStorage.setItem(`nacc_keytag_special`,String(this.showSpecialTags)),this.doCalculation()}displayCalculationResults(e){let t=this.lang,r,i=``;e.totalDays===0?r=t.result_invalid:e.totalDays===1?r=t.result_1_day:(r=n(t.result_days_format,e.totalDays),e.totalDays>90&&(i=e.years>0?this.formatYearsBlurb(e):this.formatMonthsBlurb(e)));let a=e.years*12+e.months;this.createResultsDiv(e.totalDays,a,r,i)}formatYearsBlurb(e){let t=this.lang,{years:r,months:i,days:a}=e;if(r===1){if(i===0&&a===0)return t.result_1_year;if(i===1&&a===0)return t.result_1_year_and_1_month;if(i===1&&a===1)return t.result_1_year_1_month_and_1_day;if(i===0&&a===1)return t.result_1_year_and_1_day;if(i===0&&a>1)return n(t.result_1_year_days_format,a);if(i>1&&a>1)return n(t.result_1_year_months_and_days_format,i,a);if(i>1&&a===1)return n(t.result_1_year_months_and_1_day_format,i);if(i>1&&a===0)return n(t.result_years_months_format,1,i)}return i===0&&a===0?n(t.result_years_format,r):i===1&&a===0?n(t.result_years_and_1_month_format,r):i===0&&a===1?n(t.result_years_and_1_day_format,r):i===0&&a>1?n(t.result_years_and_days_format,r,a):i>1&&a===0?n(t.result_years_months_format,r,i):i===1&&a===1?n(t.result_years_1_month_and_1_day_format,r):i===1&&a>1?n(t.result_years_1_month_and_days_format,r,a):i>1&&a===1?n(t.result_years_months_and_1_day_format,r,i):n(t.result_years_months_and_days_format,r,i,a)}formatMonthsBlurb(e){let t=this.lang,{months:r,days:i}=e;return r>1&&i===0?n(t.result_months_format,r):r>1&&i===1?n(t.result_months_and_1_day_format,r):r>1&&i>1?n(t.result_months_and_days_format,r,i):``}el(e,t,n){let r=document.createElement(e);return t&&(r.className=t),n&&n.appendChild(r),r}static uniqueId(e){return`${e}-${Math.random().toString(36).slice(2,12)}`}createHeader(){let e=this.el(`div`,`NACC-Header`,this.container);e.innerHTML=this.lang.section_title}createForm(){let e=this.el(`form`,`NACC-Form`,this.container),t=this.el(`fieldset`,`NACC-Fieldset`,e),n=this.el(`legend`,`NACC-Legend`,t),r=this.el(`div`,`NACC-Legend-div`,n);this.promptLabel=this.el(`label`,`NACC-Prompt-Label`,r),this.promptLabel.innerHTML=this.lang.prompt,this.popupContainer=this.el(`div`,`NACC-Popups`,r),this.createDateInput(),this.createCalculateButton(),this.el(`div`,`breaker`,this.popupContainer)}createDateInput(){this.dateInput=this.el(`input`,`NACC-Date`,this.popupContainer),this.dateInput.id=r.uniqueId(`NACC-Date`),this.dateInput.type=`date`;let e=new Date,t=r.formatDate(e.getFullYear(),e.getMonth()+1,e.getDate());this.dateInput.min=`1953-01-01`,this.dateInput.max=t,this.dateInput.value=t,this.promptLabel.setAttribute(`for`,this.dateInput.id)}createCalculateButton(){this.calculateButton=this.el(`input`,`NACC-Calculate-Button`,this.popupContainer),this.calculateButton.type=`button`,this.calculateButton.value=this.lang.calculate_button_text,this.calculateButton.onclick=()=>this.onSubmit()}createResultsDiv(e,t,n,r){if(this.resultsDiv?(this.resultsDiv.innerHTML=``,this.resultsTextDiv=null,this.keytagsDiv=null):this.resultsDiv=this.el(`div`,`NACC-Results`,this.container.querySelector(`.NACC-Fieldset`)),n){this.resultsTextDiv=this.el(`div`,`NACC-Results-Text`,this.resultsDiv);let e=this.el(`div`,`NACC-Days`,this.resultsTextDiv);if(e.innerHTML=n,r){let e=this.el(`div`,`NACC-MainBlurb`,this.resultsTextDiv);e.innerHTML=r}}if(e>0){let n=this.tagLayout===`linear`?``:` NACC-Keytag-Tabular`;this.keytagsDiv=this.el(`div`,`NACC-Keytags`+n,this.resultsDiv),this.createTagsArray(e,t),this.ensureLayoutToggle()}}createKeytag(e,t,n){let r=`NACC-Keytag`+((n??!t)||this.tagLayout!==`linear`?` NACC-Keytag-Ringtop`:``),i=this.el(`img`,r,this.keytagsDiv),a=t?`_Front`:``;return i.src=`${this.directoryRoot}images/${this.langCode}/${e}${a}.png`,i}createTagsArray(e,t){let n=this.tagLayout===`linear`;if(e>=1){let e=this.createKeytag(`01`,n,!0);e.className+=` NACC-White-Tag`}if(e>=30&&this.createKeytag(`02`,n),e>=60&&this.createKeytag(`03`,n),e>=90&&this.createKeytag(`04`,n),e>90){t>5&&this.createKeytag(`05`,n),t>8&&this.createKeytag(`06`,n),t>11&&this.createKeytag(`07`,n),t>17&&this.createKeytag(`08`,n),t>23&&this.createKeytag(`09`,n);for(let r=24;r<=t-12;r+=12){let t=r+12,i=!1;this.showSpecialTags&&(t===60&&(i=!0,this.createKeytag(`15`,n)),t===120&&(i=!0,this.createKeytag(`10`,n)),t===180&&(i=!0,this.createKeytag(`16`,n)),!i&&t===300&&(i=!0,this.createKeytag(`12`,n)),!i&&t===360&&(i=!0,this.createKeytag(`14`,n)),!i&&t%120==0&&(i=!0,this.createKeytag(`11`,n))),i||this.createKeytag(`09`,n),this.showSpecialTags&&t===324&&e>9999&&this.createKeytag(`13`,n)}}}ensureLayoutToggle(){this.layoutToggleButton||(this.layoutToggleButton=this.el(`input`,`NACC-Change-Layout-Button`,this.popupContainer),this.layoutToggleButton.type=`button`,this.layoutToggleButton.value=this.lang.change_layout_button_text,this.layoutToggleButton.onclick=()=>this.onToggleLayout(),this.specialTagsCheckbox=this.el(`input`,`NACC-Show-Special-Tags-Checkbox`,this.popupContainer),this.specialTagsCheckbox.id=r.uniqueId(`NACC-Show-Special-Tags-Checkbox`),this.specialTagsCheckbox.type=`checkbox`,this.specialTagsCheckbox.checked=this.showSpecialTags,this.specialTagsCheckbox.value=`1`,this.specialTagsCheckbox.onclick=()=>this.onToggleSpecial(),this.specialTagsLabel=this.el(`label`,`NACC-Show-Special-Tags-Checkbox-Label`,this.popupContainer),this.specialTagsLabel.setAttribute(`for`,this.specialTagsCheckbox.id),this.specialTagsLabel.innerHTML=this.lang.change_use_special_tags_label,this.el(`div`,`breaker`,this.popupContainer))}};return window.NACC=r,r})();
\ No newline at end of file
+var NACC=(function(){var e={en:{section_title:`NA Cleantime Calculator`,prompt:`Please enter your Clean Date`,calculate_button_text:`Calculate`,change_layout_button_text:`Change Tag Layout`,change_use_special_tags_label:`Show Special Tags`,months:[`ERROR`,`January`,`February`,`March`,`April`,`May`,`June`,`July`,`August`,`September`,`October`,`November`,`December`],result_invalid:`Please select a valid clean date!`,result_1_day:`You have been clean for 1 day!`,result_days_format:`You have been clean for %d days!`,result_months_format:`This is %d months.`,result_months_and_1_day_format:`This is %d months and 1 day.`,result_months_and_days_format:`This is %d months and %d days.`,result_1_year:`This is 1 year.`,result_1_year_and_1_day:`This is 1 year and 1 day.`,result_1_year_and_1_month:`This is 1 year and 1 month.`,result_1_year_1_month_and_1_day:`This is 1 year, 1 month and 1 day.`,result_1_year_months_and_1_day_format:`This is 1 year, %d months and 1 day.`,result_1_year_months_and_days_format:`This is 1 year, %d months and %d days.`,result_1_year_days_format:`This is 1 year and %d days.`,result_years_format:`This is %d years.`,result_years_months_format:`This is %d years and %d months.`,result_years_1_month_and_1_day_format:`This is %d years, 1 month and 1 day.`,result_years_months_and_1_day_format:`This is %d years, %d months and 1 day.`,result_years_and_1_month_format:`This is %d years and 1 month.`,result_years_and_1_day_format:`This is %d years and 1 day.`,result_years_and_days_format:`This is %d years and %d days.`,result_years_1_month_and_days_format:`This is %d years, 1 month and %d days.`,result_years_months_and_days_format:`This is %d years, %d months and %d days.`},es:{section_title:`Calculadora de Tiempo Limpio NA`,prompt:`Por favor, entra tu fecha de inicio.`,calculate_button_text:`Calcular`,change_layout_button_text:`Cambiar los llaveros de posición.`,change_use_special_tags_label:`Mostrar Llaveros Especiales.`,months:[`ERROR`,`Enero`,`Febrero`,`Marzo`,`Abril`,`Mayo`,`Junio`,`Julio`,`Agosto`,`Septiembre`,`Octubre`,`Noviembre`,`Diciembre`],result_invalid:`¡Por favor, entra una fecha de inicio válido!`,result_1_day:`¡Has estado limpio por 1 día!`,result_days_format:`¡Has estado limpio por %d días!`,result_months_format:`Esto suma un total de %d meses.`,result_months_and_1_day_format:`Esto suma un total de %d meses y un día.`,result_months_and_days_format:`Esto suma un total de %d meses y %d días.`,result_1_year:`Esto suma un total de 1 año.`,result_1_year_and_1_day:`Esto suma un total de 1 año y 1 día.`,result_1_year_and_1_month:`Esto suma un total de 1 año y 1 mes.`,result_1_year_1_month_and_1_day:`Esto suma un total de 1 año, 1 mes y 1 día.`,result_1_year_months_and_1_day_format:`Esto suma un total de 1 año, %d meses y 1 día.`,result_1_year_months_and_days_format:`Esto suma un total de 1 año, %d meses y %d días.`,result_1_year_days_format:`Esto suma un total de 1 año y %d días.`,result_years_format:`Esto suma un total de %d años.`,result_years_months_format:`Esto suma un total de %d años y %d meses.`,result_years_1_month_and_1_day_format:`Esto suma un total de %d años, 1 mes y 1 día.`,result_years_months_and_1_day_format:`Esto suma un total de %d años, %d meses y 1 día.`,result_years_and_1_month_format:`Esto suma un total de %d años y 1 mes.`,result_years_and_1_day_format:`Esto suma un total de %d años y 1 día.`,result_years_and_days_format:`Esto suma un total de %d años y %d días.`,result_years_1_month_and_days_format:`Esto suma un total de %d años, 1 mes y %d días.`,result_years_months_and_days_format:`Esto suma un total de %d años, %d meses y %d días.`},it:{section_title:`NA Tempo di Pulizia`,prompt:`Inserisci la tua data di pulizia`,calculate_button_text:`Calcola`,change_layout_button_text:`Cambia presentazione dei portachiavi`,change_use_special_tags_label:`Mostra Tag Speciali`,months:[`ERRORE`,`gennaio`,`febbraio`,`marzo`,`aprile`,`maggio`,`giugno`,`luglio`,`agosto`,`settembre`,`ottobre`,`novembre`,`dicembre`],result_invalid:`Si prega di selezionare una data pulita valida!`,result_1_day:`Sei stato pulito per 1 giorno!`,result_days_format:`Sei pulito da %d giorni!`,result_months_format:`%d mesi.`,result_months_and_1_day_format:`%d mesi e 1 giorno.`,result_months_and_days_format:`%d mesi e %d giorni.`,result_1_year:`1 anno.`,result_1_year_and_1_day:`1 anno e 1 giorno.`,result_1_year_and_1_month:`1 anno e 1 mese.`,result_1_year_1_month_and_1_day:`1 anno, 1 mese e 1 giorno.`,result_1_year_months_and_1_day_format:`1 anno, %d mesi e 1 giorno.`,result_1_year_months_and_days_format:`1 anno, %d mesi e %d giorni.`,result_1_year_days_format:`1 year e %d giorni.`,result_years_format:`%d anni.`,result_years_months_format:`%d anni e %d mesi.`,result_years_1_month_and_1_day_format:`%d anni, 1 mese e 1 giorno.`,result_years_months_and_1_day_format:`%d anni, %d mesi e 1 giorno.`,result_years_and_1_month_format:`%d anni e 1 mese.`,result_years_and_1_day_format:`%d anni e 1 giorno.`,result_years_and_days_format:`%d anni e %d giorni.`,result_years_1_month_and_days_format:`%d anni, 1 mese e %d giorni.`,result_years_months_and_days_format:`%d anni, %d mesi e %d giorni.`},pt:{section_title:`Calculadora de Tempo Limpo`,prompt:`Entre com a data que ficou limpo`,calculate_button_text:`Calcular`,change_layout_button_text:`Mudar Layout das Fichas`,change_use_special_tags_label:`Mostrar fichas especiais`,months:[`ERROR`,`Janeiro`,`Fevereiro`,`Março`,`Abril`,`Maio`,`Junho`,`Julho`,`Agosto`,`Setembro`,`Outubro`,`Novembro`,`Dezembro`],result_invalid:`Selecione uma data válida!`,result_1_day:`Você está limpo há 1 dia!`,result_days_format:`Você está limpo %d dias!`,result_months_format:`Que são %d meses.`,result_months_and_1_day_format:`Que são %d meses e 1 dia.`,result_months_and_days_format:`Que são %d meses e %d dias.`,result_1_year:`Que é 1 ano.`,result_1_year_and_1_day:`Que é 1 ano e 1 dia.`,result_1_year_and_1_month:`Que é 1 ano e 1 mês.`,result_1_year_1_month_and_1_day:`Que é 1 ano, 1 mês e 1 dia.`,result_1_year_months_and_1_day_format:`Que é 1 ano, %d meses e 1 dia.`,result_1_year_months_and_days_format:`Que é 1 ano, %d meses e %d dias.`,result_1_year_days_format:`Que é 1 ano e %d dias.`,result_years_format:`Que são %d anos.`,result_years_months_format:`Que são %d anos e %d meses.`,result_years_1_month_and_1_day_format:`Que são %d anos, 1 mês e 1 dia.`,result_years_months_and_1_day_format:`Que são %d anos, %d meses e 1 dia.`,result_years_and_1_month_format:`Que são %d anos e 1 mês.`,result_years_and_1_day_format:`Que são %d anos e 1 dia.`,result_years_and_days_format:`Que são %d anos e %d dias.`,result_years_1_month_and_days_format:`Que são %d anos, 1 mês e %d dias.`,result_years_months_and_days_format:`Que são %d anos, %d meses e %d dias.`},"zh-Hans":{section_title:`NA 清醒时间计算器`,prompt:`请输入您的清醒日期`,calculate_button_text:`计算`,change_layout_button_text:`更改钥匙扣设置`,change_use_special_tags_label:`显示特殊钥匙扣`,months:[`错误`,`1月`,`2月`,`3月`,`4月`,`5月`,`6月`,`7月`,`8月`,`9月`,`10月`,`11月`,`12月`],result_invalid:`请选择一个有效的清醒日期`,result_1_day:`您已经清醒一天了!`,result_days_format:`您已经清醒%d天了!`,result_months_format:`这是%d个月了`,result_months_and_1_day_format:`这是%d个月零一天了.`,result_months_and_days_format:`这是%d个月%d天了.`,result_1_year:`这是一年了.`,result_1_year_and_1_day:`这是一年零一天了.`,result_1_year_and_1_month:`这是一年一个月了.`,result_1_year_1_month_and_1_day:`这是一年一个月零一天了.`,result_1_year_months_and_1_day_format:`这是一年,%d个月零一天了.`,result_1_year_months_and_days_format:`这是一年,%d个月%d天了.`,result_1_year_days_format:`这是一年,%d天了.`,result_years_format:`这是%d年了.`,result_years_months_format:`这是%d年%d月了.`,result_years_1_month_and_1_day_format:`这是%d年,一个月零一天了.`,result_years_months_and_1_day_format:`这是%d年,%d月零一天了.`,result_years_and_1_month_format:`这是%d年一个月了.`,result_years_and_1_day_format:`这是%d年零一天了.`,result_years_and_days_format:`这是%d年%d天了.`,result_years_1_month_and_days_format:`这是%d年,一个月%d天了.`,result_years_months_and_days_format:`这是%d个年,%d个月,%d天了.`},"zh-Hant":{section_title:`NA 清醒時間計算器`,prompt:`請輸入您的清醒日期`,calculate_button_text:`計算`,change_layout_button_text:`更改鑰匙扣設置`,change_use_special_tags_label:`顯示特殊鑰匙扣`,months:[`錯誤`,`1月`,`2月`,`3月`,`4月`,`5月`,`6月`,`7月`,`8月`,`9月`,`10月`,`11月`,`12月`],result_invalid:`請選擇一個有效的清醒日期`,result_1_day:`您已經清醒一天了!`,result_days_format:`您已经清醒%d天了!`,result_months_format:`這是%d個月了`,result_months_and_1_day_format:`這是%d個月零一天了.`,result_months_and_days_format:`這是%d個月%d天了.`,result_1_year:`這是一年了.`,result_1_year_and_1_day:`這是一年零一天了.`,result_1_year_and_1_month:`這是一年一個月了.`,result_1_year_1_month_and_1_day:`這是一年一個月零一天了.`,result_1_year_months_and_1_day_format:`這是一年,%d個月零一天了.`,result_1_year_months_and_days_format:`這是一年,%d個月%d天了.`,result_1_year_days_format:`這是一年,%d天了.`,result_years_format:`這是%d年了.`,result_years_months_format:`這是%d年%d月了.`,result_years_1_month_and_1_day_format:`這是%d年,一個月零一天了.`,result_years_months_and_1_day_format:`這是%d年,%d月零一天了.`,result_years_and_1_month_format:`這是%d年一個月了.`,result_years_and_1_day_format:`這是%d年零一天了.`,result_years_and_days_format:`這是%d年%d天了.`,result_years_1_month_and_days_format:`這是%d年,一個月%d天了.`,result_years_months_and_days_format:`這是%d個年,%d個月,%d天了.`}};function t(e,t=new Date){let n={totalDays:0,years:0,months:0,days:0};if(t<=e)return n;if(n.totalDays=Math.floor((t.getTime()-e.getTime())/864e5),n.years=t.getFullYear()-e.getFullYear(),n.months=t.getMonth()-e.getMonth(),n.days=t.getDate()-e.getDate(),n.days<0){let t=new Date(e.getFullYear(),e.getMonth()+1,0).getDate();--n.months,n.days+=t}return n.months<0&&(n.months+=12,--n.years),n}function n(e,...t){let n=0;return e.replace(/%d/g,()=>{let e=t[n++];return e==null?``:String(Math.floor(Number(e)))})}var r=class r{resultsDiv=null;resultsTextDiv=null;keytagsDiv=null;layoutToggleButton=null;specialTagsCheckbox=null;specialTagsLabel=null;constructor(t,n=null,i=null,a=null,o=!1,s=null,c=!0){let l=document.getElementById(t);if(!l)throw alert(`NACC ERROR: INVALID CONTAINER ELEMENT ID`),Error(`NACC: no element with id "${t}"`);this.container=l;let u=r.getParameters(),d=u[`NACC-dir-root`]??s??``;d&&!d.endsWith(`/`)&&(d+=`/`),this.directoryRoot=d,this.styleSelector=u[`NACC-style`]??n??null,this.langCode=u[`NACC-lang`]??i??`en`,this.lang=e[this.langCode]??e.en;let f=u[`NACC-tag-layout`]??a;if(f===`linear`||f===`tabular`)this.tagLayout=f;else{let e=localStorage.getItem(`nacc_keytag_layout`);this.tagLayout=e===`tabular`?`tabular`:`linear`}this.allowSpecialTags=c!==!1,this.allowSpecialTags?u[`NACC-special-tags`]||o?this.showSpecialTags=!0:this.showSpecialTags=localStorage.getItem(`nacc_keytag_special`)===`true`:this.showSpecialTags=!1,this.container.classList.add(`NACC-Instance`),this.styleSelector&&this.container.classList.add(this.styleSelector),this.container.innerHTML=``,this.createHeader(),this.createForm();let p=parseInt(u[`NACC-year`])||0,m=parseInt(u[`NACC-month`])||0,h=parseInt(u[`NACC-day`])||0,g=``;if(p&&m&&h)g=r.formatDate(p,m,h);else{let e=localStorage.getItem(`nacc_clean_date`);e&&/^\d{4}-\d{2}-\d{2}$/.test(e)&&(g=e)}g&&(this.dateInput.value=g,this.doCalculation())}static formatDate(e,t,n){return`${e}-${String(t).padStart(2,`0`)}-${String(n).padStart(2,`0`)}`}static getParameters(){return Object.fromEntries(new URLSearchParams(window.location.search))}doCalculation(){let e=this.dateInput.value;if(!e){this.displayCalculationResults({totalDays:0,years:0,months:0,days:0});return}let[n,r,i]=e.split(`-`).map(e=>parseInt(e,10)),a=t(new Date(n,r-1,i));this.displayCalculationResults(a)}onSubmit(){this.dateInput.value&&localStorage.setItem(`nacc_clean_date`,this.dateInput.value),this.doCalculation()}onToggleLayout(){this.tagLayout=this.tagLayout===`linear`?`tabular`:`linear`,localStorage.setItem(`nacc_keytag_layout`,this.tagLayout),this.doCalculation()}onToggleSpecial(){this.showSpecialTags=!this.showSpecialTags,localStorage.setItem(`nacc_keytag_special`,String(this.showSpecialTags)),this.doCalculation()}displayCalculationResults(e){let t=this.lang,r,i=``;e.totalDays===0?r=t.result_invalid:e.totalDays===1?r=t.result_1_day:(r=n(t.result_days_format,e.totalDays),e.totalDays>90&&(i=e.years>0?this.formatYearsBlurb(e):this.formatMonthsBlurb(e)));let a=e.years*12+e.months;this.createResultsDiv(e.totalDays,a,r,i)}formatYearsBlurb(e){let t=this.lang,{years:r,months:i,days:a}=e;if(r===1){if(i===0&&a===0)return t.result_1_year;if(i===1&&a===0)return t.result_1_year_and_1_month;if(i===1&&a===1)return t.result_1_year_1_month_and_1_day;if(i===0&&a===1)return t.result_1_year_and_1_day;if(i===0&&a>1)return n(t.result_1_year_days_format,a);if(i>1&&a>1)return n(t.result_1_year_months_and_days_format,i,a);if(i>1&&a===1)return n(t.result_1_year_months_and_1_day_format,i);if(i>1&&a===0)return n(t.result_years_months_format,1,i)}return i===0&&a===0?n(t.result_years_format,r):i===1&&a===0?n(t.result_years_and_1_month_format,r):i===0&&a===1?n(t.result_years_and_1_day_format,r):i===0&&a>1?n(t.result_years_and_days_format,r,a):i>1&&a===0?n(t.result_years_months_format,r,i):i===1&&a===1?n(t.result_years_1_month_and_1_day_format,r):i===1&&a>1?n(t.result_years_1_month_and_days_format,r,a):i>1&&a===1?n(t.result_years_months_and_1_day_format,r,i):n(t.result_years_months_and_days_format,r,i,a)}formatMonthsBlurb(e){let t=this.lang,{months:r,days:i}=e;return r>1&&i===0?n(t.result_months_format,r):r>1&&i===1?n(t.result_months_and_1_day_format,r):r>1&&i>1?n(t.result_months_and_days_format,r,i):``}el(e,t,n){let r=document.createElement(e);return t&&(r.className=t),n&&n.appendChild(r),r}static uniqueId(e){return`${e}-${Math.random().toString(36).slice(2,12)}`}createHeader(){let e=this.el(`div`,`NACC-Header`,this.container);e.innerHTML=this.lang.section_title}createForm(){let e=this.el(`form`,`NACC-Form`,this.container),t=this.el(`fieldset`,`NACC-Fieldset`,e),n=this.el(`legend`,`NACC-Legend`,t),r=this.el(`div`,`NACC-Legend-div`,n);this.promptLabel=this.el(`label`,`NACC-Prompt-Label`,r),this.promptLabel.innerHTML=this.lang.prompt,this.popupContainer=this.el(`div`,`NACC-Popups`,r),this.createDateInput(),this.createCalculateButton(),this.el(`div`,`breaker`,this.popupContainer)}createDateInput(){this.dateInput=this.el(`input`,`NACC-Date`,this.popupContainer),this.dateInput.id=r.uniqueId(`NACC-Date`),this.dateInput.type=`date`;let e=new Date,t=r.formatDate(e.getFullYear(),e.getMonth()+1,e.getDate());this.dateInput.min=`1953-01-01`,this.dateInput.max=t,this.dateInput.value=t,this.promptLabel.setAttribute(`for`,this.dateInput.id)}createCalculateButton(){this.calculateButton=this.el(`input`,`NACC-Calculate-Button`,this.popupContainer),this.calculateButton.type=`button`,this.calculateButton.value=this.lang.calculate_button_text,this.calculateButton.onclick=()=>this.onSubmit()}createResultsDiv(e,t,n,r){if(this.resultsDiv?(this.resultsDiv.innerHTML=``,this.resultsTextDiv=null,this.keytagsDiv=null):this.resultsDiv=this.el(`div`,`NACC-Results`,this.container.querySelector(`.NACC-Fieldset`)),n){this.resultsTextDiv=this.el(`div`,`NACC-Results-Text`,this.resultsDiv);let e=this.el(`div`,`NACC-Days`,this.resultsTextDiv);if(e.innerHTML=n,r){let e=this.el(`div`,`NACC-MainBlurb`,this.resultsTextDiv);e.innerHTML=r}}if(e>0){let n=this.tagLayout===`linear`?``:` NACC-Keytag-Tabular`;this.keytagsDiv=this.el(`div`,`NACC-Keytags`+n,this.resultsDiv),this.createTagsArray(e,t),this.ensureLayoutToggle()}}createKeytag(e,t,n){let r=`NACC-Keytag`+((n??!t)||this.tagLayout!==`linear`?` NACC-Keytag-Ringtop`:``),i=this.el(`img`,r,this.keytagsDiv),a=t?`_Front`:``;return i.src=`${this.directoryRoot}images/${this.langCode}/${e}${a}.png`,i}createTagsArray(e,t){let n=this.tagLayout===`linear`;if(e>=1){let e=this.createKeytag(`01`,n,!0);e.className+=` NACC-White-Tag`}if(e>=30&&this.createKeytag(`02`,n),e>=60&&this.createKeytag(`03`,n),e>=90&&this.createKeytag(`04`,n),e>90){t>5&&this.createKeytag(`05`,n),t>8&&this.createKeytag(`06`,n),t>11&&this.createKeytag(`07`,n),t>17&&this.createKeytag(`08`,n),t>23&&this.createKeytag(`09`,n);for(let r=24;r<=t-12;r+=12){let t=r+12,i=!1;this.showSpecialTags&&(t===60&&(i=!0,this.createKeytag(`15`,n)),t===120&&(i=!0,this.createKeytag(`10`,n)),t===180&&(i=!0,this.createKeytag(`16`,n)),!i&&t===300&&(i=!0,this.createKeytag(`12`,n)),!i&&t===360&&(i=!0,this.createKeytag(`14`,n)),!i&&t%120==0&&(i=!0,this.createKeytag(`11`,n))),i||this.createKeytag(`09`,n),this.showSpecialTags&&t===324&&e>9999&&this.createKeytag(`13`,n)}}}ensureLayoutToggle(){this.layoutToggleButton||(this.layoutToggleButton=this.el(`input`,`NACC-Change-Layout-Button`,this.popupContainer),this.layoutToggleButton.type=`button`,this.layoutToggleButton.value=this.lang.change_layout_button_text,this.layoutToggleButton.onclick=()=>this.onToggleLayout(),this.allowSpecialTags&&(this.specialTagsCheckbox=this.el(`input`,`NACC-Show-Special-Tags-Checkbox`,this.popupContainer),this.specialTagsCheckbox.id=r.uniqueId(`NACC-Show-Special-Tags-Checkbox`),this.specialTagsCheckbox.type=`checkbox`,this.specialTagsCheckbox.checked=this.showSpecialTags,this.specialTagsCheckbox.value=`1`,this.specialTagsCheckbox.onclick=()=>this.onToggleSpecial(),this.specialTagsLabel=this.el(`label`,`NACC-Show-Special-Tags-Checkbox-Label`,this.popupContainer),this.specialTagsLabel.setAttribute(`for`,this.specialTagsCheckbox.id),this.specialTagsLabel.innerHTML=this.lang.change_use_special_tags_label),this.el(`div`,`breaker`,this.popupContainer))}};return window.NACC=r,r})();
\ No newline at end of file
diff --git a/nacc2/src/nacc.js b/nacc2/src/nacc.js
index 58aaaf3..f2e9340 100644
--- a/nacc2/src/nacc.js
+++ b/nacc2/src/nacc.js
@@ -22,7 +22,8 @@ class NACC {
lang = null,
tagLayout = null,
showSpecialTags = false,
- directoryRoot = null
+ directoryRoot = null,
+ allowSpecialTags = true
) {
const container = document.getElementById(containerId);
if (!container) {
@@ -56,7 +57,13 @@ class NACC {
}
// Special tags
- if (params['NACC-special-tags'] || showSpecialTags) {
+ this.allowSpecialTags = allowSpecialTags !== false;
+ if (!this.allowSpecialTags) {
+ // Specialty keytags are fully disabled by the admin: force them off
+ // and ignore any prior visitor toggle stored in localStorage so a URL
+ // param or saved preference can't re-enable them.
+ this.showSpecialTags = false;
+ } else if (params['NACC-special-tags'] || showSpecialTags) {
this.showSpecialTags = true;
} else {
this.showSpecialTags = localStorage.getItem('nacc_keytag_special') === 'true';
@@ -363,16 +370,18 @@ class NACC {
this.layoutToggleButton.value = this.lang.change_layout_button_text;
this.layoutToggleButton.onclick = () => this.onToggleLayout();
- this.specialTagsCheckbox = this.el('input', 'NACC-Show-Special-Tags-Checkbox', this.popupContainer);
- this.specialTagsCheckbox.id = NACC.uniqueId('NACC-Show-Special-Tags-Checkbox');
- this.specialTagsCheckbox.type = 'checkbox';
- this.specialTagsCheckbox.checked = this.showSpecialTags;
- this.specialTagsCheckbox.value = '1';
- this.specialTagsCheckbox.onclick = () => this.onToggleSpecial();
-
- this.specialTagsLabel = this.el('label', 'NACC-Show-Special-Tags-Checkbox-Label', this.popupContainer);
- this.specialTagsLabel.setAttribute('for', this.specialTagsCheckbox.id);
- this.specialTagsLabel.innerHTML = this.lang.change_use_special_tags_label;
+ if (this.allowSpecialTags) {
+ this.specialTagsCheckbox = this.el('input', 'NACC-Show-Special-Tags-Checkbox', this.popupContainer);
+ this.specialTagsCheckbox.id = NACC.uniqueId('NACC-Show-Special-Tags-Checkbox');
+ this.specialTagsCheckbox.type = 'checkbox';
+ this.specialTagsCheckbox.checked = this.showSpecialTags;
+ this.specialTagsCheckbox.value = '1';
+ this.specialTagsCheckbox.onclick = () => this.onToggleSpecial();
+
+ this.specialTagsLabel = this.el('label', 'NACC-Show-Special-Tags-Checkbox-Label', this.popupContainer);
+ this.specialTagsLabel.setAttribute('for', this.specialTagsCheckbox.id);
+ this.specialTagsLabel.innerHTML = this.lang.change_use_special_tags_label;
+ }
this.el('div', 'breaker', this.popupContainer);
}
diff --git a/readme.txt b/readme.txt
index 658d3a1..f4cccc5 100644
--- a/readme.txt
+++ b/readme.txt
@@ -27,6 +27,7 @@ That text will be replaced with this cleantime calculator.
6. You can change the language like so: `[nacc language="es"]`, where `language` is currently `en` (English -Default), `pt` (Portuguese), `es` (Spanish), `zh-Hans` (Simplified Chinese), `zh-Hant` (Traditional Chinese), or `it` (Italian).
7. You can specify which layout (vertical or horizontal) you want the tags to appear in by default, like so: `[nacc layout="tabular"]`, where `layout` is `linear` (default, in a long line), or `tabular` (In a horizontal row).
8. You can specify whether the "special" tags are shown, like so: `[nacc special="1"]`, where `special` is `1` for true or `0` for false.
+9. You can control whether visitors may toggle the specialty keytags themselves, like so: `[nacc allow_special="0"]`, where `allow_special` is `1` (default) to show the visitor toggle, or `0` to hide the toggle entirely and fully disable specialty keytags (the saved visitor preference in localStorage is ignored).
== Changelog ==
@@ -34,6 +35,7 @@ That text will be replaced with this cleantime calculator.
* Fixed the "Show Special Keytags" default so that specialty (over 2 years) tags stay hidden until the setting is explicitly enabled, matching the unchecked checkbox and "Default is false." label.
* Added a "How to Use" help section to the Settings → NACC admin page documenting the `[nacc]` shortcode, its attributes, and what each setting does.
+* Added an "Allow visitors to toggle specialty keytags" admin setting (Settings → NACC) and a matching `allow_special` shortcode attribute. When disabled, the in-widget specialty-keytags toggle is not rendered and the specialty tags are fully off (any saved visitor preference in localStorage is ignored).
= 6.0.1 =