diff --git a/src/components/appMediaPlaybackController.ts b/src/components/appMediaPlaybackController.ts index 55b1b4a4..c625ab3f 100644 --- a/src/components/appMediaPlaybackController.ts +++ b/src/components/appMediaPlaybackController.ts @@ -199,7 +199,7 @@ class AppMediaPlaybackController { const media = this.playingMedia; this.prevMid = this.nextMid = 0; - return appMessagesManager.getSearchNew({ + return appMessagesManager.getSearch({ peerId, query: '', inputFilter: { diff --git a/src/components/appMediaViewer.ts b/src/components/appMediaViewer.ts index 0760ad24..82759b8c 100644 --- a/src/components/appMediaViewer.ts +++ b/src/components/appMediaViewer.ts @@ -1244,7 +1244,7 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet if(anchor) maxId = anchor.mid; if(!older) maxId = appMessagesManager.incrementMessageId(maxId, 1); - const promise = appMessagesManager.getSearchNew({ + const promise = appMessagesManager.getSearch({ peerId: this.searchContext.peerId, query: this.searchContext.query, inputFilter: { diff --git a/src/components/appSearch.ts b/src/components/appSearch.ts index 5610eaac..cbc7b2a8 100644 --- a/src/components/appSearch.ts +++ b/src/components/appSearch.ts @@ -150,7 +150,7 @@ export default class AppSearch { const maxId = this.minMsgId || 0; - return this.searchPromise = appMessagesManager.getSearchNew({ + return this.searchPromise = appMessagesManager.getSearch({ peerId: this.peerId, query, inputFilter: {_: 'inputMessagesFilterEmpty'}, diff --git a/src/components/appSearchSuper..ts b/src/components/appSearchSuper..ts index 6cf0950d..a535ef16 100644 --- a/src/components/appSearchSuper..ts +++ b/src/components/appSearchSuper..ts @@ -19,7 +19,7 @@ import { horizontalMenu } from "./horizontalMenu"; import LazyLoadQueue from "./lazyLoadQueue"; import { renderImageFromUrl, putPreloader, formatPhoneNumber } from "./misc"; import { ripple } from "./ripple"; -import Scrollable from "./scrollable"; +import Scrollable, { ScrollableX } from "./scrollable"; import { wrapDocument } from "./wrappers"; const testScroll = false; @@ -33,7 +33,9 @@ export type SearchSuperContext = { folderId?: number, threadId?: number, date?: number, - nextRate?: number + nextRate?: number, + minDate?: number, + maxDate?: number }; export default class AppSearchSuper { @@ -43,6 +45,7 @@ export default class AppSearchSuper { public tabSelected: HTMLElement; public container: HTMLElement; + public nav: HTMLElement; private tabsContainer: HTMLElement; private tabsMenu: HTMLUListElement; private prevTabId = -1; @@ -74,15 +77,24 @@ export default class AppSearchSuper { } }> = {}; + private searchGroupMedia: SearchGroup; + constructor(public types: {inputFilter: SearchSuperType, name: string}[], public scrollable: Scrollable, public searchGroups?: {[group in SearchGroupType]: SearchGroup}, public asChatList = false) { this.container = document.createElement('div'); this.container.classList.add('search-super'); - const nav = document.createElement('nav'); + const navScrollableContainer = document.createElement('div'); + navScrollableContainer.classList.add('search-super-tabs-scrollable', 'menu-horizontal-scrollable'); + + const navScrollable = new ScrollableX(navScrollableContainer); + + const nav = this.nav = document.createElement('nav'); nav.classList.add('search-super-tabs', 'menu-horizontal'); this.tabsMenu = document.createElement('ul'); nav.append(this.tabsMenu); + navScrollable.container.append(nav); + for(const type of types) { const li = document.createElement('li'); const span = document.createElement('span'); @@ -115,10 +127,12 @@ export default class AppSearchSuper { this.tabs[type.inputFilter] = content; } - this.container.append(nav, this.tabsContainer); + this.container.append(navScrollableContainer, this.tabsContainer); // * construct end + this.searchGroupMedia = new SearchGroup('', 'messages', true); + this.scrollable.onScrolledBottom = () => { if(this.tabSelected && this.tabSelected.childElementCount/* && false */) { //this.log('onScrolledBottom will load media'); @@ -296,10 +310,19 @@ export default class AppSearchSuper { public async performSearchResult(messages: any[], type: SearchSuperType, append = true) { const elemsToAppend: {element: HTMLElement, message: any}[] = []; + const sharedMediaDiv: HTMLElement = this.tabs[type]; const promises: Promise[] = []; - const sharedMediaDiv: HTMLElement = type === 'inputMessagesFilterEmpty' ? this.searchGroups.messages.list : this.tabs[type]; - const middleware = this.getMiddleware(); + + let searchGroup: SearchGroup; + if(type === 'inputMessagesFilterPhotoVideo' && !!this.searchContext.query.trim()) { + type = 'inputMessagesFilterEmpty'; + searchGroup = this.searchGroupMedia; + sharedMediaDiv.append(searchGroup.container); + } else if(type === 'inputMessagesFilterEmpty') { + searchGroup = this.searchGroups.messages; + } + // https://core.telegram.org/type/MessagesFilter switch(type) { @@ -307,14 +330,14 @@ export default class AppSearchSuper { for(const message of messages) { const {dialog, dom} = appDialogsManager.addDialogNew({ dialog: message.peerId, - container: sharedMediaDiv as HTMLUListElement/* searchGroup.list */, + container: searchGroup.list, drawStatus: false, avatarSize: 54 }); appDialogsManager.setLastMessage(dialog, message, dom, this.searchContext.query); } - this.searchGroups.messages.setActive(); + searchGroup.setActive(); break; } @@ -689,7 +712,24 @@ export default class AppSearchSuper { .then((contacts) => { if(contacts) { setResults(contacts.my_results, this.searchGroups.contacts, true); - setResults(contacts.results, this.searchGroups.globalContacts); + setResults(contacts.results/* .concat(contacts.results, contacts.results, contacts.results) */, this.searchGroups.globalContacts); + + if(this.searchGroups.globalContacts.nameEl.lastElementChild) { + this.searchGroups.globalContacts.nameEl.lastElementChild.remove(); + } + + this.searchGroups.globalContacts.container.classList.add('is-short'); + + if(this.searchGroups.globalContacts.list.childElementCount > 3) { + const showMore = document.createElement('div'); + showMore.classList.add('search-group__show-more'); + showMore.innerText = 'Show more'; + this.searchGroups.globalContacts.nameEl.append(showMore); + showMore.addEventListener('click', () => { + const isShort = this.searchGroups.globalContacts.container.classList.toggle('is-short'); + showMore.innerText = isShort ? 'Show more' : 'Show less'; + }); + } } }), @@ -835,7 +875,7 @@ export default class AppSearchSuper { //this.log(logStr + 'search house of glass pre', type, maxId); //let loadCount = history.length ? 50 : 15; - return this.loadPromises[type] = appMessagesManager.getSearchNew({ + return this.loadPromises[type] = appMessagesManager.getSearch({ peerId, query: this.searchContext.query, inputFilter: {_: type}, @@ -843,7 +883,9 @@ export default class AppSearchSuper { limit: loadCount, nextRate: this.nextRates[type] ?? (this.nextRates[type] = 0), threadId: this.searchContext.threadId, - folderId: this.searchContext.folderId + folderId: this.searchContext.folderId, + minDate: this.searchContext.minDate, + maxDate: this.searchContext.maxDate }).then(value => { history.push(...value.history.map(m => ({mid: m.mid, peerId: m.peerId}))); @@ -870,13 +912,15 @@ export default class AppSearchSuper { this.usedFromHistory[type] = history.length; if(!this.loaded[type]) { - this.loadPromises[type].then(() => { + (this.loadPromises[type] || Promise.resolve()).then(() => { setTimeout(() => { + if(!middleware()) return; //this.log('will preload more'); if(this.type === type) { const promise = this.load(true, true); if(promise) { promise.then(() => { + if(!middleware()) return; //this.log('preloaded more'); setTimeout(() => { this.scrollable.checkForTriggers(); @@ -988,6 +1032,7 @@ export default class AppSearchSuper { }); this.monthContainers = {}; + this.searchGroupMedia.clear(); if(testScroll) { for(let i = 0; i < 1500; ++i) { @@ -1016,19 +1061,23 @@ export default class AppSearchSuper { return context; } - public setQuery({peerId, query, threadId, historyStorage, folderId}: { + public setQuery({peerId, query, threadId, historyStorage, folderId, minDate, maxDate}: { peerId: number, query?: string, threadId?: number, historyStorage?: AppSearchSuper['historyStorage'], - folderId?: number + folderId?: number, + minDate?: number, + maxDate?: number }) { this.searchContext = { peerId: peerId || 0, query: query || '', inputFilter: this.type, threadId, - folderId + folderId, + minDate, + maxDate }; this.historyStorage = historyStorage ?? {}; diff --git a/src/components/audio.ts b/src/components/audio.ts index 01495632..efa00655 100644 --- a/src/components/audio.ts +++ b/src/components/audio.ts @@ -290,7 +290,7 @@ function wrapAudio(audioEl: AudioElement) { const html = `
${title}${titleAdditionHTML}
-
${subtitle}
+
${subtitle || '
'}
`; audioEl.insertAdjacentHTML('beforeend', html); @@ -356,7 +356,8 @@ export default class AudioElement extends HTMLElement { this.classList.add('audio'); const doc = this.message.media.document || this.message.media.webpage.document; - const isVoice = !this.voiceAsMusic && doc.type == 'voice'; + const isRealVoice = doc.type == 'voice'; + const isVoice = !this.voiceAsMusic && isRealVoice; const uploading = this.message.pFlags.is_outgoing; const durationStr = String(doc.duration | 0).toHHMMSS(); @@ -429,7 +430,7 @@ export default class AudioElement extends HTMLElement { if(!uploading) { let preloader: ProgressivePreloader = this.preloader; - if(isVoice) { + if(isRealVoice) { let download: Download; const onClick = (e: Event) => { diff --git a/src/components/avatar.ts b/src/components/avatar.ts index 56b744cf..e8e3d3b8 100644 --- a/src/components/avatar.ts +++ b/src/components/avatar.ts @@ -52,7 +52,7 @@ export default class AvatarElement extends HTMLElement { if(peerId < 0) { const maxId = Number.MAX_SAFE_INTEGER; const inputFilter = 'inputMessagesFilterChatPhotos'; - let message: any = await appMessagesManager.getSearchNew({ + let message: any = await appMessagesManager.getSearch({ peerId, inputFilter: {_: inputFilter}, maxId, diff --git a/src/components/chat/bubbles.ts b/src/components/chat/bubbles.ts index bcabdfbd..22f533f3 100644 --- a/src/components/chat/bubbles.ts +++ b/src/components/chat/bubbles.ts @@ -2350,7 +2350,7 @@ export default class ChatBubbles { if(this.chat.type === 'chat' || this.chat.type === 'discussion') { return this.appMessagesManager.getHistory(this.peerId, maxId, loadCount, backLimit, this.chat.threadId); } else if(this.chat.type === 'pinned') { - const promise = this.appMessagesManager.getSearchNew({ + const promise = this.appMessagesManager.getSearch({ peerId: this.peerId, inputFilter: {_: 'inputMessagesFilterPinned'}, maxId, diff --git a/src/components/chat/pinnedMessage.ts b/src/components/chat/pinnedMessage.ts index 938dec57..e860b71b 100644 --- a/src/components/chat/pinnedMessage.ts +++ b/src/components/chat/pinnedMessage.ts @@ -410,7 +410,7 @@ export default class ChatPinnedMessage { try { let gotRest = false; const promises = [ - this.appMessagesManager.getSearchNew({ + this.appMessagesManager.getSearch({ peerId: this.topbar.peerId, inputFilter: {_: 'inputMessagesFilterPinned'}, maxId: mid, diff --git a/src/components/inputSearch.ts b/src/components/inputSearch.ts index 364c0aae..26ab2d51 100644 --- a/src/components/inputSearch.ts +++ b/src/components/inputSearch.ts @@ -10,6 +10,7 @@ export default class InputSearch { public prevValue = ''; public timeout = 0; public onChange: (value: string) => void; + public onClear: () => void; constructor(placeholder: string, onChange?: (value: string) => void) { this.inputField = new InputField({ @@ -57,6 +58,7 @@ export default class InputSearch { onClearClick = () => { this.value = ''; this.onChange && this.onChange(''); + this.onClear && this.onClear(); }; get value() { diff --git a/src/components/sidebarLeft/index.ts b/src/components/sidebarLeft/index.ts index e5118df9..30c0a11b 100644 --- a/src/components/sidebarLeft/index.ts +++ b/src/components/sidebarLeft/index.ts @@ -1,7 +1,5 @@ //import { logger } from "../polyfill"; import { formatNumber } from "../../helpers/number"; -import appChatsManager from "../../lib/appManagers/appChatsManager"; -import appDialogsManager from "../../lib/appManagers/appDialogsManager"; import appImManager from "../../lib/appManagers/appImManager"; import appPeersManager from "../../lib/appManagers/appPeersManager"; import appStateManager from "../../lib/appManagers/appStateManager"; @@ -29,6 +27,7 @@ import AppSettingsTab from "./tabs/settings"; import appMessagesManager from "../../lib/appManagers/appMessagesManager"; import apiManagerProxy from "../../lib/mtproto/mtprotoworker"; import AppSearchSuper from "../appSearchSuper."; +import { DateData, fillTipDates } from "../../helpers/date"; const newChannelTab = new AppNewChannelTab(); const addMembersTab = new AppAddMembersTab(); @@ -213,21 +212,157 @@ export class AppSidebarLeft extends SidebarSlider { scrollable.container.append(searchSuper.container); - searchSuper.setQuery({ - peerId: 0, - folderId: 0 + const resetSearch = () => { + searchSuper.setQuery({ + peerId: 0, + folderId: 0 + }); + searchSuper.selectTab(0); + searchSuper.load(true); + }; + + resetSearch(); + + let pickedElements: HTMLElement[] = []; + let selectedPeerId = 0; + let selectedMinDate = 0; + let selectedMaxDate = 0; + const updatePicked = () => { + (this.inputSearch.input as HTMLInputElement).placeholder = pickedElements.length ? 'Search' : 'Telegram Search'; + this.inputSearch.container.classList.toggle('is-picked-twice', pickedElements.length === 2); + this.inputSearch.container.classList.toggle('is-picked', !!pickedElements.length); + + if(pickedElements.length) { + this.inputSearch.input.style.setProperty('--paddingLeft', (pickedElements[pickedElements.length - 1].getBoundingClientRect().right - this.inputSearch.input.getBoundingClientRect().left) + 'px'); + } else { + this.inputSearch.input.style.removeProperty('--paddingLeft'); + } + }; + + const helper = document.createElement('div'); + helper.classList.add('search-helper'); + helper.addEventListener('click', (e) => { + const target = findUpClassName(e.target, 'selector-user'); + if(!target) { + return; + } + + const key = target.dataset.key; + if(key.indexOf('date_') === 0) { + const [_, minDate, maxDate] = key.split('_'); + selectedMinDate = +minDate; + selectedMaxDate = +maxDate; + } else { + selectedPeerId = +key; + } + + target.addEventListener('click', () => { + unselectEntity(target); + }); + + this.inputSearch.container.append(target); + this.inputSearch.onChange(this.inputSearch.value = ''); + pickedElements.push(target); + updatePicked(); }); - searchSuper.selectTab(0); - searchSuper.load(true); + + searchSuper.nav.parentElement.append(helper); + + const renderEntity = (peerId: any, title?: string) => { + const div = document.createElement('div'); + div.classList.add('selector-user'/* , 'scale-in' */); + + const avatarEl = document.createElement('avatar-element'); + avatarEl.classList.add('selector-user-avatar', 'tgico'); + avatarEl.setAttribute('dialog', '1'); + avatarEl.classList.add('avatar-30'); + + div.dataset.key = '' + peerId; + if(typeof(peerId) === 'number') { + if(title === undefined) { + title = peerId == rootScope.myId ? 'Saved' : appPeersManager.getPeerTitle(peerId, false, true); + } + + avatarEl.setAttribute('peer', '' + peerId); + } else { + avatarEl.classList.add('tgico-calendarfilter'); + } + + if(title) { + div.innerHTML = title; + } + + div.insertAdjacentElement('afterbegin', avatarEl); + + return div; + }; + + const unselectEntity = (target: HTMLElement) => { + const key = target.dataset.key; + if(key.indexOf('date_') === 0) { + selectedMinDate = selectedMaxDate = 0; + } else { + selectedPeerId = 0; + } + + target.remove(); + pickedElements.findAndSplice(t => t === target); + + setTimeout(() => { + updatePicked(); + this.inputSearch.onChange(this.inputSearch.value); + }, 0); + }; + + this.inputSearch.onClear = () => { + pickedElements.forEach(el => { + unselectEntity(el); + }); + }; this.inputSearch.onChange = (value) => { searchSuper.cleanupHTML(); searchSuper.setQuery({ - peerId: 0, - folderId: 0, - query: value + peerId: selectedPeerId, + folderId: selectedPeerId ? undefined : 0, + query: value, + minDate: selectedMinDate, + maxDate: selectedMaxDate }); searchSuper.load(true); + + helper.innerHTML = ''; + searchSuper.nav.classList.remove('hide'); + if(!value) { + } + + if(!selectedPeerId && value.trim()) { + const middleware = searchSuper.getMiddleware(); + Promise.all([ + appMessagesManager.getConversationsAll(value).then(dialogs => dialogs.map(d => d.peerId)), + appUsersManager.getContacts(value, true) + ]).then(results => { + if(!middleware()) return; + const peerIds = new Set(results[0].concat(results[1])); + + peerIds.forEach(peerId => { + helper.append(renderEntity(peerId)); + }); + + searchSuper.nav.classList.toggle('hide', !!helper.innerHTML); + //console.log('got peerIds by value:', value, [...peerIds]); + }); + } + + if(!selectedMinDate && value.trim()) { + const dates: DateData[] = []; + fillTipDates(value, dates); + dates.forEach(dateData => { + helper.append(renderEntity('date_' + dateData.minDate + '_' + dateData.maxDate, dateData.title)); + }); + + searchSuper.nav.classList.toggle('hide', !!helper.innerHTML); + } }; searchSuper.tabs.inputMessagesFilterEmpty.addEventListener('click', (e) => { @@ -272,6 +407,7 @@ export class AppSidebarLeft extends SidebarSlider { if(id === 0) { this.inputSearch.onClearClick(); + resetSearch(); hideNewBtnMenuTimeout = window.setTimeout(() => { hideNewBtnMenuTimeout = 0; this.newBtnMenu.classList.remove('is-hidden'); diff --git a/src/helpers/date.ts b/src/helpers/date.ts index ae26750b..44ab3d73 100644 --- a/src/helpers/date.ts +++ b/src/helpers/date.ts @@ -1,3 +1,5 @@ +import { MOUNT_CLASS_TO } from "../lib/mtproto/mtproto_config"; + export const months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; export const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; @@ -49,4 +51,289 @@ export const getFullDate = (date: Date, options: Partial<{ export function tsNow(seconds?: true) { const t = Date.now(); return seconds ? Math.floor(t / 1000) : t; -} \ No newline at end of file +} + +// https://github.com/DrKLO/Telegram/blob/d52b2c921abd3c1e8d6368858313ad0cb0468c07/TMessagesProj/src/main/java/org/telegram/ui/Adapters/FiltersView.java +const minYear = 2013; +const yearPattern = new RegExp("20[0-9]{1,2}"); +const monthYearOrDayPattern = new RegExp("(\\w{3,}) ([0-9]{0,4})", 'i'); +const yearOrDayAndMonthPattern = new RegExp("([0-9]{0,4}) (\\w{2,})", 'i'); +const shortDate = new RegExp("^([0-9]{1,4})(\\.| |/|\\-)([0-9]{1,4})$", 'i'); +const longDate = new RegExp("^([0-9]{1,2})(\\.| |/|\\-)([0-9]{1,2})(\\.| |/|\\-)([0-9]{1,4})$", 'i'); +const numberOfDaysEachMonth = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; +export type DateData = { + title: string, + minDate: number, + maxDate: number, +}; +export function fillTipDates(query: string, dates: DateData[]) { + const q = query.trim(); + + if(q.length < 3) { + return; + } + + let matches: any[]; + if((matches = shortDate.exec(q)) !== null) { + const g1 = matches[1]; + const g2 = matches[3]; + const k = parseInt(g1); + const k1 = parseInt(g2); + if(k > 0 && k <= 31) { + if(k1 >= minYear && k <= 12) { + const selectedYear = k1; + const month = k - 1; + createForMonthYear(dates, month, selectedYear); + return; + } else if (k1 <= 12) { + const day = k - 1; + const month = k1 - 1; + createForDayMonth(dates, day, month); + } + } else if (k >= minYear && k1 <= 12) { + const selectedYear = k; + const month = k1 - 1; + createForMonthYear(dates, month, selectedYear); + } + + return; + } + + if((matches = longDate.exec(q)) !== null) { + const g1 = matches[1]; + const g2 = matches[3]; + const g3 = matches[5]; + if(!matches[2] == matches[4]) { + return; + } + + const day = parseInt(g1); + const month = parseInt(g2) - 1; + let year = parseInt(g3); + if(year >= 10 && year <= 99) { + year += 2000; + } + + const currentYear = new Date().getFullYear(); + if(validDateForMonth(day - 1, month) && year >= minYear && year <= currentYear) { + const date = new Date(); + date.setFullYear(year, month, day); + date.setHours(0, 0, 0); + + const minDate = date.getTime(); + date.setFullYear(year, month, day + 1); + date.setHours(0, 0, 0); + + const maxDate = date.getTime() - 1; + dates.push({ + title: formatterYearMax(minDate), + minDate, + maxDate + }); + return; + } + + return; + } + + if((matches = yearPattern.exec(q)) !== null) { + let selectedYear = +q; + const currentYear = new Date().getFullYear(); + if(selectedYear < minYear) { + selectedYear = minYear; + for(let i = currentYear; i >= selectedYear; i--) { + const date = new Date(); + date.setFullYear(i, 0, 1); + date.setHours(0, 0, 0); + + const minDate = date.getTime(); + date.setFullYear(i + 1, 0, 1); + date.setHours(0, 0, 0); + + const maxDate = date.getTime() - 1; + dates.push({ + title: '' + i, + minDate, + maxDate + }); + } + } else if(selectedYear <= currentYear) { + const date = new Date(); + date.setFullYear(selectedYear, 0, 1); + date.setHours(0, 0, 0); + + const minDate = date.getTime(); + date.setFullYear(selectedYear + 1, 0, 1); + date.setHours(0, 0, 0); + + const maxDate = date.getTime() - 1; + dates.push({ + title: '' + selectedYear, + minDate, + maxDate + }); + } + + return; + } + + if((matches = monthYearOrDayPattern.exec(q)) !== null) { + const g1 = matches[1]; + const g2 = matches[2]; + const month = getMonth(g1); + if(month >= 0) { + const k = +g2; + if(k > 0 && k <= 31) { + const day = k - 1; + createForDayMonth(dates, day, month); + return; + } else if(k >= minYear) { + const selectedYear = k; + createForMonthYear(dates, month, selectedYear); + return; + } + } + } + + if((matches = yearOrDayAndMonthPattern.exec(q)) !== null) { + const g1 = matches[1]; + const g2 = matches[2]; + const month = getMonth(g2); + if(month >= 0) { + const k = +g1; + if(k > 0 && k <= 31) { + const day = k - 1; + createForDayMonth(dates, day, month); + return; + } else if (k >= minYear) { + const selectedYear = k; + createForMonthYear(dates, month, selectedYear); + } + } + } +} + +function createForMonthYear(dates: DateData[], month: number, selectedYear: number) { + const currentYear = new Date().getFullYear(); + const today = Date.now(); + if(selectedYear >= minYear && selectedYear <= currentYear) { + const date = new Date(); + date.setFullYear(selectedYear, month, 1); + date.setHours(0, 0, 0); + const minDate = date.getTime(); + if(minDate > today) { + return; + } + date.setMonth(date.getMonth() + 1); + const maxDate = date.getTime() - 1; + + dates.push({ + title: formatterMonthYear(minDate), + minDate, + maxDate + }); + } +} + +function createForDayMonth(dates: DateData[], day: number, month: number) { + if(validDateForMonth(day, month)) { + const currentYear = new Date().getFullYear(); + const today = Date.now(); + + for(let i = currentYear; i >= minYear; i--) { + if(month == 1 && day == 28 && !isLeapYear(i)) { + continue; + } + + const date = new Date(); + date.setFullYear(i, month, day + 1); + date.setHours(0, 0, 0); + + const minDate = date.getTime(); + if(minDate > today) { + continue; + } + + date.setFullYear(i, month, day + 2); + date.setHours(0, 0, 0); + const maxDate = date.getTime() - 1; + if(i == currentYear) { + dates.push({ + title: formatterDayMonth(minDate), + minDate, + maxDate + }); + } else { + dates.push({ + title: formatterYearMax(minDate), + minDate, + maxDate + }); + } + } + } +} + +function formatterMonthYear(timestamp: number) { + const date = new Date(timestamp); + return months[date.getMonth()].slice(0, 3) + ' ' + date.getFullYear(); +} + +function formatterDayMonth(timestamp: number) { + const date = new Date(timestamp); + return months[date.getMonth()].slice(0, 3) + ' ' + date.getDate(); +} + +function formatterYearMax(timestamp: number) { + const date = new Date(timestamp); + return ('0' + date.getDate()).slice(-2) + '.' + ('0' + (date.getMonth() + 1)).slice(-2) + '.' + date.getFullYear(); +} + +function validDateForMonth(day: number, month: number) { + if(month >= 0 && month < 12) { + if(day >= 0 && day < numberOfDaysEachMonth[month]) { + return true; + } + } + return false; +} + +function isLeapYear(year: number) { + return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0); +} + +function getMonth(q: string) { + /* String[] months = new String[]{ + LocaleController.getString("January", R.string.January).toLowerCase(), + LocaleController.getString("February", R.string.February).toLowerCase(), + LocaleController.getString("March", R.string.March).toLowerCase(), + LocaleController.getString("April", R.string.April).toLowerCase(), + LocaleController.getString("May", R.string.May).toLowerCase(), + LocaleController.getString("June", R.string.June).toLowerCase(), + LocaleController.getString("July", R.string.July).toLowerCase(), + LocaleController.getString("August", R.string.August).toLowerCase(), + LocaleController.getString("September", R.string.September).toLowerCase(), + LocaleController.getString("October", R.string.October).toLowerCase(), + LocaleController.getString("November", R.string.November).toLowerCase(), + LocaleController.getString("December", R.string.December).toLowerCase() + }; */ + + /* String[] monthsEng = new String[12]; + Calendar c = Calendar.getInstance(); + for (int i = 1; i <= 12; i++) { + c.set(0, 0, 0, 0, 0, 0); + c.set(Calendar.MONTH, i); + monthsEng[i - 1] = c.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.ENGLISH).toLowerCase(); + } */ + + q = q.toLowerCase(); + for(let i = 0; i < 12; i++) { + const month = months[i].toLowerCase(); + if(month.indexOf(q) === 0) { + return i; + } + } + return -1; +} + +MOUNT_CLASS_TO && (MOUNT_CLASS_TO.fillTipDates = fillTipDates); \ No newline at end of file diff --git a/src/index.hbs b/src/index.hbs index c4dad960..0921f39f 100644 --- a/src/index.hbs +++ b/src/index.hbs @@ -143,7 +143,7 @@