Fix highlighting when selecting
Fix webpage in input for messageEntityTextUrl Fix webpage clearing Fix length in input field due to emoji length Fix pointer-events for sticky date
This commit is contained in:
parent
3cc7d874bf
commit
e3ce8c1906
@ -35,6 +35,9 @@ export default class ChatContextMenu {
|
||||
bubble = bubbleContainer ? bubbleContainer.parentElement : findUpClassName(e.target, 'bubble');
|
||||
} catch(e) {}
|
||||
|
||||
// ! context menu click by date bubble (there is no pointer-events)
|
||||
if(!bubble) return;
|
||||
|
||||
if(e instanceof MouseEvent) e.preventDefault();
|
||||
if(this.element.classList.contains('active')) {
|
||||
return false;
|
||||
|
@ -22,6 +22,7 @@ import Scrollable from "../scrollable";
|
||||
import { toast } from "../toast";
|
||||
import { wrapReply } from "../wrappers";
|
||||
import InputField from '../inputField';
|
||||
import { MessageEntity } from '../../layer';
|
||||
|
||||
const RECORD_MIN_TIME = 500;
|
||||
const POSTING_MEDIA_NOT_ALLOWED = 'Posting media content isn\'t allowed in this group.';
|
||||
@ -195,35 +196,56 @@ export class ChatInput {
|
||||
const value = this.messageInput.innerText;
|
||||
|
||||
const entities = RichTextProcessor.parseEntities(value);
|
||||
//console.log('messageInput entities', entities);
|
||||
console.log('messageInput entities', entities);
|
||||
|
||||
const entityUrl = entities.find(e => e._ == 'messageEntityUrl');
|
||||
if(entityUrl) { // need to get webpage
|
||||
const url = value.slice(entityUrl.offset, entityUrl.offset + entityUrl.length);
|
||||
const urlEntities = entities.filter(e => e._ == 'messageEntityUrl');
|
||||
if(urlEntities.length) {
|
||||
const richEntities: MessageEntity[] = [];
|
||||
const richValue = RichTextProcessor.parseMarkdown(getRichValue(this.messageInput), richEntities);
|
||||
console.log('messageInput url', entities, richEntities);
|
||||
for(const entity of urlEntities) {
|
||||
const url = value.slice(entity.offset, entity.offset + entity.length);
|
||||
|
||||
//console.log('messageInput url:', url);
|
||||
if(!(url.includes('http://') || url.includes('https://')) && !richEntities.find(e => e._ == 'messageEntityTextUrl')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(this.lastUrl != url) {
|
||||
this.lastUrl = url;
|
||||
this.willSendWebPage = null;
|
||||
apiManager.invokeApi('messages.getWebPage', {
|
||||
url: url,
|
||||
hash: 0
|
||||
}).then((webpage) => {
|
||||
webpage = appWebPagesManager.saveWebPage(webpage);
|
||||
if(webpage._ == 'webPage') {
|
||||
if(this.lastUrl != url) return;
|
||||
//console.log('got webpage: ', webpage);
|
||||
//console.log('messageInput url:', url);
|
||||
|
||||
if(this.lastUrl != url) {
|
||||
this.lastUrl = url;
|
||||
this.willSendWebPage = null;
|
||||
apiManager.invokeApi('messages.getWebPage', {
|
||||
url: url,
|
||||
hash: 0
|
||||
}).then((webpage) => {
|
||||
webpage = appWebPagesManager.saveWebPage(webpage);
|
||||
if(webpage._ == 'webPage') {
|
||||
if(this.lastUrl != url) return;
|
||||
//console.log('got webpage: ', webpage);
|
||||
|
||||
this.setTopInfo('webpage', () => {}, webpage.site_name || webpage.title || 'Webpage', webpage.description || webpage.url || '');
|
||||
|
||||
delete this.noWebPage;
|
||||
this.willSendWebPage = webpage;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.setTopInfo('webpage', () => {}, webpage.site_name || webpage.title || 'Webpage', webpage.description || webpage.url || '');
|
||||
|
||||
delete this.noWebPage;
|
||||
this.willSendWebPage = webpage;
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
} else if(this.lastUrl) {
|
||||
this.lastUrl = '';
|
||||
delete this.noWebPage;
|
||||
this.willSendWebPage = null;
|
||||
|
||||
if(this.helperType) {
|
||||
this.helperFunc();
|
||||
} else {
|
||||
this.clearHelper();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(!value.trim() && !serializeNodes(Array.from(this.messageInput.childNodes)).trim()) {
|
||||
this.messageInput.innerHTML = '';
|
||||
|
||||
@ -481,7 +503,9 @@ export class ChatInput {
|
||||
};
|
||||
}
|
||||
|
||||
this.replyElements.cancelBtn.addEventListener('click', () => {
|
||||
this.replyElements.cancelBtn.addEventListener('click', (e) => {
|
||||
cancelEvent(e);
|
||||
|
||||
if(this.willSendWebPage) {
|
||||
this.noWebPage = true;
|
||||
this.willSendWebPage = null;
|
||||
|
@ -8,31 +8,7 @@ import CheckboxField from "../checkbox";
|
||||
import PopupDeleteMessages from "../popupDeleteMessages";
|
||||
import PopupForward from "../popupForward";
|
||||
import { toast } from "../toast";
|
||||
|
||||
const SetTransition = (element: HTMLElement, className: string, forwards: boolean, duration: number, onTransitionEnd?: () => void) => {
|
||||
const timeout = element.dataset.timeout;
|
||||
if(timeout !== undefined) {
|
||||
clearTimeout(+timeout);
|
||||
}
|
||||
|
||||
if(forwards) {
|
||||
element.classList.add(className);
|
||||
}
|
||||
|
||||
element.classList.add('animating');
|
||||
|
||||
element.classList.toggle('backwards', !forwards);
|
||||
element.dataset.timeout = '' + setTimeout(() => {
|
||||
delete element.dataset.timeout;
|
||||
if(!forwards) {
|
||||
element.classList.remove('backwards', className);
|
||||
}
|
||||
|
||||
element.classList.remove('animating');
|
||||
|
||||
onTransitionEnd && onTransitionEnd();
|
||||
}, duration);
|
||||
};
|
||||
import SetTransition from "../singleTransition";
|
||||
|
||||
const MAX_SELECTION_LENGTH = 100;
|
||||
//const MIN_CLICK_MOVE = 32; // minimum bubble height
|
||||
@ -61,7 +37,16 @@ export default class ChatSelection {
|
||||
|
||||
bubblesContainer.addEventListener('mousedown', (e) => {
|
||||
//console.log('selection mousedown', e);
|
||||
if(e.button != 0 || (!this.selectedMids.size && !(e.target as HTMLElement).classList.contains('bubble'))) { // LEFT BUTTON
|
||||
const bubble = findUpClassName(e.target, 'bubble');
|
||||
// LEFT BUTTON
|
||||
// проверка внизу нужна для того, чтобы не активировать селект если target потомок .bubble
|
||||
if(e.button != 0
|
||||
|| (
|
||||
!this.selectedMids.size
|
||||
&& !(e.target as HTMLElement).classList.contains('bubble')
|
||||
&& bubble
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -80,7 +65,12 @@ export default class ChatSelection {
|
||||
} */
|
||||
|
||||
//const foundTargets: Map<HTMLElement, true> = new Map();
|
||||
let canceledSelection = false;
|
||||
const onMouseMove = (e: MouseEvent) => {
|
||||
if(!canceledSelection) {
|
||||
cancelSelection();
|
||||
canceledSelection = true;
|
||||
}
|
||||
/* if(!good) {
|
||||
if(Math.abs(e.x - x) > MIN_CLICK_MOVE || Math.abs(e.y - y) > MIN_CLICK_MOVE) {
|
||||
good = true;
|
||||
@ -93,7 +83,7 @@ export default class ChatSelection {
|
||||
foundTargets.set(e.target as HTMLElement, true); */
|
||||
const bubble = findUpClassName(e.target, 'bubble');
|
||||
if(!bubble) {
|
||||
console.error('found no bubble', e);
|
||||
//console.error('found no bubble', e);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -96,7 +96,8 @@ const InputField = (options: {
|
||||
|
||||
processInput = () => {
|
||||
const wasError = input.classList.contains('error');
|
||||
const inputLength = plainText ? input.value.length : getRichValue(input).length;
|
||||
// * https://stackoverflow.com/a/54369605 #2 to count emoji as 1 symbol
|
||||
const inputLength = plainText ? input.value.length : [...getRichValue(input)].length;
|
||||
const diff = maxLength - inputLength;
|
||||
const isError = diff < 0;
|
||||
input.classList.toggle('error', isError);
|
||||
|
@ -204,24 +204,24 @@ export default class AppEditProfileTab implements SliderTab {
|
||||
Object.assign(this.originalValues, {
|
||||
firstName: user.first_name,
|
||||
lastName: user.last_name,
|
||||
userName: user.username
|
||||
userName: user.username,
|
||||
bio: ''
|
||||
});
|
||||
|
||||
this.firstNameInput.innerHTML = user.rFirstName;
|
||||
this.lastNameInput.innerHTML = RichTextProcessor.wrapRichText(user.last_name, {noLinks: true, noLinebreaks: true});
|
||||
this.bioInput.innerHTML = '';
|
||||
this.userNameInput.value = this.originalValues.userName = user.username ?? '';
|
||||
|
||||
this.firstNameInput.classList.remove('error');
|
||||
this.lastNameInput.classList.remove('error');
|
||||
this.bioInput.classList.remove('error');
|
||||
|
||||
this.userNameInput.classList.remove('valid', 'error');
|
||||
this.userNameInput.nextElementSibling.innerHTML = 'Username (optional)';
|
||||
|
||||
appProfileManager.getProfile(user.id, true).then(userFull => {
|
||||
if(userFull.rAbout) {
|
||||
if(userFull.about) {
|
||||
this.originalValues.bio = userFull.about;
|
||||
this.bioInput.innerHTML = userFull.rAbout;
|
||||
|
||||
this.handleChange();
|
||||
}
|
||||
});
|
||||
|
||||
@ -233,6 +233,7 @@ export default class AppEditProfileTab implements SliderTab {
|
||||
this.uploadAvatar = null;
|
||||
|
||||
this.setProfileUrl();
|
||||
this.handleChange();
|
||||
}
|
||||
|
||||
public isUsernameValid(username: string) {
|
||||
@ -268,5 +269,6 @@ export default class AppEditProfileTab implements SliderTab {
|
||||
|
||||
onCloseAfterTimeout() {
|
||||
this.nextBtn.classList.remove('is-visible');
|
||||
this.firstNameInput.innerHTML = this.lastNameInput.innerHTML = this.bioInput.innerHTML = '';
|
||||
}
|
||||
}
|
26
src/components/singleTransition.ts
Normal file
26
src/components/singleTransition.ts
Normal file
@ -0,0 +1,26 @@
|
||||
const SetTransition = (element: HTMLElement, className: string, forwards: boolean, duration: number, onTransitionEnd?: () => void) => {
|
||||
const timeout = element.dataset.timeout;
|
||||
if(timeout !== undefined) {
|
||||
clearTimeout(+timeout);
|
||||
}
|
||||
|
||||
if(forwards) {
|
||||
element.classList.add(className);
|
||||
}
|
||||
|
||||
element.classList.add('animating');
|
||||
|
||||
element.classList.toggle('backwards', !forwards);
|
||||
element.dataset.timeout = '' + setTimeout(() => {
|
||||
delete element.dataset.timeout;
|
||||
if(!forwards) {
|
||||
element.classList.remove('backwards', className);
|
||||
}
|
||||
|
||||
element.classList.remove('animating');
|
||||
|
||||
onTransitionEnd && onTransitionEnd();
|
||||
}, duration);
|
||||
};
|
||||
|
||||
export default SetTransition;
|
@ -1515,16 +1515,17 @@ export class AppImManager {
|
||||
}
|
||||
|
||||
public highlightBubble(element: HTMLElement) {
|
||||
if(element.dataset.timeout) {
|
||||
clearTimeout(+element.dataset.timeout);
|
||||
const datasetKey = 'highlightTimeout';
|
||||
if(element.dataset[datasetKey]) {
|
||||
clearTimeout(+element.dataset[datasetKey]);
|
||||
element.classList.remove('is-highlighted');
|
||||
void element.offsetWidth; // reflow
|
||||
}
|
||||
|
||||
element.classList.add('is-highlighted');
|
||||
element.dataset.timeout = '' + setTimeout(() => {
|
||||
element.dataset[datasetKey] = '' + setTimeout(() => {
|
||||
element.classList.remove('is-highlighted');
|
||||
delete element.dataset.timeout;
|
||||
delete element.dataset[datasetKey];
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
|
@ -153,6 +153,7 @@ $bubble-margin: .25rem;
|
||||
z-index: 2;
|
||||
transition: opacity .3s ease;
|
||||
opacity: 0.99999; // for safari
|
||||
pointer-events: none;
|
||||
|
||||
&.is-sticky {
|
||||
opacity: 0.00001; // for safari
|
||||
@ -172,6 +173,7 @@ $bubble-margin: .25rem;
|
||||
|
||||
.bubble__container {
|
||||
cursor: pointer;
|
||||
pointer-events: all;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user