Temp
This commit is contained in:
parent
6bb932a371
commit
7c73101ef4
@ -163,10 +163,12 @@ class InputField {
|
||||
//this.onLengthChange && this.onLengthChange(inputLength, isError);
|
||||
|
||||
if(isError || diff <= showLengthOn) {
|
||||
labelEl.innerText = label + ` (${maxLength - inputLength})`;
|
||||
labelEl.innerHTML = '';
|
||||
labelEl.append(i18n(label), ` (${maxLength - inputLength})`);
|
||||
if(!showingLength) showingLength = true;
|
||||
} else if((wasError && !isError) || showingLength) {
|
||||
labelEl.innerText = label;
|
||||
labelEl.innerHTML = '';
|
||||
labelEl.append(i18n(label));
|
||||
showingLength = false;
|
||||
}
|
||||
};
|
||||
@ -244,7 +246,7 @@ class InputField {
|
||||
this.input.classList.toggle('valid', !!(state & InputState.Valid));
|
||||
}
|
||||
|
||||
public setError(label?: string) {
|
||||
public setError(label?: LangPackKey) {
|
||||
this.setState(InputState.Error, label);
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,18 @@
|
||||
import PopupElement, { addCancelButton, PopupButton, PopupOptions } from ".";
|
||||
import { LangPackKey, _i18n } from "../../lib/langPack";
|
||||
|
||||
export default class PopupConfirmAction extends PopupElement {
|
||||
constructor(className: string, buttons: PopupButton[], options: PopupOptions & Partial<{title: string, text: string}> = {}) {
|
||||
constructor(className: string, buttons: PopupButton[], options: PopupOptions & {title: LangPackKey, text: LangPackKey}) {
|
||||
super('popup-peer popup-confirm-action ' + className, addCancelButton(buttons), {
|
||||
overlayClosable: true,
|
||||
...options
|
||||
});
|
||||
|
||||
this.title.innerHTML = options.title || 'Warning';
|
||||
_i18n(this.title, options.title);
|
||||
|
||||
const p = document.createElement('p');
|
||||
p.classList.add('popup-description');
|
||||
p.innerHTML = options.text;
|
||||
_i18n(p, options.text);
|
||||
|
||||
this.container.insertBefore(p, this.header.nextElementSibling);
|
||||
}
|
||||
|
@ -3,10 +3,13 @@ import { blurActiveElement, findUpClassName } from "../../helpers/dom";
|
||||
import { ripple } from "../ripple";
|
||||
import animationIntersector from "../animationIntersector";
|
||||
import appNavigationController, { NavigationItem } from "../appNavigationController";
|
||||
import { i18n, LangPackKey } from "../../lib/langPack";
|
||||
|
||||
export type PopupButton = {
|
||||
text: string,
|
||||
text?: string,
|
||||
callback?: () => void,
|
||||
langKey?: LangPackKey,
|
||||
langArgs?: any[],
|
||||
isDanger?: true,
|
||||
isCancel?: true
|
||||
};
|
||||
@ -89,7 +92,13 @@ export default class PopupElement {
|
||||
const buttonsElements = buttons.map(b => {
|
||||
const button = document.createElement('button');
|
||||
button.className = 'btn' + (b.isDanger ? ' danger' : ' primary');
|
||||
button.innerHTML = b.text;
|
||||
|
||||
if(b.text) {
|
||||
button.innerHTML = b.text;
|
||||
} else {
|
||||
button.append(i18n(b.langKey, b.langArgs));
|
||||
}
|
||||
|
||||
ripple(button);
|
||||
|
||||
if(b.callback) {
|
||||
@ -157,7 +166,7 @@ export const addCancelButton = (buttons: PopupButton[]) => {
|
||||
const button = buttons.find(b => b.isCancel);
|
||||
if(!button) {
|
||||
buttons.push({
|
||||
text: 'CANCEL',
|
||||
langKey: 'Cancel',
|
||||
isCancel: true
|
||||
});
|
||||
}
|
||||
|
@ -21,16 +21,17 @@ export default class PopupPickUser extends PopupElement {
|
||||
appendTo: this.body,
|
||||
onChange: async() => {
|
||||
const peerId = this.selector.getSelected()[0];
|
||||
this.btnClose.click();
|
||||
|
||||
|
||||
this.selector = null;
|
||||
|
||||
|
||||
if(options.onSelect) {
|
||||
const res = options.onSelect(peerId);
|
||||
if(res instanceof Promise) {
|
||||
await res;
|
||||
}
|
||||
}
|
||||
|
||||
this.hide();
|
||||
},
|
||||
peerType: options.peerTypes,
|
||||
onFirstRender: () => {
|
||||
|
@ -2,6 +2,7 @@ import { randomLong } from "../helpers/random";
|
||||
import { InputPrivacyKey, InputPrivacyRule } from "../layer";
|
||||
import appPrivacyManager, { PrivacyType } from "../lib/appManagers/appPrivacyManager";
|
||||
import appUsersManager from "../lib/appManagers/appUsersManager";
|
||||
import { i18n, join, LangPackKey, _i18n } from "../lib/langPack";
|
||||
import RadioField from "./radioField";
|
||||
import Row, { RadioFormFromRows } from "./row";
|
||||
import Scrollable from "./scrollable";
|
||||
@ -9,15 +10,16 @@ import { SettingSection, generateSection } from "./sidebarLeft";
|
||||
import AppAddMembersTab from "./sidebarLeft/tabs/addMembers";
|
||||
import { SliderSuperTabEventable } from "./sliderTab";
|
||||
|
||||
type PrivacySectionStr = LangPackKey | '';
|
||||
export default class PrivacySection {
|
||||
public radioRows: Map<PrivacyType, Row>;
|
||||
public radioSection: SettingSection;
|
||||
public exceptions: Map<keyof PrivacySection['peerIds'], {
|
||||
title: string,
|
||||
titleLangKey: LangPackKey,
|
||||
key: keyof PrivacySection['peerIds'],
|
||||
row: Row,
|
||||
icon: string,
|
||||
subtitle: string,
|
||||
subtitleLangKey: LangPackKey,
|
||||
clickable: true
|
||||
}>;
|
||||
public peerIds: {
|
||||
@ -28,32 +30,32 @@ export default class PrivacySection {
|
||||
|
||||
constructor(public options: {
|
||||
tab: SliderSuperTabEventable,
|
||||
title: string,
|
||||
title: LangPackKey,
|
||||
inputKey: InputPrivacyKey['_'],
|
||||
captions?: [string, string, string],
|
||||
captions?: [PrivacySectionStr, PrivacySectionStr, PrivacySectionStr],
|
||||
appendTo?: Scrollable,
|
||||
noExceptions?: boolean,
|
||||
onRadioChange?: (value: number) => any,
|
||||
skipTypes?: PrivacyType[],
|
||||
exceptionTexts?: [string, string]
|
||||
exceptionTexts?: [LangPackKey, LangPackKey]
|
||||
}) {
|
||||
if(options.captions) {
|
||||
options.captions.reverse();
|
||||
}
|
||||
|
||||
this.radioSection = new SettingSection({name: options.title, caption: ' '});
|
||||
this.radioSection = new SettingSection({name: options.title, caption: true});
|
||||
|
||||
this.radioRows = new Map();
|
||||
|
||||
let r = [{
|
||||
let r: Array<{type: PrivacyType, langKey: LangPackKey}> = [{
|
||||
type: PrivacyType.Everybody,
|
||||
text: 'Everybody'
|
||||
langKey: 'PrivacySettingsController.Everbody'
|
||||
}, {
|
||||
type: PrivacyType.Contacts,
|
||||
text: 'My Contacts'
|
||||
langKey: 'PrivacySettingsController.MyContacts'
|
||||
}, {
|
||||
type: PrivacyType.Nobody,
|
||||
text: 'Nobody'
|
||||
langKey: 'PrivacySettingsController.Nobody'
|
||||
}];
|
||||
|
||||
if(options.skipTypes) {
|
||||
@ -61,10 +63,10 @@ export default class PrivacySection {
|
||||
}
|
||||
|
||||
const random = randomLong();
|
||||
r.forEach(({type, text}) => {
|
||||
r.forEach(({type, langKey}) => {
|
||||
const row = new Row({
|
||||
radioField: new RadioField({
|
||||
text,
|
||||
langKey,
|
||||
name: random,
|
||||
value: '' + type
|
||||
})
|
||||
@ -81,26 +83,26 @@ export default class PrivacySection {
|
||||
}
|
||||
|
||||
if(!options.noExceptions) {
|
||||
const container = generateSection(options.appendTo, 'Exceptions', 'You can add users or entire groups as exceptions that will override settings above.');
|
||||
const container = generateSection(options.appendTo, 'PrivacyExceptions', 'PrivacySettingsController.PeerInfo');
|
||||
|
||||
this.exceptions = new Map([[
|
||||
'disallow',
|
||||
{
|
||||
title: options.exceptionTexts[0],
|
||||
titleLangKey: options.exceptionTexts[0],
|
||||
key: 'disallow',
|
||||
row: null,
|
||||
icon: 'deleteuser',
|
||||
subtitle: 'Add Users',
|
||||
subtitleLangKey: 'PrivacySettingsController.AddUsers',
|
||||
clickable: true
|
||||
}
|
||||
], [
|
||||
'allow',
|
||||
{
|
||||
title: options.exceptionTexts[1],
|
||||
titleLangKey: options.exceptionTexts[1],
|
||||
key: 'allow',
|
||||
row: null,
|
||||
icon: 'adduser',
|
||||
subtitle: 'Add Users',
|
||||
subtitleLangKey: 'PrivacySettingsController.AddUsers',
|
||||
clickable: true
|
||||
}
|
||||
]]);
|
||||
@ -114,12 +116,13 @@ export default class PrivacySection {
|
||||
new AppAddMembersTab(options.tab.slider).open({
|
||||
type: 'privacy',
|
||||
skippable: true,
|
||||
title: exception.title,
|
||||
title: exception.titleLangKey,
|
||||
placeholder: 'Add Users or Groups...',
|
||||
takeOut: (newPeerIds) => {
|
||||
_peerIds.length = 0;
|
||||
_peerIds.push(...newPeerIds);
|
||||
exception.row.subtitle.innerHTML = this.generateStr(this.splitPeersByType(newPeerIds));
|
||||
exception.row.subtitle.innerHTML = '';
|
||||
exception.row.subtitle.append(...this.generateStr(this.splitPeersByType(newPeerIds)));
|
||||
},
|
||||
selectedPeerIds: _peerIds
|
||||
});
|
||||
@ -146,7 +149,9 @@ export default class PrivacySection {
|
||||
arr.push(...from.users);
|
||||
arr.push(...from.chats.map(id => -id));
|
||||
this.peerIds[k] = arr;
|
||||
this.exceptions.get(k).row.subtitle.innerHTML = this.generateStr(from);
|
||||
const s = this.exceptions.get(k).row.subtitle;
|
||||
s.innerHTML = '';
|
||||
s.append(...this.generateStr(from));
|
||||
});
|
||||
}
|
||||
|
||||
@ -204,7 +209,11 @@ export default class PrivacySection {
|
||||
|
||||
const caption = this.options.captions[this.type];
|
||||
const captionElement = this.radioSection.caption;
|
||||
captionElement.innerHTML = caption;
|
||||
if(!caption) {
|
||||
captionElement.innerHTML = '';
|
||||
} else {
|
||||
_i18n(captionElement, caption);
|
||||
}
|
||||
captionElement.classList.toggle('hide', !caption);
|
||||
|
||||
if(this.exceptions) {
|
||||
@ -230,14 +239,14 @@ export default class PrivacySection {
|
||||
return peers;
|
||||
}
|
||||
|
||||
private generateStr(peers: {users: number[], chats: number[]}) {
|
||||
private generateStr(peers: {users: number[], chats: number[]}): HTMLElement[] {
|
||||
if(!peers.users.length && !peers.chats.length) {
|
||||
return 'Add Users';
|
||||
return [i18n('PrivacySettingsController.AddUsers')];
|
||||
}
|
||||
|
||||
return [
|
||||
peers.users.length ? peers.users.length + ' ' + (peers.users.length === 1 ? 'user' : 'users') : '',
|
||||
peers.chats.length ? peers.chats.length + ' ' + (peers.chats.length === 1 ? 'chat' : 'chats') : ''
|
||||
].filter(Boolean).join(', ');
|
||||
return join([
|
||||
peers.users.length ? i18n('Users', [peers.users.length]) : null,
|
||||
peers.chats.length ? i18n('Chats', [peers.chats.length]) : null
|
||||
].filter(Boolean), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,8 @@ export default class RadioField {
|
||||
public main: HTMLElement;
|
||||
|
||||
constructor(options: {
|
||||
text?: LangPackKey,
|
||||
text?: string,
|
||||
langKey?: LangPackKey,
|
||||
name: string,
|
||||
value?: string,
|
||||
stateKey?: string
|
||||
@ -38,7 +39,7 @@ export default class RadioField {
|
||||
main.classList.add('radio-field-main');
|
||||
|
||||
if(options.text) {
|
||||
_i18n(main, options.text);
|
||||
main.innerHTML = options.text;
|
||||
/* const caption = document.createElement('div');
|
||||
caption.classList.add('radio-field-main-caption');
|
||||
caption.innerHTML = text;
|
||||
@ -49,6 +50,8 @@ export default class RadioField {
|
||||
}
|
||||
|
||||
main.append(caption); */
|
||||
} else if(options.langKey) {
|
||||
_i18n(main, options.langKey);
|
||||
}
|
||||
|
||||
label.append(input, main);
|
||||
|
@ -437,7 +437,7 @@ export class SettingSection {
|
||||
|
||||
constructor(options: {
|
||||
name?: LangPackKey,
|
||||
caption?: string,
|
||||
caption?: LangPackKey | true,
|
||||
noDelimiter?: boolean
|
||||
}) {
|
||||
this.container = document.createElement('div');
|
||||
@ -462,7 +462,10 @@ export class SettingSection {
|
||||
if(options.caption) {
|
||||
this.caption = this.generateContentElement();
|
||||
this.caption.classList.add('sidebar-left-section-caption');
|
||||
this.caption.innerHTML = options.caption;
|
||||
|
||||
if(options.caption !== true) {
|
||||
i18n_({element: this.caption, key: options.caption});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -474,7 +477,7 @@ export class SettingSection {
|
||||
}
|
||||
}
|
||||
|
||||
export const generateSection = (appendTo: Scrollable, name?: LangPackKey, caption?: string) => {
|
||||
export const generateSection = (appendTo: Scrollable, name?: LangPackKey, caption?: LangPackKey) => {
|
||||
const section = new SettingSection({name, caption});
|
||||
appendTo.append(section.container);
|
||||
return section.content;
|
||||
|
@ -11,6 +11,7 @@ import PopupConfirmAction from "../../popups/confirmAction";
|
||||
import apiManager from "../../../lib/mtproto/mtprotoworker";
|
||||
import { toast } from "../../toast";
|
||||
import AppPrivacyAndSecurityTab from "./privacyAndSecurity";
|
||||
import I18n from "../../../lib/langPack";
|
||||
|
||||
export default class AppActiveSessionsTab extends SliderSuperTab {
|
||||
public privacyTab: AppPrivacyAndSecurityTab;
|
||||
@ -19,7 +20,7 @@ export default class AppActiveSessionsTab extends SliderSuperTab {
|
||||
|
||||
protected init() {
|
||||
this.container.classList.add('active-sessions-container');
|
||||
this.title.innerText = 'Active Sessions';
|
||||
this.setTitle('SessionsTitle');
|
||||
|
||||
const Session = (auth: Authorization.authorization) => {
|
||||
const row = new Row({
|
||||
@ -44,7 +45,7 @@ export default class AppActiveSessionsTab extends SliderSuperTab {
|
||||
|
||||
{
|
||||
const section = new SettingSection({
|
||||
name: 'Current Session'
|
||||
name: 'CurrentSession'
|
||||
});
|
||||
|
||||
const auth = authorizations.findAndSplice(auth => auth.pFlags.current);
|
||||
@ -53,10 +54,10 @@ export default class AppActiveSessionsTab extends SliderSuperTab {
|
||||
section.content.append(session.container);
|
||||
|
||||
if(authorizations.length) {
|
||||
const btnTerminate = Button('btn-primary btn-transparent danger', {icon: 'stop', text: 'Terminate all other sessions'});
|
||||
const btnTerminate = Button('btn-primary btn-transparent danger', {icon: 'stop', text: 'TerminateAllSessions'});
|
||||
attachClickEvent(btnTerminate, (e) => {
|
||||
new PopupConfirmAction('revoke-session', [{
|
||||
text: 'TERMINATE',
|
||||
langKey: 'Terminate',
|
||||
isDanger: true,
|
||||
callback: () => {
|
||||
const toggle = toggleDisability([btnTerminate], true);
|
||||
@ -70,8 +71,8 @@ export default class AppActiveSessionsTab extends SliderSuperTab {
|
||||
});
|
||||
}
|
||||
}], {
|
||||
title: 'Terminate All Other Sessions',
|
||||
text: 'Are you sure you want to terminate all other sessions?'
|
||||
title: 'AreYouSureSessionsTitle',
|
||||
text: 'AreYouSureSessions'
|
||||
}).show();
|
||||
});
|
||||
|
||||
@ -86,7 +87,7 @@ export default class AppActiveSessionsTab extends SliderSuperTab {
|
||||
}
|
||||
|
||||
const otherSection = new SettingSection({
|
||||
name: 'Other Sessions'
|
||||
name: 'OtherSessions'
|
||||
});
|
||||
|
||||
authorizations.forEach(auth => {
|
||||
@ -97,7 +98,7 @@ export default class AppActiveSessionsTab extends SliderSuperTab {
|
||||
|
||||
const onError = (err: any) => {
|
||||
if(err.type === 'FRESH_RESET_AUTHORISATION_FORBIDDEN') {
|
||||
toast('For security reasons, you can\'t terminate older sessions from a device that you\'ve just connected. Please use an earlier connection or wait for a few hours.');
|
||||
toast(I18n.getString('RecentSessions.Error.FreshReset'));
|
||||
}
|
||||
};
|
||||
|
||||
@ -106,7 +107,7 @@ export default class AppActiveSessionsTab extends SliderSuperTab {
|
||||
const hash = target.dataset.hash;
|
||||
|
||||
new PopupConfirmAction('revoke-session', [{
|
||||
text: 'TERMINATE',
|
||||
langKey: 'Terminate',
|
||||
isDanger: true,
|
||||
callback: () => {
|
||||
apiManager.invokeApi('account.resetAuthorization', {hash})
|
||||
@ -118,8 +119,8 @@ export default class AppActiveSessionsTab extends SliderSuperTab {
|
||||
}, onError);
|
||||
}
|
||||
}], {
|
||||
title: 'Terminate Session',
|
||||
text: 'Do you want to terminate this session?'
|
||||
title: 'AreYouSureSessionTitle',
|
||||
text: 'TerminateSessionText'
|
||||
}).show();
|
||||
};
|
||||
|
||||
|
@ -8,7 +8,7 @@ export default class AppArchivedTab extends SliderSuperTab {
|
||||
|
||||
init() {
|
||||
this.container.id = 'chats-archived-container';
|
||||
this.title.innerHTML = 'Archived Chats';
|
||||
this.setTitle('ArchivedChats');
|
||||
|
||||
//this.scrollable = new Scrollable(this.container, 'CLA', 500);
|
||||
this.scrollable.append(appDialogsManager.chatListArchived);
|
||||
|
@ -15,11 +15,11 @@ export default class AppBlockedUsersTab extends SliderSuperTab {
|
||||
|
||||
protected init() {
|
||||
this.container.classList.add('blocked-users-container');
|
||||
this.title.innerText = 'Blocked Users';
|
||||
this.setTitle('BlockedUsers');
|
||||
|
||||
{
|
||||
const section = new SettingSection({
|
||||
caption: 'Blocked users will not be able to contact you and will not see your Last Seen time.'
|
||||
caption: 'BlockedUsersInfo'
|
||||
});
|
||||
|
||||
this.scrollable.append(section.container);
|
||||
|
@ -91,7 +91,7 @@ export default class AppGeneralSettingsTab extends SliderSuperTab {
|
||||
|
||||
const enterRow = new Row({
|
||||
radioField: new RadioField({
|
||||
text: 'General.SendShortcut.Enter',
|
||||
langKey: 'General.SendShortcut.Enter',
|
||||
name: 'send-shortcut',
|
||||
value: 'enter',
|
||||
stateKey: 'settings.sendShortcut'
|
||||
|
@ -96,7 +96,7 @@ export default class AppIncludedChatsTab extends SliderSuperTab {
|
||||
});
|
||||
|
||||
this.dialogsByFilters = new Map();
|
||||
appMessagesManager.filtersStorage.getDialogFilters().then(filters => {
|
||||
return appMessagesManager.filtersStorage.getDialogFilters().then(filters => {
|
||||
for(const filter of filters) {
|
||||
this.dialogsByFilters.set(filter, new Set(appMessagesManager.dialogsStorage.getFolder(filter.id).map(d => d.peerId)));
|
||||
}
|
||||
@ -146,21 +146,6 @@ export default class AppIncludedChatsTab extends SliderSuperTab {
|
||||
joined.forEach(el => {
|
||||
dom.lastMessageSpan.append(el);
|
||||
});
|
||||
/* let subtitle: LangPackKey;
|
||||
|
||||
if(peerId > 0) {
|
||||
if(peerId === rootScope.myId) {
|
||||
subtitle = 'Chat with yourself';
|
||||
} else if(appUsersManager.isBot(peerId)) {
|
||||
subtitle = 'Bot';
|
||||
} else {
|
||||
subtitle = appUsersManager.contactsList.has(peerId) ? 'Contact' : 'Non-Contact';
|
||||
}
|
||||
} else {
|
||||
subtitle = appPeersManager.isBroadcast(peerId) ? 'Channel' : 'Group';
|
||||
}
|
||||
|
||||
_i18n(dom.lastMessageSpan, subtitle); */
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -79,19 +79,19 @@ export default class AppNotificationsTab extends SliderSuperTabEventable {
|
||||
};
|
||||
|
||||
NotifySection({
|
||||
name: 'AutoDownloadSettings.TypePrivateChats',
|
||||
name: 'NotificationsPrivateChats',
|
||||
typeText: 'NotificationsForPrivateChats',
|
||||
inputKey: 'inputNotifyUsers'
|
||||
});
|
||||
|
||||
NotifySection({
|
||||
name: 'AutoDownloadSettings.TypeGroupChats',
|
||||
name: 'NotificationsGroups',
|
||||
typeText: 'NotificationsForGroups',
|
||||
inputKey: 'inputNotifyChats'
|
||||
});
|
||||
|
||||
NotifySection({
|
||||
name: 'AutoDownloadSettings.TypeChannels',
|
||||
name: 'NotificationsChannels',
|
||||
typeText: 'NotificationsForChannels',
|
||||
inputKey: 'inputNotifyBroadcasts'
|
||||
});
|
||||
|
@ -1,18 +1,19 @@
|
||||
import { SliderSuperTabEventable } from "../../../sliderTab";
|
||||
import PrivacySection from "../../../privacySection";
|
||||
import { LangPackKey } from "../../../../lib/langPack";
|
||||
|
||||
export default class AppPrivacyAddToGroupsTab extends SliderSuperTabEventable {
|
||||
protected init() {
|
||||
this.container.classList.add('privacy-tab', 'privacy-add-to-groups');
|
||||
this.title.innerHTML = 'Groups and Channels';
|
||||
this.setTitle('PrivacySettings.Groups');
|
||||
|
||||
const caption = 'You can restrict who can add you to groups and channels with granular precision.';
|
||||
const caption: LangPackKey = 'PrivacySettingsController.GroupDescription';
|
||||
new PrivacySection({
|
||||
tab: this,
|
||||
title: 'Who can add me to group chats?',
|
||||
title: 'WhoCanAddMe',
|
||||
inputKey: 'inputPrivacyKeyChatInvite',
|
||||
captions: [caption, caption, caption],
|
||||
exceptionTexts: ['Never Allow', 'Always Allow'],
|
||||
exceptionTexts: ['PrivacySettingsController.NeverAllow', 'PrivacySettingsController.AlwaysAllow'],
|
||||
appendTo: this.scrollable
|
||||
});
|
||||
}
|
||||
|
@ -1,29 +1,30 @@
|
||||
import { SliderSuperTabEventable } from "../../../sliderTab";
|
||||
import PrivacySection from "../../../privacySection";
|
||||
import { LangPackKey } from "../../../../lib/langPack";
|
||||
|
||||
export default class AppPrivacyCallsTab extends SliderSuperTabEventable {
|
||||
protected init() {
|
||||
this.container.classList.add('privacy-tab', 'privacy-calls');
|
||||
this.title.innerHTML = 'Calls';
|
||||
this.setTitle('PrivacySettings.VoiceCalls');
|
||||
|
||||
const caption = 'You can restrict who can call you with granular precision.';
|
||||
const caption: LangPackKey = 'PrivacySettingsController.PhoneCallDescription';
|
||||
new PrivacySection({
|
||||
tab: this,
|
||||
title: 'Who can call me?',
|
||||
title: 'WhoCanCallMe',
|
||||
inputKey: 'inputPrivacyKeyPhoneCall',
|
||||
captions: [caption, caption, caption],
|
||||
exceptionTexts: ['Never Allow', 'Always Allow'],
|
||||
exceptionTexts: ['PrivacySettingsController.NeverAllow', 'PrivacySettingsController.AlwaysAllow'],
|
||||
appendTo: this.scrollable
|
||||
});
|
||||
|
||||
{
|
||||
const caption = 'Disabling peer-to-peer will relay all calls through Telegram servers to avoid revealing your IP address, but will slightly decrease audio quality.';
|
||||
const caption: LangPackKey = 'PrivacySettingsController.P2p.Desc';
|
||||
new PrivacySection({
|
||||
tab: this,
|
||||
title: 'Peer to peer?',
|
||||
title: 'PrivacyP2PHeader',
|
||||
inputKey: 'inputPrivacyKeyPhoneP2P',
|
||||
captions: [caption, caption, caption],
|
||||
exceptionTexts: ['Never Allow', 'Always Allow'],
|
||||
exceptionTexts: ['PrivacySettingsController.NeverAllow', 'PrivacySettingsController.AlwaysAllow'],
|
||||
appendTo: this.scrollable
|
||||
});
|
||||
}
|
||||
|
@ -1,18 +1,19 @@
|
||||
import { SliderSuperTabEventable } from "../../../sliderTab";
|
||||
import PrivacySection from "../../../privacySection";
|
||||
import { LangPackKey } from "../../../../lib/langPack";
|
||||
|
||||
export default class AppPrivacyForwardMessagesTab extends SliderSuperTabEventable {
|
||||
protected init() {
|
||||
this.container.classList.add('privacy-tab', 'privacy-forward-messages');
|
||||
this.title.innerHTML = 'Forward Messages';
|
||||
this.setTitle('PrivacySettings.Forwards');
|
||||
|
||||
const caption = 'You can restrict who can add a link to your account when forwarding your messages.';
|
||||
const caption: LangPackKey = 'PrivacySettingsController.Forwards.CustomHelp';
|
||||
new PrivacySection({
|
||||
tab: this,
|
||||
title: 'Who can add a link to my account when forwarding my messages?',
|
||||
title: 'PrivacyForwardsTitle',
|
||||
inputKey: 'inputPrivacyKeyForwards',
|
||||
captions: [caption, caption, caption],
|
||||
exceptionTexts: ['Never Allow', 'Always Allow'],
|
||||
exceptionTexts: ['PrivacySettingsController.NeverAllow', 'PrivacySettingsController.AlwaysAllow'],
|
||||
appendTo: this.scrollable
|
||||
});
|
||||
}
|
||||
|
@ -1,18 +1,19 @@
|
||||
import { SliderSuperTabEventable } from "../../../sliderTab";
|
||||
import PrivacySection from "../../../privacySection";
|
||||
import { LangPackKey } from "../../../../lib/langPack";
|
||||
|
||||
export default class AppPrivacyLastSeenTab extends SliderSuperTabEventable {
|
||||
protected init() {
|
||||
this.container.classList.add('privacy-tab', 'privacy-last-seen');
|
||||
this.title.innerHTML = 'Last Seen & Online';
|
||||
this.setTitle('PrivacyLastSeen');
|
||||
|
||||
const caption = 'You won\'t see Last Seen and online statuses for people with whom you don\'t share yours.<br>Approximate last seen will be shown instead (recently, within a week, within a month).';
|
||||
const caption: LangPackKey = 'PrivacySettingsController.LastSeenDescription';
|
||||
new PrivacySection({
|
||||
tab: this,
|
||||
title: 'Who can see your Last Seen time?',
|
||||
title: 'LastSeenTitle',
|
||||
inputKey: 'inputPrivacyKeyStatusTimestamp',
|
||||
captions: [caption, caption, caption],
|
||||
exceptionTexts: ['Never Share With', 'Always Share With'],
|
||||
exceptionTexts: ['PrivacySettingsController.NeverShare', 'PrivacySettingsController.AlwaysShare'],
|
||||
appendTo: this.scrollable
|
||||
});
|
||||
}
|
||||
|
@ -1,19 +1,20 @@
|
||||
import { SliderSuperTabEventable } from "../../../sliderTab";
|
||||
import PrivacySection from "../../../privacySection";
|
||||
import { PrivacyType } from "../../../../lib/appManagers/appPrivacyManager";
|
||||
import { LangPackKey } from "../../../../lib/langPack";
|
||||
|
||||
export default class AppPrivacyProfilePhotoTab extends SliderSuperTabEventable {
|
||||
protected init() {
|
||||
this.container.classList.add('privacy-tab', 'privacy-profile-photo');
|
||||
this.title.innerHTML = 'Profile Photo';
|
||||
this.setTitle('PrivacyProfilePhoto');
|
||||
|
||||
const caption = 'You can restrict who can see your profile photo with granular precision.';
|
||||
const caption: LangPackKey = 'PrivacySettingsController.ProfilePhoto.CustomHelp';
|
||||
new PrivacySection({
|
||||
tab: this,
|
||||
title: 'Who can see your profile photo?',
|
||||
title: 'PrivacyProfilePhotoTitle',
|
||||
inputKey: 'inputPrivacyKeyChatInvite',
|
||||
captions: [caption, caption, caption],
|
||||
exceptionTexts: ['Never Share With', 'Always Share With'],
|
||||
exceptionTexts: ['PrivacySettingsController.NeverShare', 'PrivacySettingsController.AlwaysShare'],
|
||||
appendTo: this.scrollable,
|
||||
skipTypes: [PrivacyType.Nobody]
|
||||
});
|
||||
|
@ -19,7 +19,7 @@ import AppBlockedUsersTab from "./blockedUsers";
|
||||
import appUsersManager from "../../../lib/appManagers/appUsersManager";
|
||||
import rootScope from "../../../lib/rootScope";
|
||||
import { convertKeyToInputKey } from "../../../helpers/string";
|
||||
import { LangPackKey, _i18n } from "../../../lib/langPack";
|
||||
import { i18n, LangPackKey, _i18n } from "../../../lib/langPack";
|
||||
|
||||
export default class AppPrivacyAndSecurityTab extends SliderSuperTab {
|
||||
private activeSessionsRow: Row;
|
||||
@ -97,9 +97,9 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTab {
|
||||
blockedCount = count;
|
||||
|
||||
if(count) {
|
||||
_i18n(blockedUsersRow.subtitle, 'Privacy.BlockedUsers', [count]);
|
||||
_i18n(blockedUsersRow.subtitle, 'PrivacySettingsController.UserCount', [count]);
|
||||
} else {
|
||||
_i18n(blockedUsersRow.subtitle, 'Privacy.BlockedUsers.None');
|
||||
_i18n(blockedUsersRow.subtitle, 'BlockedEmpty');
|
||||
}
|
||||
};
|
||||
|
||||
@ -124,7 +124,7 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTab {
|
||||
|
||||
passwordManager.getState().then(state => {
|
||||
passwordState = state;
|
||||
twoFactorRow.subtitle.innerText = state.pFlags.has_password ? 'On' : 'Off';
|
||||
_i18n(twoFactorRow.subtitle, state.pFlags.has_password ? 'PrivacyAndSecurity.Item.On' : 'PrivacyAndSecurity.Item.Off');
|
||||
twoFactorRow.freezed = false;
|
||||
|
||||
//console.log('password state', state);
|
||||
@ -198,11 +198,16 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTab {
|
||||
|
||||
appPrivacyManager.getPrivacy(key).then(rules => {
|
||||
const details = appPrivacyManager.getPrivacyRulesDetails(rules);
|
||||
const type = details.type === PrivacyType.Everybody ? 'Everybody' : (details.type === PrivacyType.Contacts ? 'My Contacts' : 'Nobody');
|
||||
const langKey = details.type === PrivacyType.Everybody ? 'PrivacySettingsController.Everbody' : (details.type === PrivacyType.Contacts ? 'PrivacySettingsController.MyContacts' : 'PrivacySettingsController.Nobody');
|
||||
const disallowLength = details.disallowPeers.users.length + details.disallowPeers.chats.length;
|
||||
const allowLength = details.allowPeers.users.length + details.allowPeers.chats.length;
|
||||
const str = type + (disallowLength || allowLength ? ` (${[-disallowLength, allowLength ? '+' + allowLength : 0].filter(Boolean).join(', ')})` : '');
|
||||
row.subtitle.innerHTML = str;
|
||||
|
||||
row.subtitle.innerHTML = '';
|
||||
const s = i18n(langKey);
|
||||
row.subtitle.append(s);
|
||||
if(disallowLength || allowLength) {
|
||||
row.subtitle.append(` (${[-disallowLength, allowLength ? '+' + allowLength : 0].filter(Boolean).join(', ')})`);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
61
src/lang.ts
61
src/lang.ts
@ -39,11 +39,6 @@ const lang = {
|
||||
one_value: '%1$d device',
|
||||
other_value: '%1$d devices'
|
||||
},
|
||||
"Privacy.BlockedUsers": {
|
||||
one_value: '%1$d user',
|
||||
other_value: '%1$d users',
|
||||
},
|
||||
"Privacy.BlockedUsers.None": 'None',
|
||||
|
||||
// * android
|
||||
FilterAlwaysShow: 'Include Chats',
|
||||
@ -68,6 +63,10 @@ const lang = {
|
||||
one_value: '%1$d group',
|
||||
other_value: '%1$d groups'
|
||||
},
|
||||
Users: {
|
||||
one_value: "%1$d user",
|
||||
other_value: "%1$d users"
|
||||
},
|
||||
UsernameHelpLink: "This link opens a chat with you:\n%1$s",
|
||||
NewGroup: "New Group",
|
||||
Contacts: "Contacts",
|
||||
@ -88,20 +87,44 @@ const lang = {
|
||||
NotificationsForGroups: 'Notifications for groups',
|
||||
NotificationsForPrivateChats: 'Notifications for private chats',
|
||||
NotificationsForChannels: 'Notifications for channels',
|
||||
NotificationsPrivateChats: "Private Chats",
|
||||
NotificationsGroups: "Groups",
|
||||
NotificationsChannels: "Channels",
|
||||
NotificationsOther: 'Other',
|
||||
ContactJoined: 'Contact joined Telegram',
|
||||
Loading: "Loading...",
|
||||
Unblock: "Unblock",
|
||||
BlockedUsers: "Blocked Users",
|
||||
BlockedUsersInfo: 'Blocked users will not be able to contact you and will not see your Last Seen time.',
|
||||
BlockedEmpty: "None",
|
||||
TwoStepVerification: "Two-Step Verification",
|
||||
PrivacyExceptions: "Exceptions",
|
||||
PrivacyLastSeen: "Last Seen & Online",
|
||||
PrivacySettings: "Privacy and Security",
|
||||
PrivacyTitle: "Privacy",
|
||||
PrivacyPhone: "Phone Number",
|
||||
PrivacyPhoneTitle: "Who can see my phone number?",
|
||||
PrivacyPhoneTitle2: "Who can find me by my number?",
|
||||
PrivacyPhoneInfo: "Users who have your number saved in their contacts will also see it on Telegram.",
|
||||
PrivacyPhoneInfo3: "Users who add your number to their contacts will see it on Telegram only if they are your contacts.",
|
||||
PrivacyProfilePhoto: "Profile Photos",
|
||||
PrivacyProfilePhotoTitle: "Who can see my profile photos & videos?",
|
||||
PrivacyP2PHeader: "Peer-to-Peer",
|
||||
PrivacyForwardsTitle: "Who can add a link to my account when forwarding my messages?",
|
||||
LastSeenTitle: "Who can see your Last Seen time?",
|
||||
SessionsTitle: "Active Sessions",
|
||||
CurrentSession: "This device",
|
||||
TerminateAllSessions: "Terminate All Other Sessions",
|
||||
TerminateSessionText: "Are you sure you want to terminate this session?",
|
||||
OtherSessions: "Active sessions",
|
||||
AreYouSureSessionTitle: "Terminate session",
|
||||
AreYouSureSessionsTitle: "Terminate sessions",
|
||||
AreYouSureSessions: "Are you sure you want to terminate all other sessions?",
|
||||
Terminate: "Terminate",
|
||||
WhoCanCallMe: "Who can call me?",
|
||||
WhoCanAddMe: "Who can add me to group chats?",
|
||||
ArchivedChats: "Archived Chats",
|
||||
Cancel: "Cancel",
|
||||
|
||||
// * macos
|
||||
"ChatList.Filter.Header": "Create folders for different groups of chats and quickly switch between them.",
|
||||
@ -132,9 +155,31 @@ const lang = {
|
||||
"Telegram.NotificationSettingsViewController": "Notifications",
|
||||
"Stickers.SuggestStickers": "Suggest Stickers by Emoji",
|
||||
"InstalledStickers.LoopAnimated": "Loop Animated Stickers",
|
||||
"AutoDownloadSettings.TypePrivateChats": "Private Chats",
|
||||
"AutoDownloadSettings.TypeGroupChats": "Groups",
|
||||
"AutoDownloadSettings.TypeChannels": "Channels",
|
||||
"PrivacyAndSecurity.Item.On": "On",
|
||||
"PrivacyAndSecurity.Item.Off": "Off",
|
||||
"PrivacySettings.VoiceCalls": "Calls",
|
||||
"PrivacySettings.Forwards": "Forwarded Messages",
|
||||
"PrivacySettings.Groups": "Groups and Channels",
|
||||
"PrivacySettingsController.AddUsers": "Add Users",
|
||||
"PrivacySettingsController.GroupDescription": "You can restrict who can add you to groups and channels with granular precision.",
|
||||
"PrivacySettingsController.Forwards.CustomHelp": "You can restrict who can add a link to your account when forwarding your messages.",
|
||||
"PrivacySettingsController.P2p.Desc": "Disabling peer-to-peer will relay all calls through Telegram servers to avoid revealing your IP address, but may slightly decrease audio and video quality.",
|
||||
"PrivacySettingsController.PhoneCallDescription": "You can restrict who can call you with granular precision.",
|
||||
"PrivacySettingsController.ProfilePhoto.CustomHelp": "You can restrict who can see your profile photo with granular precision.",
|
||||
"PrivacySettingsController.LastSeenDescription": "You won't see Last Seen and Online statuses for people with whom you don't share yours. Approximate last seen will be shown instead (recently, within a week, within a month).",
|
||||
"PrivacySettingsController.PeerInfo": "You can add users or entire groups as exceptions that will override the settings above.",
|
||||
"PrivacySettingsController.Everbody": "Everybody",
|
||||
"PrivacySettingsController.MyContacts": "My Contacts",
|
||||
"PrivacySettingsController.Nobody": "Nobody",
|
||||
"PrivacySettingsController.NeverShare": "Never Share With",
|
||||
"PrivacySettingsController.AlwaysShare": "Always Share With",
|
||||
"PrivacySettingsController.NeverAllow": "Never Allow",
|
||||
"PrivacySettingsController.AlwaysAllow": "Always Allow",
|
||||
"PrivacySettingsController.UserCount": {
|
||||
one_value: '%d user',
|
||||
other_value: '%d users'
|
||||
},
|
||||
"RecentSessions.Error.FreshReset": "For security reasons, you can't terminate older sessions from a device that you've just connected. Please use an earlier connection or wait for a few hours.",
|
||||
};
|
||||
|
||||
export default lang;
|
||||
|
@ -152,7 +152,7 @@ ul.chatlist {
|
||||
}
|
||||
|
||||
span {
|
||||
display: inline-block;
|
||||
//display: inline-block;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
@ -17,7 +17,6 @@
|
||||
font-size: 1.25rem;
|
||||
font-weight: 500;
|
||||
margin-bottom: .125rem;
|
||||
text-transform: capitalize;
|
||||
|
||||
&:not(:first-child) {
|
||||
padding-left: .75rem;
|
||||
|
381
src/vendor/dateFormat.ts
vendored
Normal file
381
src/vendor/dateFormat.ts
vendored
Normal file
@ -0,0 +1,381 @@
|
||||
/*
|
||||
* Date Format 1.2.3
|
||||
* (c) 2007-2009 Steven Levithan <stevenlevithan.com>
|
||||
* MIT license
|
||||
*
|
||||
* Includes enhancements by Scott Trenda <scott.trenda.net>
|
||||
* and Kris Kowal <cixar.com/~kris.kowal/>
|
||||
*
|
||||
* Accepts a date, a mask, or a date and a mask.
|
||||
* Returns a formatted version of the given date.
|
||||
* The date defaults to the current date/time.
|
||||
* The mask defaults to dateFormat.masks.default.
|
||||
*/
|
||||
|
||||
const dateFormat = (() => {
|
||||
const token = /d{1,4}|D{3,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|W{1,2}|[LlopSZN]|"[^"]*"|'[^']*'/g;
|
||||
const timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g;
|
||||
const timezoneClip = /[^-+\dA-Z]/g;
|
||||
|
||||
// Regexes and supporting functions are cached through closure
|
||||
function f(date?: number | Date, mask?: string, utc?: boolean, gmt?: boolean): string {
|
||||
// You can't provide utc if you skip other args (use the 'UTC:' mask prefix)
|
||||
/* if(
|
||||
arguments.length === 1 &&
|
||||
kindOf(date) === "string" &&
|
||||
!/\d/.test(date)
|
||||
) {
|
||||
mask = date;
|
||||
date = undefined;
|
||||
} */
|
||||
|
||||
date = date || date === 0 ? date : new Date();
|
||||
|
||||
if(!(date instanceof Date)) {
|
||||
date = new Date(date);
|
||||
}
|
||||
|
||||
/* if(isNaN(date)) {
|
||||
throw TypeError("Invalid date");
|
||||
} */
|
||||
|
||||
/* mask = String(
|
||||
dateFormat.masks[mask] || mask || dateFormat.masks["default"]
|
||||
); */
|
||||
|
||||
// Allow setting the utc/gmt argument via the mask
|
||||
const maskSlice = mask.slice(0, 4);
|
||||
if(maskSlice === "UTC:" || maskSlice === "GMT:") {
|
||||
mask = mask.slice(4);
|
||||
utc = true;
|
||||
if(maskSlice === "GMT:") {
|
||||
gmt = true;
|
||||
}
|
||||
}
|
||||
|
||||
const _ = () => (utc ? "getUTC" : "get");
|
||||
const d = (): number => (date as any)[_() + "Date"]();
|
||||
const D = (): number => (date as any)[_() + "Day"]();
|
||||
const m = (): number => (date as any)[_() + "Month"]();
|
||||
const y = (): number => (date as any)[_() + "FullYear"]();
|
||||
const H = (): number => (date as any)[_() + "Hours"]();
|
||||
const M = (): number => (date as any)[_() + "Minutes"]();
|
||||
const s = (): number => (date as any)[_() + "Seconds"]();
|
||||
const L = (): number => (date as any)[_() + "Milliseconds"]();
|
||||
const o = (): number => (utc ? 0 : (date as Date).getTimezoneOffset());
|
||||
const W = (): number => getWeek(date as Date);
|
||||
const N = (): number => getDayOfWeek(date as Date);
|
||||
|
||||
const flags = {
|
||||
d: () => d(),
|
||||
dd: () => pad(d()),
|
||||
ddd: () => dateFormat.i18n.dayNames[D()],
|
||||
DDD: () => getDayName({
|
||||
y: y(),
|
||||
m: m(),
|
||||
d: d(),
|
||||
_: _(),
|
||||
dayName: dateFormat.i18n.dayNames[D()],
|
||||
short: true
|
||||
}),
|
||||
dddd: () => dateFormat.i18n.dayNames[D() + 7],
|
||||
DDDD: () => getDayName({
|
||||
y: y(),
|
||||
m: m(),
|
||||
d: d(),
|
||||
_: _(),
|
||||
dayName: dateFormat.i18n.dayNames[D() + 7]
|
||||
}),
|
||||
m: () => m() + 1,
|
||||
mm: () => pad(m() + 1),
|
||||
mmm: () => dateFormat.i18n.monthNames[m()],
|
||||
mmmm: () => dateFormat.i18n.monthNames[m() + 12],
|
||||
yy: () => String(y()).slice(2),
|
||||
yyyy: () => pad(y(), 4),
|
||||
h: () => H() % 12 || 12,
|
||||
hh: () => pad(H() % 12 || 12),
|
||||
H: () => H(),
|
||||
HH: () => pad(H()),
|
||||
M: () => M(),
|
||||
MM: () => pad(M()),
|
||||
s: () => s(),
|
||||
ss: () => pad(s()),
|
||||
l: () => pad(L(), 3),
|
||||
L: () => pad(Math.floor(L() / 10)),
|
||||
t: () =>
|
||||
H() < 12 ?
|
||||
dateFormat.i18n.timeNames[0] : dateFormat.i18n.timeNames[1],
|
||||
tt: () =>
|
||||
H() < 12 ?
|
||||
dateFormat.i18n.timeNames[2] : dateFormat.i18n.timeNames[3],
|
||||
T: () =>
|
||||
H() < 12 ?
|
||||
dateFormat.i18n.timeNames[4] : dateFormat.i18n.timeNames[5],
|
||||
TT: () =>
|
||||
H() < 12 ?
|
||||
dateFormat.i18n.timeNames[6] : dateFormat.i18n.timeNames[7],
|
||||
Z: () =>
|
||||
gmt ?
|
||||
"GMT" : utc ?
|
||||
"UTC" : (String(date).match(timezone) || [""])
|
||||
.pop()
|
||||
.replace(timezoneClip, "")
|
||||
.replace(/GMT\+0000/g, "UTC"),
|
||||
o: () =>
|
||||
(o() > 0 ? "-" : "+") +
|
||||
pad(Math.floor(Math.abs(o()) / 60) * 100 + (Math.abs(o()) % 60), 4),
|
||||
p: () =>
|
||||
(o() > 0 ? "-" : "+") +
|
||||
pad(Math.floor(Math.abs(o()) / 60), 2) +
|
||||
":" +
|
||||
pad(Math.floor(Math.abs(o()) % 60), 2),
|
||||
S: () => ["th", "st", "nd", "rd"][
|
||||
// @ts-ignore
|
||||
d() % 10 > 3 ? 0 : (((d() % 100) - (d() % 10) != 10) * d()) % 10
|
||||
],
|
||||
W: () => W(),
|
||||
WW: () => pad(W()),
|
||||
N: () => N(),
|
||||
};
|
||||
|
||||
return mask.replace(token, (match) => {
|
||||
if(match in flags) {
|
||||
// @ts-ignore
|
||||
return flags[match]();
|
||||
}
|
||||
return match.slice(1, match.length - 1);
|
||||
});
|
||||
};
|
||||
|
||||
// Internationalization strings
|
||||
f.i18n = {
|
||||
dayNames: [
|
||||
"Sun",
|
||||
"Mon",
|
||||
"Tue",
|
||||
"Wed",
|
||||
"Thu",
|
||||
"Fri",
|
||||
"Sat",
|
||||
"Sunday",
|
||||
"Monday",
|
||||
"Tuesday",
|
||||
"Wednesday",
|
||||
"Thursday",
|
||||
"Friday",
|
||||
"Saturday",
|
||||
],
|
||||
monthNames: [
|
||||
"Jan",
|
||||
"Feb",
|
||||
"Mar",
|
||||
"Apr",
|
||||
"May",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Aug",
|
||||
"Sep",
|
||||
"Oct",
|
||||
"Nov",
|
||||
"Dec",
|
||||
"January",
|
||||
"February",
|
||||
"March",
|
||||
"April",
|
||||
"May",
|
||||
"June",
|
||||
"July",
|
||||
"August",
|
||||
"September",
|
||||
"October",
|
||||
"November",
|
||||
"December",
|
||||
],
|
||||
timeNames: ["a", "p", "am", "pm", "A", "P", "AM", "PM"],
|
||||
};
|
||||
|
||||
f.setLocale = function(code: string) {
|
||||
const date = new Date();
|
||||
|
||||
{
|
||||
const dateTimeFormat = new Intl.DateTimeFormat(code, {month: 'long'});
|
||||
const dateTimeFormatShort = new Intl.DateTimeFormat(code, {month: 'short'});
|
||||
for(let i = 0; i < 12; ++i) {
|
||||
date.setMonth(i);
|
||||
f.i18n.monthNames[i] = dateTimeFormatShort.format(date);
|
||||
f.i18n.monthNames[i + 12] = dateTimeFormat.format(date);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const day = date.getDay();
|
||||
if(day !== 0) {
|
||||
date.setDate(date.getDate() - day);
|
||||
}
|
||||
|
||||
const dateTimeFormat = new Intl.DateTimeFormat(code, {weekday: 'long'});
|
||||
const dateTimeFormatShort = new Intl.DateTimeFormat(code, {weekday: 'short'});
|
||||
for(let i = 0; i < 7; ++i) {
|
||||
date.setDate(date.getDate() + 1);
|
||||
f.i18n.dayNames[i] = dateTimeFormatShort.format(date);
|
||||
f.i18n.dayNames[i + 7] = dateTimeFormat.format(date);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return f;
|
||||
})();
|
||||
|
||||
export default dateFormat;
|
||||
|
||||
(window as any).dateFormat = dateFormat;
|
||||
|
||||
/* dateFormat.masks = {
|
||||
default: "ddd mmm dd yyyy HH:MM:ss",
|
||||
shortDate: "m/d/yy",
|
||||
paddedShortDate: "mm/dd/yyyy",
|
||||
mediumDate: "mmm d, yyyy",
|
||||
longDate: "mmmm d, yyyy",
|
||||
fullDate: "dddd, mmmm d, yyyy",
|
||||
shortTime: "h:MM TT",
|
||||
mediumTime: "h:MM:ss TT",
|
||||
longTime: "h:MM:ss TT Z",
|
||||
isoDate: "yyyy-mm-dd",
|
||||
isoTime: "HH:MM:ss",
|
||||
isoDateTime: "yyyy-mm-dd'T'HH:MM:sso",
|
||||
isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'",
|
||||
expiresHeaderFormat: "ddd, dd mmm yyyy HH:MM:ss Z",
|
||||
}; */
|
||||
|
||||
const pad = (val: number | string, len = 2) => {
|
||||
val = String(val);
|
||||
while(val.length < len) {
|
||||
val = "0" + val;
|
||||
}
|
||||
return val;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get day name
|
||||
* Yesterday, Today, Tomorrow if the date lies within, else fallback to Monday - Sunday
|
||||
* @param {Object}
|
||||
* @return {String}
|
||||
*/
|
||||
const getDayName = ({
|
||||
y,
|
||||
m,
|
||||
d,
|
||||
_,
|
||||
dayName,
|
||||
short = false
|
||||
}: {
|
||||
y: number,
|
||||
m: number,
|
||||
d: number,
|
||||
_: any,
|
||||
dayName: any,
|
||||
short?: boolean
|
||||
}) => {
|
||||
const today = new Date();
|
||||
const yesterday = new Date();
|
||||
yesterday.setDate((yesterday as any)[_ + 'Date']() - 1);
|
||||
const tomorrow = new Date();
|
||||
tomorrow.setDate((tomorrow as any)[_ + 'Date']() + 1);
|
||||
const today_d = (): number => (today as any)[_ + 'Date']();
|
||||
const today_m = (): number => (today as any)[_ + 'Month']();
|
||||
const today_y = (): number => (today as any)[_ + 'FullYear']();
|
||||
const yesterday_d = (): number => (yesterday as any)[_ + 'Date']();
|
||||
const yesterday_m = (): number => (yesterday as any)[_ + 'Month']();
|
||||
const yesterday_y = (): number => (yesterday as any)[_ + 'FullYear']();
|
||||
const tomorrow_d = (): number => (tomorrow as any)[_ + 'Date']();
|
||||
const tomorrow_m = (): number => (tomorrow as any)[_ + 'Month']();
|
||||
const tomorrow_y = (): number => (tomorrow as any)[_ + 'FullYear']();
|
||||
|
||||
if(today_y() === y && today_m() === m && today_d() === d) {
|
||||
return short ? 'Tdy' : 'Today';
|
||||
} else if(yesterday_y() === y && yesterday_m() === m && yesterday_d() === d) {
|
||||
return short ? 'Ysd' : 'Yesterday';
|
||||
} else if(tomorrow_y() === y && tomorrow_m() === m && tomorrow_d() === d) {
|
||||
return short ? 'Tmw' : 'Tomorrow';
|
||||
}
|
||||
return dayName;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the ISO 8601 week number
|
||||
* Based on comments from
|
||||
* http://techblog.procurios.nl/k/n618/news/view/33796/14863/Calculate-ISO-8601-week-and-year-in-javascript.html
|
||||
*
|
||||
* @param {Object} `date`
|
||||
* @return {Number}
|
||||
*/
|
||||
const getWeek = (date: Date) => {
|
||||
// Remove time components of date
|
||||
const targetThursday = new Date(
|
||||
date.getFullYear(),
|
||||
date.getMonth(),
|
||||
date.getDate()
|
||||
);
|
||||
|
||||
// Change date to Thursday same week
|
||||
targetThursday.setDate(
|
||||
targetThursday.getDate() - ((targetThursday.getDay() + 6) % 7) + 3
|
||||
);
|
||||
|
||||
// Take January 4th as it is always in week 1 (see ISO 8601)
|
||||
const firstThursday = new Date(targetThursday.getFullYear(), 0, 4);
|
||||
|
||||
// Change date to Thursday same week
|
||||
firstThursday.setDate(
|
||||
firstThursday.getDate() - ((firstThursday.getDay() + 6) % 7) + 3
|
||||
);
|
||||
|
||||
// Check if daylight-saving-time-switch occurred and correct for it
|
||||
const ds =
|
||||
targetThursday.getTimezoneOffset() - firstThursday.getTimezoneOffset();
|
||||
targetThursday.setHours(targetThursday.getHours() - ds);
|
||||
|
||||
// Number of weeks between target Thursday and first Thursday
|
||||
const weekDiff = (targetThursday.getTime() - firstThursday.getTime()) / (86400000 * 7);
|
||||
return 1 + Math.floor(weekDiff);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get ISO-8601 numeric representation of the day of the week
|
||||
* 1 (for Monday) through 7 (for Sunday)
|
||||
*
|
||||
* @param {Object} `date`
|
||||
* @return {Number}
|
||||
*/
|
||||
const getDayOfWeek = (date: Date) => {
|
||||
let dow = date.getDay();
|
||||
if(dow === 0) {
|
||||
dow = 7;
|
||||
}
|
||||
return dow;
|
||||
};
|
||||
|
||||
/**
|
||||
* kind-of shortcut
|
||||
* @param {*} val
|
||||
* @return {String}
|
||||
*/
|
||||
/* const kindOf = (val: any) => {
|
||||
if(val === null) {
|
||||
return "null";
|
||||
}
|
||||
|
||||
if(val === undefined) {
|
||||
return "undefined";
|
||||
}
|
||||
|
||||
if(typeof val !== "object") {
|
||||
return typeof val;
|
||||
}
|
||||
|
||||
if(Array.isArray(val)) {
|
||||
return "array";
|
||||
}
|
||||
|
||||
return {}.toString.call(val).slice(8, -1).toLowerCase();
|
||||
}; */
|
Loading…
Reference in New Issue
Block a user