diff --git a/.DS_Store b/.DS_Store
index e96bc568..4f258411 100644
Binary files a/.DS_Store and b/.DS_Store differ
diff --git a/package-lock.json b/package-lock.json
index eca1e2e1..3e931485 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4926,13 +4926,13 @@
}
},
"globule": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.1.tgz",
- "integrity": "sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ==",
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.1.tgz",
+ "integrity": "sha512-OVyWOHgw29yosRHCHo7NncwR1hW5ew0W/UrvtwvjefVJeQ26q4/8r8FmPsSF1hJ93IgWkyv16pCTz6WblMzm/g==",
"dev": true,
"requires": {
"glob": "~7.1.1",
- "lodash": "~4.17.10",
+ "lodash": "~4.17.12",
"minimatch": "~3.0.2"
}
},
@@ -5555,13 +5555,10 @@
"integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI="
},
"is-finite": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz",
- "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=",
- "dev": true,
- "requires": {
- "number-is-nan": "^1.0.0"
- }
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz",
+ "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==",
+ "dev": true
},
"is-fullwidth-code-point": {
"version": "2.0.0",
@@ -6247,9 +6244,9 @@
}
},
"js-base64": {
- "version": "2.5.1",
- "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.5.1.tgz",
- "integrity": "sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw==",
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.5.2.tgz",
+ "integrity": "sha512-Vg8czh0Q7sFBSUMWWArX/miJeBWYBPpdU/3M/DKSaekLMqrqVPaedp+5mZhie/r0lgrcaYBfwXatEew6gwgiQQ==",
"dev": true
},
"js-sha3": {
@@ -7088,9 +7085,9 @@
}
},
"node-sass": {
- "version": "4.13.0",
- "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.13.0.tgz",
- "integrity": "sha512-W1XBrvoJ1dy7VsvTAS5q1V45lREbTlZQqFbiHb3R3OTTCma0XBtuG6xZ6Z4506nR4lmHPTqVRwxT6KgtWC97CA==",
+ "version": "4.13.1",
+ "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.13.1.tgz",
+ "integrity": "sha512-TTWFx+ZhyDx1Biiez2nB0L3YrCZ/8oHagaDalbuBSlqXgUPsdkUSzJsVxeDO9LtPB49+Fh3WQl3slABo6AotNw==",
"dev": true,
"requires": {
"async-foreach": "^0.1.3",
@@ -7191,9 +7188,9 @@
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="
},
"npm": {
- "version": "6.13.4",
- "resolved": "https://registry.npmjs.org/npm/-/npm-6.13.4.tgz",
- "integrity": "sha512-vTcUL4SCg3AzwInWTbqg1OIaOXlzKSS8Mb8kc5avwrJpcvevDA5J9BhYSuei+fNs3pwOp4lzA5x2FVDXACvoXA==",
+ "version": "6.14.1",
+ "resolved": "https://registry.npmjs.org/npm/-/npm-6.14.1.tgz",
+ "integrity": "sha512-2hi3UF7g5VL8VKm46Bx5GAW28DPb8BJZbj2uONMBMhY8XkJ56lSmHJNFcjTQr7KHZqWqiBT5BugaQEy+Y/4T2g==",
"dev": true,
"requires": {
"JSONStream": "^1.3.5",
@@ -7202,12 +7199,12 @@
"ansistyles": "~0.1.3",
"aproba": "^2.0.0",
"archy": "~1.0.0",
- "bin-links": "^1.1.6",
+ "bin-links": "^1.1.7",
"bluebird": "^3.5.5",
"byte-size": "^5.0.1",
"cacache": "^12.0.3",
"call-limit": "^1.1.1",
- "chownr": "^1.1.3",
+ "chownr": "^1.1.4",
"ci-info": "^2.0.0",
"cli-columns": "^3.1.2",
"cli-table3": "^0.5.1",
@@ -7227,7 +7224,7 @@
"glob": "^7.1.4",
"graceful-fs": "^4.2.3",
"has-unicode": "~2.0.1",
- "hosted-git-info": "^2.8.5",
+ "hosted-git-info": "^2.8.7",
"iferr": "^1.0.2",
"imurmurhash": "*",
"infer-owner": "^1.0.4",
@@ -7245,7 +7242,7 @@
"libnpmorg": "^1.0.1",
"libnpmsearch": "^2.0.2",
"libnpmteam": "^1.0.2",
- "libnpx": "^10.2.0",
+ "libnpx": "^10.2.2",
"lock-verify": "^2.1.0",
"lockfile": "^1.0.4",
"lodash._baseindexof": "*",
@@ -7264,7 +7261,7 @@
"mississippi": "^3.0.0",
"mkdirp": "~0.5.1",
"move-concurrently": "^1.0.1",
- "node-gyp": "^5.0.5",
+ "node-gyp": "^5.0.7",
"nopt": "~4.0.1",
"normalize-package-data": "^2.5.0",
"npm-audit-report": "^1.3.2",
@@ -7272,16 +7269,16 @@
"npm-install-checks": "^3.0.2",
"npm-lifecycle": "^3.1.4",
"npm-package-arg": "^6.1.1",
- "npm-packlist": "^1.4.7",
+ "npm-packlist": "^1.4.8",
"npm-pick-manifest": "^3.0.2",
"npm-profile": "^4.0.2",
- "npm-registry-fetch": "^4.0.2",
+ "npm-registry-fetch": "^4.0.3",
"npm-user-validate": "~1.0.0",
"npmlog": "~4.1.2",
"once": "~1.4.0",
"opener": "^1.5.1",
"osenv": "^0.1.5",
- "pacote": "^9.5.11",
+ "pacote": "^9.5.12",
"path-is-inside": "~1.0.2",
"promise-inflight": "~1.0.1",
"qrcode-terminal": "^0.12.0",
@@ -7292,7 +7289,7 @@
"read-installed": "~4.0.3",
"read-package-json": "^2.1.1",
"read-package-tree": "^5.3.1",
- "readable-stream": "^3.4.0",
+ "readable-stream": "^3.6.0",
"readdir-scoped-modules": "^1.1.0",
"request": "^2.88.0",
"retry": "^0.12.0",
@@ -7484,7 +7481,7 @@
}
},
"bin-links": {
- "version": "1.1.6",
+ "version": "1.1.7",
"bundled": true,
"dev": true,
"requires": {
@@ -7597,7 +7594,7 @@
}
},
"chownr": {
- "version": "1.1.3",
+ "version": "1.1.4",
"bundled": true,
"dev": true
},
@@ -8037,7 +8034,7 @@
}
},
"env-paths": {
- "version": "1.0.0",
+ "version": "2.2.0",
"bundled": true,
"dev": true
},
@@ -8381,7 +8378,7 @@
}
},
"get-caller-file": {
- "version": "1.0.2",
+ "version": "1.0.3",
"bundled": true,
"dev": true
},
@@ -8490,7 +8487,7 @@
"dev": true
},
"hosted-git-info": {
- "version": "2.8.5",
+ "version": "2.8.7",
"bundled": true,
"dev": true
},
@@ -8606,7 +8603,7 @@
}
},
"invert-kv": {
- "version": "1.0.0",
+ "version": "2.0.0",
"bundled": true,
"dev": true
},
@@ -8795,11 +8792,11 @@
"dev": true
},
"lcid": {
- "version": "1.0.0",
+ "version": "2.0.0",
"bundled": true,
"dev": true,
"requires": {
- "invert-kv": "^1.0.0"
+ "invert-kv": "^2.0.0"
}
},
"libcipm": {
@@ -8972,7 +8969,7 @@
}
},
"libnpx": {
- "version": "10.2.0",
+ "version": "10.2.2",
"bundled": true,
"dev": true,
"requires": {
@@ -9123,17 +9120,34 @@
"ssri": "^6.0.0"
}
},
+ "map-age-cleaner": {
+ "version": "0.1.3",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "p-defer": "^1.0.0"
+ }
+ },
"meant": {
"version": "1.0.1",
"bundled": true,
"dev": true
},
"mem": {
- "version": "1.1.0",
+ "version": "4.3.0",
"bundled": true,
"dev": true,
"requires": {
- "mimic-fn": "^1.0.0"
+ "map-age-cleaner": "^0.1.1",
+ "mimic-fn": "^2.0.0",
+ "p-is-promise": "^2.0.0"
+ },
+ "dependencies": {
+ "mimic-fn": {
+ "version": "2.1.0",
+ "bundled": true,
+ "dev": true
+ }
}
},
"mime-db": {
@@ -9149,11 +9163,6 @@
"mime-db": "~1.35.0"
}
},
- "mimic-fn": {
- "version": "1.2.0",
- "bundled": true,
- "dev": true
- },
"minimatch": {
"version": "3.0.4",
"bundled": true,
@@ -9241,6 +9250,11 @@
"bundled": true,
"dev": true
},
+ "nice-try": {
+ "version": "1.0.5",
+ "bundled": true,
+ "dev": true
+ },
"node-fetch-npm": {
"version": "2.0.2",
"bundled": true,
@@ -9252,36 +9266,21 @@
}
},
"node-gyp": {
- "version": "5.0.5",
+ "version": "5.0.7",
"bundled": true,
"dev": true,
"requires": {
- "env-paths": "^1.0.0",
- "glob": "^7.0.3",
- "graceful-fs": "^4.1.2",
- "mkdirp": "^0.5.0",
- "nopt": "2 || 3",
- "npmlog": "0 || 1 || 2 || 3 || 4",
- "request": "^2.87.0",
- "rimraf": "2",
- "semver": "~5.3.0",
+ "env-paths": "^2.2.0",
+ "glob": "^7.1.4",
+ "graceful-fs": "^4.2.2",
+ "mkdirp": "^0.5.1",
+ "nopt": "^4.0.1",
+ "npmlog": "^4.1.2",
+ "request": "^2.88.0",
+ "rimraf": "^2.6.3",
+ "semver": "^5.7.1",
"tar": "^4.4.12",
- "which": "1"
- },
- "dependencies": {
- "nopt": {
- "version": "3.0.6",
- "bundled": true,
- "dev": true,
- "requires": {
- "abbrev": "1"
- }
- },
- "semver": {
- "version": "5.3.0",
- "bundled": true,
- "dev": true
- }
+ "which": "^1.3.1"
}
},
"nopt": {
@@ -9381,12 +9380,13 @@
}
},
"npm-packlist": {
- "version": "1.4.7",
+ "version": "1.4.8",
"bundled": true,
"dev": true,
"requires": {
"ignore-walk": "^3.0.1",
- "npm-bundled": "^1.0.1"
+ "npm-bundled": "^1.0.1",
+ "npm-normalize-package-bin": "^1.0.1"
}
},
"npm-pick-manifest": {
@@ -9410,7 +9410,7 @@
}
},
"npm-registry-fetch": {
- "version": "4.0.2",
+ "version": "4.0.3",
"bundled": true,
"dev": true,
"requires": {
@@ -9502,13 +9502,41 @@
"dev": true
},
"os-locale": {
- "version": "2.1.0",
+ "version": "3.1.0",
"bundled": true,
"dev": true,
"requires": {
- "execa": "^0.7.0",
- "lcid": "^1.0.0",
- "mem": "^1.1.0"
+ "execa": "^1.0.0",
+ "lcid": "^2.0.0",
+ "mem": "^4.0.0"
+ },
+ "dependencies": {
+ "cross-spawn": {
+ "version": "6.0.5",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "nice-try": "^1.0.4",
+ "path-key": "^2.0.1",
+ "semver": "^5.5.0",
+ "shebang-command": "^1.2.0",
+ "which": "^1.2.9"
+ }
+ },
+ "execa": {
+ "version": "1.0.0",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "cross-spawn": "^6.0.0",
+ "get-stream": "^4.0.0",
+ "is-stream": "^1.1.0",
+ "npm-run-path": "^2.0.0",
+ "p-finally": "^1.0.0",
+ "signal-exit": "^3.0.0",
+ "strip-eof": "^1.0.0"
+ }
+ }
}
},
"os-tmpdir": {
@@ -9525,11 +9553,21 @@
"os-tmpdir": "^1.0.0"
}
},
+ "p-defer": {
+ "version": "1.0.0",
+ "bundled": true,
+ "dev": true
+ },
"p-finally": {
"version": "1.0.0",
"bundled": true,
"dev": true
},
+ "p-is-promise": {
+ "version": "2.1.0",
+ "bundled": true,
+ "dev": true
+ },
"p-limit": {
"version": "1.2.0",
"bundled": true,
@@ -9563,7 +9601,7 @@
}
},
"pacote": {
- "version": "9.5.11",
+ "version": "9.5.12",
"bundled": true,
"dev": true,
"requires": {
@@ -9877,7 +9915,7 @@
}
},
"readable-stream": {
- "version": "3.4.0",
+ "version": "3.6.0",
"bundled": true,
"dev": true,
"requires": {
@@ -10261,11 +10299,18 @@
}
},
"string_decoder": {
- "version": "1.2.0",
+ "version": "1.3.0",
"bundled": true,
"dev": true,
"requires": {
- "safe-buffer": "~5.1.0"
+ "safe-buffer": "~5.2.0"
+ },
+ "dependencies": {
+ "safe-buffer": {
+ "version": "5.2.0",
+ "bundled": true,
+ "dev": true
+ }
}
},
"stringify-package": {
@@ -10646,7 +10691,7 @@
"dev": true
},
"yargs": {
- "version": "11.0.0",
+ "version": "11.1.1",
"bundled": true,
"dev": true,
"requires": {
@@ -10654,7 +10699,7 @@
"decamelize": "^1.1.1",
"find-up": "^2.1.0",
"get-caller-file": "^1.0.1",
- "os-locale": "^2.0.0",
+ "os-locale": "^3.1.0",
"require-directory": "^2.1.1",
"require-main-filename": "^1.0.1",
"set-blocking": "^2.0.0",
diff --git a/package.json b/package.json
index b726d817..2d840f7a 100644
--- a/package.json
+++ b/package.json
@@ -42,8 +42,8 @@
"jest": "^24.9.0",
"leemon": "^6.2.0",
"lottie-web": "^5.6.4",
- "node-sass": "^4.13.0",
- "npm": "^6.13.4",
+ "node-sass": "^4.13.1",
+ "npm": "^6.14.1",
"offscreen-canvas": "^0.1.1",
"on-build-webpack": "^0.1.0",
"overlayscrollbars": "^1.10.0",
diff --git a/src/components/misc.ts b/src/components/misc.ts
index 11cce135..968be45a 100644
--- a/src/components/misc.ts
+++ b/src/components/misc.ts
@@ -52,11 +52,23 @@ export function ripple(elem: Element) {
}
}
-export function putPreloader(elem: Element) {
+export function putPreloader(elem: Element, returnDiv = false) {
const html = `
`;
+
+ if(returnDiv) {
+ let div = document.createElement('div');
+ div.classList.add('preloader');
+ div.innerHTML = html;
+
+ if(elem) {
+ elem.appendChild(div);
+ }
+
+ return div;
+ }
elem.innerHTML += html;
}
@@ -76,18 +88,19 @@ export function horizontalMenu(tabs: HTMLUListElement, content: HTMLDivElement,
///////console.log('tabs click:', target);
- if(!target || target.classList.contains('active')) return false;
+ if(!target) return false;
+
+ let id = whichChild(target);
+ let tabContent = content.children[id] as HTMLDivElement;
+ if(onClick) onClick(id, tabContent);
+ if(target.classList.contains('active') || id == prevId) {
+ return false;
+ }
let prev = tabs.querySelector('li.active') as HTMLLIElement;
prev && prev.classList.remove('active');
target.classList.add('active');
-
- let id = whichChild(target);
-
- if(id == prevId) return false;
-
- let tabContent = content.children[id] as HTMLDivElement;
tabContent.classList.add('active');
/////console.log('mambo rap', prevId, id);
@@ -139,7 +152,6 @@ export function horizontalMenu(tabs: HTMLUListElement, content: HTMLDivElement,
if(onTransitionEnd) onTransitionEnd();
}, 200);
- if(onClick) onClick(id, tabContent);
prevTabContent = tabContent;
});
}
diff --git a/src/components/scrollable.ts b/src/components/scrollable.ts
index 3b77063d..208d4044 100644
--- a/src/components/scrollable.ts
+++ b/src/components/scrollable.ts
@@ -32,12 +32,13 @@ export default class Scrollable {
public type: string;
public side: string;
+ public translate: string;
public scrollType: string;
public scrollSide: string;
public clientAxis: string;
- public scrollSize = -1;
- public size = 0;
+ public scrollSize = -1; // it will be scrollHeight
+ public size = 0; // it will be outerHeight of container (not scrollHeight)
public thumbSize = 0;
public hiddenElements: {
@@ -57,11 +58,12 @@ export default class Scrollable {
public onAddedBottom: () => void = null;
public onScrolledTop: () => void = null;
public onScrolledBottom: () => void = null;
+ public onScrolledTopFired = false;
+ public onScrolledBottomFired = false;
public topObserver: IntersectionObserver;
public bottomObserver: IntersectionObserver;
- public splitObserver: IntersectionObserver;
public splitMeasureTop: Promise<{element: Element, height: number}[]> = null;
public splitMeasureBottom: Scrollable['splitMeasureTop'] = null;
public splitMeasureAdd: Promise = null;
@@ -86,37 +88,17 @@ export default class Scrollable {
private log: ReturnType;
private debug = false;
- constructor(public el: HTMLDivElement, x = false, y = true, public splitOffset = 300, logPrefix = '') {
+ constructor(public el: HTMLDivElement, x = false, y = true, public splitOffset = 300, logPrefix = '', public appendTo = el, public onScrollOffset = splitOffset) {
this.container = document.createElement('div');
this.container.classList.add('scrollable');
this.log = logger('SCROLL' + (logPrefix ? '-' + logPrefix : ''));
- let arr = [];
- for(let i = 0.001; i < 1; i += 0.001) arr.push(i);
- this.topObserver = new IntersectionObserver(entries => {
- let entry = entries[entries.length - 1];
-
- //console.log('top intersection:', entries, entry.isIntersecting, entry.intersectionRatio > 0);
- if(entry.isIntersecting) {
- if(this.onScrolledTop) this.onScrolledTop();
- }
- // console.log('top intersection end');
- }, {root: this.el});
-
- this.bottomObserver = new IntersectionObserver(entries => {
- let entry = entries[entries.length - 1];
-
- //console.log('bottom intersection:', entries, entry, entry.isIntersecting, entry.intersectionRatio > 0);
- if(entry.isIntersecting) {
- if(this.onScrolledBottom) this.onScrolledBottom();
- }
- }, {root: this.el});
-
if(x) {
this.container.classList.add('scrollable-x');
this.type = 'width';
this.side = 'left';
+ this.translate = 'translateX';
this.scrollType = 'scrollWidth';
this.scrollSide = 'scrollLeft';
this.clientAxis = 'clientX';
@@ -141,6 +123,7 @@ export default class Scrollable {
this.container.classList.add('scrollable-y');
this.type = 'height';
this.side = 'top';
+ this.translate = 'translateY';
this.scrollType = 'scrollHeight';
this.scrollSide = 'scrollTop';
this.clientAxis = 'clientY';
@@ -181,16 +164,14 @@ export default class Scrollable {
window.addEventListener('resize', () => {
//this.resize.bind(this);
this.onScroll();
+ this.resize();
});
this.paddingTopDiv = document.createElement('div');
this.paddingTopDiv.classList.add('scroll-padding');
this.paddingBottomDiv = document.createElement('div');
this.paddingBottomDiv.classList.add('scroll-padding');
-
- this.topObserver.observe(this.paddingTopDiv);
- this.bottomObserver.observe(this.paddingBottomDiv);
-
+
this.container.addEventListener('scroll', this.onScroll.bind(this));
Array.from(el.children).forEach(c => this.container.append(c));
@@ -280,181 +261,9 @@ export default class Scrollable {
});
}
- public detachByPrevScroll(child: Element, prevScrollTop: number, needHeight = 0) {
- if(this.splitMeasureBottom) fastdom.clear(this.splitMeasureBottom);
- if(this.splitMutateBottom) fastdom.clear(this.splitMutateBottom);
-
- let attachToTop = this.paddings.up < prevScrollTop;
-
- this.splitMeasureBottom = fastdom.measure(() => {
- let sliced: {element: Element, height: number}[] = [];
-
- do {
- if(needHeight > 0) {
- needHeight -= child.scrollHeight;
- } else {
- sliced.push({element: child, height: child.scrollHeight});
- }
- } while(child = child.nextElementSibling);
- return sliced;
- });
-
- return this.splitMeasureBottom.then(sliced => {
- if(this.splitMutateBottom) fastdom.clear(this.splitMutateBottom);
-
- return this.splitMutateBottom = fastdom.mutate(() => {
- sliced.forEachReverse((child) => {
- let {element, height} = child;
- if(!this.splitUp.contains(element)) return;
-
- this.paddings.down += height;
- this.hiddenElements.down.unshift(child);
- this.splitUp.removeChild(element);
- //element.parentElement.removeChild(element);
- });
-
- this.log('sliced down', sliced);
- this.paddingBottomDiv.style.height = this.paddings.down + 'px';
- });
- });
- }
-
- public splitObserve(entries: IntersectionObserverEntry[]) {
- let sorted: {
- intersecting: {
- top?: IntersectionObserverEntry,
- bottom?: IntersectionObserverEntry
- },
- notIntersecting: {
- top?: IntersectionObserverEntry,
- bottom?: IntersectionObserverEntry
- }
- } = {
- intersecting: {},
- notIntersecting: {}
- };
-
- for(let entry of entries) { // there may be duplicates (1st - not intersecting, 2nd - intersecting)
- //console.log('onscroll entry 1', entry.target, entry.isIntersecting, entry);
- if(!entry.target.parentElement || !entry.rootBounds) continue;
-
- if(!entry.isIntersecting) {
- let isTop = entry.boundingClientRect.top <= 0;
- let isBottom = entry.rootBounds.height <= entry.boundingClientRect.top;
- //console.log('onscroll entry notIntersecting', isTop, isBottom, entry.target, entry);
-
- if(isTop) {
- sorted.notIntersecting.top = entry;
- } else if(isBottom && !sorted.notIntersecting.bottom) {
- sorted.notIntersecting.bottom = entry;
- }
-
- //console.log('splitObserver', entry, entry.target, isTop);
- } else {
- let isTop = entry.boundingClientRect.top <= entry.rootBounds.top;
- let isBottom = entry.boundingClientRect.bottom >= entry.rootBounds.bottom;
-
- if(isTop) {
- sorted.intersecting.top = entry;
- } else if(isBottom && !sorted.intersecting.bottom) {
- sorted.intersecting.bottom = entry;
- }
-
- // if(isTop) {
- // this.onTopIntersection(entry.boundingClientRect.height);
- // } else if(isBottom) {
- // this.onTopIntersection(entry.boundingClientRect.height);
- // }
- }
- }
-
- console.log('splitObserve', entries, sorted);
-
- let needHeight = this.splitOffset;
- let isOutOfView: boolean;
- let entry: IntersectionObserverEntry;
- if(entry = sorted.notIntersecting.top) { // scrolled bottom
- let child = entry.target;
-
- let diff = entry.boundingClientRect.bottom + needHeight;
- if(diff < 0) { // maybe need <=, means out of view
- if(!(child = child.nextElementSibling)) {
- this.detachTop(this.splitUp.lastElementChild, 0);
- } else {
- if(this.splitMeasureRemoveBad) fastdom.clear(this.splitMeasureRemoveBad);
- this.splitMeasureRemoveBad = fastdom.measure(() => {
- do {
- diff += child.scrollHeight;
- } while(diff < 0 && (child = child.nextElementSibling));
-
- return child || this.splitUp.lastElementChild;
- });
-
- this.splitMeasureRemoveBad.then(child => {
- this.detachTop(child, 0);
- });
- }
- } else {
- this.detachTop(child, needHeight);
- }
- }
-
- if(entry = sorted.notIntersecting.bottom) { // scrolled top
- isOutOfView = (entry.boundingClientRect.top - needHeight) >= entry.rootBounds.height;
- this.detachBottom(entry.target, isOutOfView ? 0 : needHeight);
- }
-
- if(entry = sorted.intersecting.top) { // scrolling top
- let needHeight = this.splitOffset;
-
- let child = entry.target;
- if(this.splitMeasureAdd) fastdom.clear(this.splitMeasureAdd);
- this.splitMeasureAdd = fastdom.measure(() => {
- while(child = child.previousElementSibling) {
- needHeight -= child.scrollHeight;
- }
-
- return needHeight;
- });
-
- this.splitMeasureAdd.then(needHeight => {
- this.onTopIntersection(needHeight);
- });
- }
-
- if(entry = sorted.intersecting.bottom) { // scrolling bottom
- let needHeight = this.splitOffset;
-
- let child = entry.target;
- if(this.splitMeasureAdd) fastdom.clear(this.splitMeasureAdd);
- this.splitMeasureAdd = fastdom.measure(() => {
- while(child = child.nextElementSibling) {
- needHeight -= child.scrollHeight;
- }
-
- return needHeight;
- });
-
- this.splitMeasureAdd.then(needHeight => {
- this.onBottomIntersection(needHeight);
- });
- }
- }
-
- public async resize() {
+ public resize() {
//console.time('scroll resize');
-
- await fastdom.measure(() => {
- // @ts-ignore
- this.scrollSize = this.container[this.scrollType];
-
- let rect = this.container.getBoundingClientRect();
-
- // @ts-ignore
- this.size = rect[this.type];
- });
-
- await fastdom.mutate(() => {
+ fastdom.mutate(() => {
if(!this.size || this.size == this.scrollSize) {
this.thumbSize = 0;
@@ -480,7 +289,7 @@ export default class Scrollable {
//console.log('onresize', thumb.style[type], thumbHeight, height);
}
- public async setVirtualContainer(el?: HTMLElement) {
+ public setVirtualContainer(el?: HTMLElement) {
this.splitUp = el;
this.hiddenElements.up.length = this.hiddenElements.down.length = 0;
@@ -494,12 +303,6 @@ export default class Scrollable {
});
}
- /* if(this.splitObserver) {
- this.splitObserver.disconnect();
- }
-
- this.splitObserver = new IntersectionObserver((entries) => this.splitObserve(entries), {root: this.el}); */
-
this.log('setVirtualContainer:', el, this);
this.getScrollTopOffset();
@@ -509,6 +312,9 @@ export default class Scrollable {
el.parentElement.insertBefore(this.paddingTopDiv, el);
el.parentNode.insertBefore(this.paddingBottomDiv, el.nextSibling);
});
+ } else {
+ this.paddingTopDiv.remove();
+ this.paddingBottomDiv.remove();
}
}
@@ -529,33 +335,66 @@ export default class Scrollable {
public onScroll() {
if(this.onScrollMeasure) fastdom.clear(this.onScrollMeasure);
this.onScrollMeasure = fastdom.measure(() => {
+ // @ts-ignore quick brown fix
+ this.size = this.parentElement[this.scrollType];
+
// @ts-ignore
- if(this.container[this.scrollType] != this.scrollSize || this.thumbSize == 0) {
+ let scrollSize = this.container[this.scrollType];
+ if(scrollSize != this.scrollSize || this.thumbSize == 0) {
this.resize();
}
-
+ this.scrollSize = scrollSize;
+
// @ts-ignore
- let value = this.container[this.scrollSide] / (this.scrollSize - this.size) * 100;
- let maxValue = 100 - (this.thumbSize / this.size * 100);
+ let scrollPos = this.container[this.scrollSide];
+
+ // let value = scrollPos / (this.scrollSize - this.size) * 100;
+ // let maxValue = 100 - (this.thumbSize / this.size * 100);
+ let value = scrollPos / (this.scrollSize - this.size) * this.size;
+ let maxValue = this.size - this.thumbSize;
+ //this.log(scrollPos, this.scrollSize, this.size, value, scrollPos / (this.scrollSize - this.size) * this.size);
let ret = {value, maxValue};
+
+ let scrollTop = scrollPos - this.scrollTopOffset;
+ let maxScrollTop = this.scrollSize - this.scrollTopOffset - this.size;
+
+ if(this.onScrolledBottom) {
+ if(!this.hiddenElements.down.length && (maxScrollTop - scrollTop) <= this.onScrollOffset) {
+ if(!this.onScrolledBottomFired) {
+ this.onScrolledBottomFired = true;
+ this.onScrolledBottom();
+ }
+ } else {
+ this.onScrolledBottomFired = false;
+ }
+ }
+
+ if(this.onScrolledTop) {
+ //this.log('onScrolledTop:', scrollTop, this.onScrollOffset);
+ if(!this.hiddenElements.up.length && scrollTop <= this.onScrollOffset) {
+ if(!this.onScrolledTopFired) {
+ this.onScrolledTopFired = true;
+ this.onScrolledTop();
+ }
+ } else {
+ this.onScrolledTopFired = false;
+ }
+ }
if(!this.splitUp) {
return ret;
}
let perf = performance.now();
- let scrollTop = this.scrollTop - this.scrollTopOffset;
- let outerHeight = this.parentElement.scrollHeight;
- let maxScrollTop = this.scrollHeight - this.scrollTopOffset - outerHeight;
if(scrollTop < 0) scrollTop = 0;
else if(scrollTop > maxScrollTop) scrollTop = maxScrollTop;
let toBottom = scrollTop > this.lastScrollTop;
let visibleFrom = /* scrollTop < this.paddings.up ? scrollTop : */scrollTop - this.paddings.up;
- let visibleUntil = visibleFrom + outerHeight;
+ let visibleUntil = visibleFrom + this.size;
let sum = 0;
let firstVisibleElement: Element;
@@ -619,10 +458,6 @@ export default class Scrollable {
this.onBottomIntersection(needHeight);
return needHeight;
});
-
- /* this.splitMeasureAdd.then(needHeight => {
- this.onBottomIntersection(needHeight);
- }); */
} else if(length) { // scrolled manually or safari
if(this.debug) {
this.log.warn('will detach all of top', length, this.splitUp.childElementCount, maxScrollTop, this.paddings, this.lastScrollTop);
@@ -652,10 +487,6 @@ export default class Scrollable {
this.onTopIntersection(needHeight);
return needHeight;
});
-
- /* this.splitMeasureAdd.then(needHeight => {
- this.onTopIntersection(needHeight);
- }); */
} else if(length) { // scrolled manually or safari
if(this.debug) {
this.log.warn('will detach all of bottom', length, this.splitUp.childElementCount, maxScrollTop, this.paddings, this.lastScrollTop);
@@ -681,7 +512,8 @@ export default class Scrollable {
this.onScrollMeasure.then(({value, maxValue}) => {
fastdom.mutate(() => {
// @ts-ignore
- this.thumb.style[this.side] = (value >= maxValue ? maxValue : value) + '%';
+ //this.thumb.style[this.side] = (value >= maxValue ? maxValue : value) + '%';
+ this.thumb.style.transform = this.translate + '(' + (value >= maxValue ? maxValue : value) + 'px)';
});
});
@@ -691,7 +523,7 @@ export default class Scrollable {
public onManualScrollTop(scrollTop: number, needHeight: number, maxScrollTop: number) {
//if(this.splitMutateRemoveBad) fastdom.clear(this.splitMutateRemoveBad);
this.splitMutateRemoveBad = fastdom.mutate(() => {
- let h = maxScrollTop - (scrollTop + outerHeight);
+ let h = maxScrollTop - (scrollTop + this.size);
while(this.paddings.down < h && this.paddings.up) {
let child = this.hiddenElements.up.pop();
@@ -705,11 +537,8 @@ export default class Scrollable {
}
this.paddingBottomDiv.style.height = this.paddings.down + 'px';
- this.onTopIntersection((outerHeight * 2) + (needHeight * 2));
+ this.onTopIntersection((this.size * 2) + (needHeight * 2));
});
-
- /* this.splitMutateRemoveBad.then(() => {
- }); */
}
public onManualScrollBottom(scrollTop: number, needHeight: number) {
@@ -729,11 +558,8 @@ export default class Scrollable {
}
this.paddingTopDiv.style.height = this.paddings.up + 'px';
- this.onBottomIntersection(outerHeight + (needHeight * 2));
+ this.onBottomIntersection(this.size + (needHeight * 2));
});
-
- /* this.splitMutateRemoveBad.then(() => {
- }); */
}
public onTopIntersection(needHeight: number) {
@@ -813,7 +639,7 @@ export default class Scrollable {
});
if(this.hiddenElements.up.length) {
- fastdom.mutate(() => {
+ /* fastdom.mutate(() => {
this.splitUp.append(...smth);
}).then(() => {
return fastdom.measure(() => {
@@ -839,13 +665,26 @@ export default class Scrollable {
this.onScroll();
});
+ }); */
+ this.splitUp.prepend(...smth);
+ smth.forEachReverse(node => {
+ let height = node.scrollHeight;
+ this.log('will append element to up hidden', node, height);
+ this.paddings.up += height;
+ this.hiddenElements.up.unshift({
+ element: node,
+ height: height
+ });
+ node.parentElement.removeChild(node);
});
+ this.paddingTopDiv.style.height = this.paddings.up + 'px';
+ this.onScroll();
} else {
this.splitUp.prepend(...smth);
this.onScroll();
}
} else {
- this.container.prepend(...smth);
+ this.appendTo.prepend(...smth);
this.onScroll();
}
@@ -891,7 +730,7 @@ export default class Scrollable {
this.onScroll();
}
} else {
- this.container.append(...smth);
+ this.appendTo.append(...smth);
this.onScroll();
}
@@ -914,17 +753,14 @@ export default class Scrollable {
}
}
- let index = this.hiddenElements.up.findIndex(c => c.element == element);
- let child: {element: Element, height: number};
+ let child = this.hiddenElements.up.findAndSplice(c => c.element == element);
let foundUp = false;
- if(index !== -1) {
- child = this.hiddenElements.up.splice(index, 1)[0];
+ if(child) {
this.paddings.up -= child.height;
foundUp = true;
} else {
- index = this.hiddenElements.down.findIndex(c => c.element == element);
- if(index !== -1) {
- child = this.hiddenElements.down.splice(index, 1)[0];
+ child = this.hiddenElements.down.findAndSplice(c => c.element == element);
+ if(child) {
this.paddings.down -= child.height;
}
}
@@ -943,7 +779,7 @@ export default class Scrollable {
}
public insertBefore(newChild: Element, refChild: Element, height?: number) {
- this.log('insertBefore', newChild, refChild);
+ //this.log('insertBefore', newChild, refChild);
return;
if(this.splitUp) {
@@ -1022,6 +858,29 @@ export default class Scrollable {
this.onScroll();
return ret;
}
+
+ public scrollIntoView(element: Element) {
+ if(element.parentElement) {
+ element.scrollIntoView();
+ } else if(this.splitUp) {
+ let index = this.hiddenElements.up.findIndex(e => e.element == element);
+ let y = 0;
+ if(index !== -1) {
+ for(let i = 0; i < index; ++i) {
+ y += this.hiddenElements.up[i].height;
+ }
+
+ this.scrollTop = y;
+ } else if((index = this.hiddenElements.down.findIndex(e => e.element == element)) !== -1) {
+ y += this.paddings.up + this.size;
+ for(let i = 0; i < index; ++i) {
+ y += this.hiddenElements.down[i].height;
+ }
+
+ this.scrollTop = y;
+ }
+ }
+ }
set scrollTop(y: number) {
fastdom.mutate(() => {
diff --git a/src/components/wrappers.ts b/src/components/wrappers.ts
index 79e461a6..fb31d380 100644
--- a/src/components/wrappers.ts
+++ b/src/components/wrappers.ts
@@ -259,15 +259,21 @@ export function wrapAudio(doc: MTDocument, withTime = false): HTMLDivElement {
let svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
svg.classList.add('audio-waveform');
- svg.setAttributeNS(null, 'width', '250');
+ svg.setAttributeNS(null, 'width', '190');
svg.setAttributeNS(null, 'height', '23');
- svg.setAttributeNS(null, 'viewBox', '0 0 250 23');
+ svg.setAttributeNS(null, 'viewBox', '0 0 190 23');
div.insertBefore(svg, div.lastElementChild);
let wave = doc.attributes[0].waveform as Uint8Array;
let index = 0;
+ let skipped = 0;
for(let uint8 of wave) {
+ if (index > 0 && index % 4 == 0) {
+ ++index;
+ ++skipped;
+ continue;
+ }
let percents = uint8 / 255;
let height = 23 * percents;
@@ -276,12 +282,14 @@ export function wrapAudio(doc: MTDocument, withTime = false): HTMLDivElement {
}
svg.insertAdjacentHTML('beforeend', `
-
+
`);
++index;
}
+ let progress = div.querySelector('.audio-waveform') as HTMLDivElement;
+
let onClick = () => {
if(!promise) {
if(downloadDiv.classList.contains('downloading')) {
@@ -310,6 +318,7 @@ export function wrapAudio(doc: MTDocument, withTime = false): HTMLDivElement {
let toggle = div.querySelector('.audio-toggle') as HTMLDivElement;
let interval = 0;
+ let lastIndex = 0;
toggle.addEventListener('click', () => {
if(audio.paused) {
@@ -327,7 +336,6 @@ export function wrapAudio(doc: MTDocument, withTime = false): HTMLDivElement {
(Array.from(svg.children) as HTMLElement[]).forEach(node => node.classList.remove('active'));
- let lastIndex = 0;
interval = setInterval(() => {
if(lastIndex > svg.childElementCount || isNaN(audio.duration)) {
clearInterval(interval);
@@ -337,10 +345,11 @@ export function wrapAudio(doc: MTDocument, withTime = false): HTMLDivElement {
// @ts-ignore
timeDiv.innerText = String(audio.currentTime | 0).toHHMMSS(true);
- lastIndex = Math.round(audio.currentTime / audio.duration * 62);
+ lastIndex = Math.round(audio.currentTime / audio.duration * 47);
//svg.children[lastIndex].setAttributeNS(null, 'fill', '#000');
- svg.children[lastIndex].classList.add('active');
+ //svg.children[lastIndex].classList.add('active'); #Иногда пропускает полоски..
+ (Array.from(svg.children) as HTMLElement[]).slice(0,lastIndex+1).forEach(node => node.classList.add('active'));
//++lastIndex;
//console.log('lastIndex:', lastIndex, audio.currentTime);
//}, duration * 1000 / svg.childElementCount | 0/* 63 * duration / 10 */);
@@ -358,11 +367,51 @@ export function wrapAudio(doc: MTDocument, withTime = false): HTMLDivElement {
toggle.classList.add('tgico-largeplay');
toggle.classList.remove('tgico-largepause');
clearInterval(interval);
+ (Array.from(svg.children) as HTMLElement[]).forEach(node => node.classList.remove('active'));
// @ts-ignore
timeDiv.innerText = String(audio.currentTime | 0).toHHMMSS(true);
});
+ let mousedown = false, mousemove = false;
+ progress.addEventListener('mouseleave', (e) => {
+ if(mousedown) {
+ audio.play();
+ mousedown = false;
+ }
+ mousemove = false;
+ })
+ progress.addEventListener('mousemove', (e) => {
+ mousemove = true;
+ if(mousedown) scrub(e, audio, progress);
+ });
+ progress.addEventListener('mousedown', (e) => {
+ e.preventDefault();
+ if(!audio.paused) {
+ audio.pause();
+ scrub(e, audio, progress);
+ mousedown = true;
+ }
+ });
+ progress.addEventListener('mouseup', (e) => {
+ if (mousemove && mousedown) {
+ audio.play();
+ mousedown = false;
+ }
+ });
+ progress.addEventListener('click', (e) => {
+ if(!audio.paused) scrub(e, audio, progress);
+ });
+
+ function scrub(e: MouseEvent, audio: HTMLAudioElement, progress: HTMLDivElement) {
+ let scrubTime = e.offsetX / 190 /* width */ * audio.duration;
+ (Array.from(svg.children) as HTMLElement[]).forEach(node => node.classList.remove('active'));
+ lastIndex = Math.round(scrubTime / audio.duration * 47);
+
+ (Array.from(svg.children) as HTMLElement[]).slice(0,lastIndex+1).forEach(node => node.classList.add('active'));
+ audio.currentTime = scrubTime;
+ }
+
audio.append(source);
audio.style.display = 'none';
div.append(audio);
diff --git a/src/lib/appManagers/appImManager.ts b/src/lib/appManagers/appImManager.ts
index 024561b4..407b076f 100644
--- a/src/lib/appManagers/appImManager.ts
+++ b/src/lib/appManagers/appImManager.ts
@@ -27,35 +27,167 @@ console.log('appImManager included!');
let testScroll = false;
class ScrollPosition {
- public previousScrollHeightMinusTop = 0;
- public readyFor = 'up';
- public container: HTMLElement;
-
- constructor(public node: HTMLElement) {
+ previousScrollHeightMinusTop = 0;
+ readyFor = 'up';
+ container: HTMLElement;
+ rAF: number;
+ debug = true;
+
+ constructor(node: HTMLElement) {
this.container = node.parentElement;
}
+
+ restore() {
+ let setScrollTop = this.container.scrollHeight - this.previousScrollHeightMinusTop;
+ if(this.debug) appImManager.log('scrollPosition restore', this.readyFor, this.container.scrollHeight,
+ setScrollTop, this.container, this.container.parentElement.classList.contains('scrolled-down'));
+
+ if(this.readyFor === 'up'/* || this.container.parentElement.classList.contains('scrolled-down') */) {
+ if(this.debug) appImManager.log('scrollPosition restore 2', this.readyFor, this.container.scrollHeight,
+ setScrollTop, this.container);
+
+ if(this.rAF) window.cancelAnimationFrame(this.rAF);
+ this.rAF = window.requestAnimationFrame(() => {
+ this.container.scrollTop = this.container.scrollHeight - this.previousScrollHeightMinusTop;
+ this.rAF = 0;
+ });
+ } else if(this.container.parentElement.classList.contains('scrolled-down')) {
+ if(this.debug) appImManager.log('scrollPosition restore 2', this.readyFor, this.container.scrollHeight,
+ setScrollTop, this.container);
- public restore() {
- //console.log('scrollPosition restore 2', this.node.scrollHeight, (this.node.scrollHeight
- //- this.previousScrollHeightMinusTop) + 'px', this.container);
-
- if(this.readyFor === 'up' || appImManager.scroll.parentElement.classList.contains('scrolled-down')) {
- this.container.scrollTop = this.node.scrollHeight
- - this.previousScrollHeightMinusTop;
+ this.container.scrollTop = setScrollTop;
}
-
+
// 'down' doesn't need to be special cased unless the
// content was flowing upwards, which would only happen
// if the container is position: absolute, bottom: 0 for
// a Facebook messages effect
}
+
+ prepareFor(direction = 'up') {
+ if(this.rAF) {
+ window.cancelAnimationFrame(this.rAF);
+ this.rAF = 0;
+ }
- public prepareFor(direction: string) {
- this.readyFor = direction || 'up';
- this.previousScrollHeightMinusTop = this.node.scrollHeight
- - this.container.scrollTop;
+ this.readyFor = direction;
- //console.log('scrollPosition prepareFor', direction, this.node.scrollHeight, this.previousScrollHeightMinusTop + 'px')
+ if(direction == 'down') {
+ let scrollTop = this.container.scrollTop;
+ this.previousScrollHeightMinusTop = scrollTop > 0 ? this.container.scrollHeight - scrollTop : 0;
+ } else {
+ this.previousScrollHeightMinusTop = this.container.scrollHeight - this.container.scrollTop;
+ }
+ //let scrollTop = this.container.scrollTop;
+ //this.previousScrollHeightMinusTop = scrollTop > 0 || this.readyFor == 'up' ? this.container.scrollHeight - this.container.scrollTop : 0;
+
+ if(this.debug) appImManager.log.trace('scrollPosition prepareFor', direction, this.container.scrollHeight,
+ this.container.scrollTop, this.previousScrollHeightMinusTop);
+ }
+}
+
+class BubbleGroups {
+ bubblesByGroups: Array<{timestamp: number, fromID: number, mid: number, group: HTMLDivElement[]}> = []; // map to group
+ groups: Array = [];
+ updateRAFs: Map = new Map();
+ newGroupDiff = 120;
+
+ removeBubble(bubble: HTMLDivElement, mid: number) {
+ let details = this.bubblesByGroups.findAndSplice(g => g.mid == mid);
+ if(details && details.group.length) {
+ details.group.findAndSplice(d => d == bubble);
+ if(!details.group.length) {
+ this.groups.findAndSplice(g => g == details.group);
+ }
+ }
+ }
+
+ addBubble(bubble: HTMLDivElement, message: any, reverse: boolean) {
+ let timestamp = message.date;
+ let fromID = message.fromID;
+ let group: HTMLDivElement[];
+
+ // try to find added
+ //this.removeBubble(message.mid);
+
+ if(this.bubblesByGroups.length) {
+ if(reverse) {
+ let g = this.bubblesByGroups[0];
+ if(g.fromID == fromID && (g.timestamp - timestamp) < this.newGroupDiff) {
+ group = g.group;
+ group.unshift(bubble);
+ } else {
+ this.groups.unshift(group = [bubble]);
+ }
+ } else {
+ let g = this.bubblesByGroups[this.bubblesByGroups.length - 1];
+ if(g.fromID == fromID && (timestamp - g.timestamp) < this.newGroupDiff) {
+ group = g.group;
+ group.push(bubble);
+ } else {
+ this.groups.push(group = [bubble]);
+ }
+ }
+ } else {
+ this.groups.push(group = [bubble]);
+ }
+
+ console.log('addBubble', bubble, message.mid, fromID, reverse, group);
+
+ this.bubblesByGroups[reverse ? 'unshift' : 'push']({timestamp, fromID, mid: message.mid, group});
+ this.updateGroup(group);
+ }
+
+ updateGroup(group: HTMLDivElement[]) {
+ if(this.updateRAFs.has(group)) {
+ window.cancelAnimationFrame(this.updateRAFs.get(group));
+ this.updateRAFs.delete(group);
+ }
+
+ this.updateRAFs.set(group, window.requestAnimationFrame(() => {
+ this.updateRAFs.delete(group);
+
+ if(!group.length) {
+ return;
+ }
+
+ let first = group[0];
+
+ console.log('updateGroup', group, first);
+
+ if(group.length == 1) {
+ first.classList.add('is-group-first', 'is-group-last');
+ return;
+ } else {
+ first.classList.remove('is-group-last');
+ first.classList.add('is-group-first');
+ }
+
+ let length = group.length - 1;
+ for(let i = 1; i < length; ++i) {
+ let bubble = group[i];
+ bubble.classList.remove('is-group-last', 'is-group-first');
+ }
+
+ let last = group[group.length - 1];
+ last.classList.remove('is-group-first');
+ last.classList.add('is-group-last');
+ }));
+ }
+
+ updateGroupByMessageID(mid: number) {
+ let details = this.bubblesByGroups.find(g => g.mid == mid);
+ if(details) {
+ this.updateGroup(details.group);
+ }
+ }
+
+ cleanup() {
+ this.bubblesByGroups = [];
+ for(let value of this.updateRAFs.values()) {
+ window.cancelAnimationFrame(value);
+ }
+ this.updateRAFs.clear();
}
}
@@ -72,13 +204,13 @@ export class AppImManager {
public goDownBtn = this.pageEl.querySelector('#bubbles-go-down') as HTMLButtonElement;
private getHistoryPromise: Promise;
private getHistoryTimeout = 0;
-
+
private chatInputC: ChatInput = null;
-
+
public myID = 0;
public peerID = 0;
public muted = false;
-
+
public bubbles: {[mid: number]: HTMLDivElement} = {};
public dateMessages: {[timestamp: number]: { div: HTMLDivElement, firstTimestamp: number }} = {};
public unreaded: number[] = [];
@@ -87,13 +219,13 @@ export class AppImManager {
public offline = false;
public updateStatusInterval = 0;
-
+
public pinnedMsgID = 0;
private pinnedMessageContainer = this.pageEl.querySelector('.pinned-message') as HTMLDivElement;
private pinnedMessageContent = this.pinnedMessageContainer.querySelector('.pinned-message-subtitle') as HTMLDivElement;
private firstTopMsgID = 0;
-
+
public loadMediaQueue: Array<() => Promise> = [];
private loadMediaQueuePromise: Promise = null;
private loadingMedia = 0;
@@ -101,116 +233,121 @@ export class AppImManager {
public scroll: HTMLDivElement = null;
public scrollable: Scrollable = null;
public scrollPosition: ScrollPosition = null;
-
+
public log: ReturnType;
-
+
private preloader: ProgressivePreloader = null;
-
+
private typingTimeouts: {[peerID: number]: number} = {};
private typingUsers: {[userID: number]: number} = {} // to peerID
-
+
private topbar: HTMLDivElement = null;
private chatInput: HTMLDivElement = null;
private scrolledAll: boolean;
private scrolledAllDown: boolean;
-
+
public contextMenu = document.getElementById('bubble-contextmenu') as HTMLDivElement;
private contextMenuPin = this.contextMenu.querySelector('.menu-pin') as HTMLDivElement;
private contextMenuEdit = this.contextMenu.querySelector('.menu-edit') as HTMLDivElement;
private contextMenuMsgID: number;
-
+
private popupDeleteMessage: {
popupEl?: HTMLDivElement,
deleteBothBtn?: HTMLButtonElement,
deleteMeBtn?: HTMLButtonElement,
cancelBtn?: HTMLButtonElement
} = {};
-
+
private setPeerPromise: Promise = null;
-
+
+ public bubbleGroups = new BubbleGroups();
+
constructor() {
this.log = logger('IM');
-
+
this.chatInputC = new ChatInput();
-
+
this.preloader = new ProgressivePreloader(null, false);
-
+
this.popupDeleteMessage.popupEl = this.pageEl.querySelector('.popup-delete-message') as HTMLDivElement;
this.popupDeleteMessage.deleteBothBtn = this.popupDeleteMessage.popupEl.querySelector('.popup-delete-both') as HTMLButtonElement;
this.popupDeleteMessage.deleteMeBtn = this.popupDeleteMessage.popupEl.querySelector('.popup-delete-me') as HTMLButtonElement;
this.popupDeleteMessage.cancelBtn = this.popupDeleteMessage.popupEl.querySelector('.popup-close') as HTMLButtonElement;
-
+
apiManager.getUserID().then((id) => {
this.myID = id;
});
-
+
this.topbar = document.getElementById('topbar') as HTMLDivElement;
this.chatInput = document.getElementById('chat-input') as HTMLDivElement;
-
+
$rootScope.$on('user_auth', (e: CustomEvent) => {
let userAuth = e.detail;
this.myID = userAuth ? userAuth.id : 0;
});
-
+
+ // will call when message is sent (only 1)
$rootScope.$on('history_append', (e: CustomEvent) => {
let details = e.detail;
-
+
this.renderMessagesByIDs([details.messageID]);
});
-
+
+ // will call when sent for update pos
$rootScope.$on('history_update', (e: CustomEvent) => {
let details = e.detail;
-
+
if(details.mid && details.peerID == this.peerID) {
let mid = details.mid;
-
+
let bubble = this.bubbles[mid];
if(!bubble) return;
-
+
let message = appMessagesManager.getMessage(mid);
//this.log('history_update', this.bubbles[mid], mid, message);
- this.renderMessage(message, false, false, bubble);
+ this.renderMessage(message, false, false, bubble);
+
this.deleteEmptySideDivs();
}
});
-
+
$rootScope.$on('history_multiappend', (e: CustomEvent) => {
let msgIDsByPeer = e.detail;
if(!(this.peerID in msgIDsByPeer)) return;
-
+
let msgIDs = msgIDsByPeer[this.peerID];
-
+
this.renderMessagesByIDs(msgIDs);
-
+
//appDialogsManager.sortDom();
});
-
+
$rootScope.$on('history_delete', (e: CustomEvent) => {
let detail: {
peerID: string,
msgs: {[x: number]: boolean}
} = e.detail;
-
+
this.deleteMessagesByIDs(Object.keys(detail.msgs).map(s => +s));
-
+
setTimeout(() => {
this.deleteEmptySideDivs();
}, 0);
});
-
+
// Calls when message successfully sent and we have an ID
$rootScope.$on('message_sent', (e: CustomEvent) => {
let {tempID, mid} = e.detail;
-
+
////this.log('message_sent', e.detail);
-
+
let bubble = this.bubbles[tempID];
if(bubble) {
this.bubbles[mid] = bubble;
-
+
/////this.log('message_sent', bubble);
-
+
let media = bubble.querySelector('img, video');
if(media) {
media.setAttribute('message-id', mid);
@@ -219,11 +356,13 @@ export class AppImManager {
bubble.classList.remove('is-sending');
bubble.classList.add('is-sent');
+ this.bubbleGroups.removeBubble(bubble, tempID);
+
delete this.bubbles[tempID];
} else {
this.log.warn('message_sent there is no bubble', e.detail);
}
-
+
let length = this.unreadOut.length;
for(let i = 0; i < length; i++) {
if(this.unreadOut[i] == tempID) {
@@ -231,19 +370,19 @@ export class AppImManager {
}
}
});
-
+
$rootScope.$on('message_edit', (e: CustomEvent) => {
let {peerID, mid, id, justMedia} = e.detail;
-
+
if(peerID != this.peerID) return;
-
+
let bubble = this.bubbles[mid];
if(!bubble) return;
-
+
let message = appMessagesManager.getMessage(mid);
this.renderMessage(message, false, false, bubble, false);
});
-
+
$rootScope.$on('messages_downloaded', (e: CustomEvent) => {
let mids: number[] = e.detail;
@@ -255,65 +394,65 @@ export class AppImManager {
this.pinnedMessageContainer.style.display = '';
this.pinnedMessageContent.innerHTML = RichTextProcessor.wrapEmojiText(message.message);
}
-
+
this.needUpdate.forEachReverse((obj, idx) => {
if(obj.replyMid == mid) {
let {mid, replyMid} = this.needUpdate.splice(idx, 1)[0];
-
+
//this.log('messages_downloaded', mid, replyMid, i, this.needUpdate, this.needUpdate.length, mids, this.bubbles[mid]);
let bubble = this.bubbles[mid];
if(!bubble) return;
-
+
let message = appMessagesManager.getMessage(mid);
-
+
let repliedMessage = appMessagesManager.getMessage(replyMid);
if(repliedMessage.deleted) { // чтобы не пыталось бесконечно загрузить удалённое сообщение
delete message.reply_to_mid; // WARNING!
}
-
+
this.renderMessage(message, false, false, bubble, false);
}
});
});
});
-
+
$rootScope.$on('apiUpdate', (e: CustomEvent) => {
let update = e.detail;
-
+
this.handleUpdate(update);
});
-
+
window.addEventListener('blur', () => {
lottieLoader.checkAnimations(true);
-
+
this.offline = true;
this.updateStatus();
clearInterval(this.updateStatusInterval);
window.addEventListener('focus', () => {
lottieLoader.checkAnimations(false);
-
+
this.offline = false;
this.updateStatus();
this.updateStatusInterval = window.setInterval(() => this.updateStatus(), 50e3);
}, {once: true});
});
-
+
(this.pageEl.querySelector('.person') as HTMLDivElement).addEventListener('click', (e) => {
appSidebarRight.toggleSidebar(true);
});
-
+
this.chatInner.addEventListener('click', (e) => {
let target = e.target as HTMLElement;
let bubble: HTMLDivElement = null;
try {
bubble = findUpClassName(e.target, 'bubble');
} catch(err) {}
-
+
if(!bubble) return;
-
+
if(['IMG', 'VIDEO', 'SVG', 'DIV'].indexOf(target.tagName) === -1) target = findUpTag(target, 'DIV');
-
+
if(target.tagName == 'DIV') {
if(target.classList.contains('forward')) {
let savedFrom = bubble.dataset.savedFrom;
@@ -329,16 +468,16 @@ export class AppImManager {
if(!isNaN(peerID)) {
this.setPeer(peerID);
}
-
+
return;
}
-
+
let isReplyClick = false;
-
+
try {
isReplyClick = !!findUpClassName(e.target, 'reply');
} catch(err) {}
-
+
if(isReplyClick && bubble.classList.contains('is-reply')/* || bubble.classList.contains('forwarded') */) {
let originalMessageID = +bubble.getAttribute('data-original-mid');
this.setPeer(this.peerID, originalMessageID);
@@ -347,103 +486,101 @@ export class AppImManager {
} else if(target.tagName == 'IMG' && target.parentElement.classList.contains('user-avatar')) {
let peerID = +target.parentElement.dataset.peerID;
-
+
if(!isNaN(peerID)) {
this.setPeer(peerID);
}
} else if((target.tagName == 'IMG' && !target.classList.contains('emoji')) || target.tagName == 'VIDEO') {
let messageID = +target.getAttribute('message-id');
let message = appMessagesManager.getMessage(messageID);
-
+
if(!message) {
this.log.warn('no message by messageID:', messageID);
return;
}
-
+
let ids = Object.keys(this.bubbles).map(k => +k).filter(id => {
let message = appMessagesManager.getMessage(id);
-
- return message.media && (message.media.photo
- || (message.media.document && (message.media.document.type == 'video' || message.media.document.type == 'gif'))
- || (message.media.webpage && (message.media.webpage.document || message.media.webpage.photo)));
+
+ return message.media && (message.media.photo || (message.media.document && (message.media.document.type == 'video' || message.media.document.type == 'gif')) || (message.media.webpage && (message.media.webpage.document || message.media.webpage.photo)));
}).sort();
let idx = ids.findIndex(i => i == messageID);
-
+
let prev = ids[idx + 1] || null;
let next = ids[idx - 1] || null;
-
+
let prevTarget = this.bubbles[prev] ? this.bubbles[prev].querySelector('img, video') as HTMLElement : null;
let nextTarget = this.bubbles[next] ? this.bubbles[next].querySelector('img, video') as HTMLElement : null;
-
+
/////this.log('ids', ids, idx, this.bubbles[prev], this.bubbles[next]);
-
+
appMediaViewer.openMedia(message, target, nextTarget, prevTarget);
-
+
//appMediaViewer.openMedia(message, target as HTMLImageElement);
}
-
+
//console.log('chatInner click', e);
});
-
+
this.searchBtn.addEventListener('click', (e) => {
if(this.peerID) {
appSidebarLeft.beginSearch(this.peerID);
}
});
-
+
this.pinnedMessageContainer.addEventListener('click', (e) => {
e.preventDefault();
e.cancelBubble = true;
-
+
let mid = +this.pinnedMessageContainer.getAttribute('data-mid');
this.setPeer(this.peerID, mid);
});
-
+
this.btnMenuMute.addEventListener('click', () => this.mutePeer());
this.btnMute.addEventListener('click', () => this.mutePeer());
-
+
let onKeyDown = (e: KeyboardEvent) => {
let target = e.target as HTMLElement;
-
+
//if(target.tagName == 'INPUT') return;
-
+
//this.log('onkeydown', e);
-
+
if(this.chatInputC.attachMediaPopUp.container.classList.contains('active')) {
if(target.tagName != 'INPUT') {
this.chatInputC.attachMediaPopUp.captionInput.focus();
}
-
+
if(e.key == 'Enter') {
this.chatInputC.attachMediaPopUp.sendBtn.click();
} else if(e.key == 'Escape') {
this.chatInputC.attachMediaPopUp.container.classList.remove('active');
}
-
+
return;
}
-
+
if(e.key == 'Meta' || e.key == 'Control') {
return;
} else if(e.key == 'c' && (e.ctrlKey || e.metaKey) && target.tagName != 'INPUT') {
return;
}
-
+
if(e.target != this.chatInputC.messageInput && target.tagName != 'INPUT') {
this.chatInputC.messageInput.focus();
placeCaretAtEnd(this.chatInputC.messageInput);
}
};
-
+
document.body.addEventListener('keydown', onKeyDown);
-
+
this.chatInner.addEventListener('contextmenu', e => {
let bubble: HTMLDivElement = null;
-
+
try {
bubble = findUpClassName(e.target, 'bubble');
} catch(e) {}
-
+
if(bubble) {
e.preventDefault();
e.cancelBubble = true;
@@ -455,60 +592,59 @@ export class AppImManager {
break;
}
}
-
+
if(!msgID) return;
-
- if(this.myID == this.peerID ||
- (this.peerID < 0 && !appPeersManager.isChannel(this.peerID) && !appPeersManager.isMegagroup(this.peerID))) {
+
+ if(this.myID == this.peerID || (this.peerID < 0 && !appPeersManager.isChannel(this.peerID) && !appPeersManager.isMegagroup(this.peerID))) {
this.contextMenuPin.style.display = '';
} else this.contextMenuPin.style.display = 'none';
-
+
this.contextMenuMsgID = msgID;
-
+
let side = bubble.parentElement.classList.contains('in') ? 'left' : 'right';
-
+
this.contextMenuEdit.style.display = side == 'right' ? '' : 'none';
-
+
this.contextMenu.classList.remove('bottom-left', 'bottom-right');
this.contextMenu.classList.add(side == 'left' ? 'bottom-right' : 'bottom-left');
-
+
let {clientX, clientY} = e;
-
+
this.contextMenu.style.left = (side == 'right' ? clientX - this.contextMenu.scrollWidth : clientX) + 'px';
if((clientY + this.contextMenu.scrollHeight) > window.innerHeight) {
this.contextMenu.style.top = (window.innerHeight - this.contextMenu.scrollHeight) + 'px';
} else {
this.contextMenu.style.top = clientY + 'px';
}
-
+
//this.contextMenu.classList.add('active');
openBtnMenu(this.contextMenu);
-
+
/////this.log('contextmenu', e, bubble, msgID, side);
}
});
-
+
this.contextMenu.querySelector('.menu-copy').addEventListener('click', () => {
let message = appMessagesManager.getMessage(this.contextMenuMsgID);
-
+
let str = message ? message.message : '';
-
+
var textArea = document.createElement("textarea");
textArea.value = str;
textArea.style.position = "fixed"; //avoid scrolling to bottom
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
-
+
try {
document.execCommand('copy');
} catch (err) {
console.error('Oops, unable to copy', err);
}
-
+
document.body.removeChild(textArea);
});
-
+
this.contextMenu.querySelector('.menu-delete').addEventListener('click', () => {
if(this.peerID == this.myID) {
this.popupDeleteMessage.deleteBothBtn.style.display = 'none';
@@ -516,7 +652,7 @@ export class AppImManager {
} else {
this.popupDeleteMessage.deleteBothBtn.style.display = '';
this.popupDeleteMessage.deleteMeBtn.innerText = 'DELETE JUST FOR ME';
-
+
if(this.peerID > 0) {
let title = appPeersManager.getPeerTitle(this.peerID);
this.popupDeleteMessage.deleteBothBtn.innerHTML = 'DELETE FOR ME AND ' + title;
@@ -524,7 +660,7 @@ export class AppImManager {
this.popupDeleteMessage.deleteBothBtn.innerText = 'DELETE FOR ALL';
}
}
-
+
this.popupDeleteMessage.popupEl.classList.add('active');
});
@@ -534,14 +670,14 @@ export class AppImManager {
this.chatInputC.replyToMsgID = this.contextMenuMsgID;
this.chatInputC.editMsgID = 0;
});
-
+
this.contextMenuEdit.addEventListener('click', () => {
let message = appMessagesManager.getMessage(this.contextMenuMsgID);
this.chatInputC.setTopInfo('Editing', message.message, message.message, message.media);
this.chatInputC.replyToMsgID = 0;
this.chatInputC.editMsgID = this.contextMenuMsgID;
});
-
+
this.contextMenuPin.addEventListener('click', () => {
apiManager.invokeApi('messages.updatePinnedMessage', {
flags: 0,
@@ -552,12 +688,12 @@ export class AppImManager {
apiUpdatesManager.processUpdateMessage(updates);
});
});
-
+
this.popupDeleteMessage.deleteBothBtn.addEventListener('click', () => {
this.deleteMessages(true);
this.popupDeleteMessage.cancelBtn.click();
});
-
+
this.popupDeleteMessage.deleteMeBtn.addEventListener('click', () => {
this.deleteMessages(false);
this.popupDeleteMessage.cancelBtn.click();
@@ -565,32 +701,32 @@ export class AppImManager {
this.goDownBtn.addEventListener('click', () => {
let dialog = appMessagesManager.getDialogByPeerID(this.peerID)[0];
-
+
if(dialog) {
this.setPeer(this.peerID, dialog.top_message);
} else {
this.scroll.scrollTop = this.scroll.scrollHeight;
}
});
-
+
this.updateStatusInterval = window.setInterval(() => this.updateStatus(), 50e3);
this.updateStatus();
setInterval(() => this.setPeerStatus(), 60e3);
-
+
this.setScroll();
}
-
+
public deleteMessages(revoke = false) {
let flags = revoke ? 1 : 0;
let ids = [this.contextMenuMsgID];
-
+
apiManager.invokeApi('messages.deleteMessages', {
flags: flags,
revoke: revoke,
id: ids
}).then((affectedMessages: any) => {
/////this.log('deleted messages:', affectedMessages);
-
+
apiUpdatesManager.processUpdateMessage({
_: 'updateShort',
update: {
@@ -599,7 +735,7 @@ export class AppImManager {
pts_count: affectedMessages.pts_count
}
});
-
+
apiUpdatesManager.processUpdateMessage({
_: 'updateShort',
update: {
@@ -609,14 +745,14 @@ export class AppImManager {
});
});
}
-
+
public deleteEmptySideDivs() {
return;
-
+
let nodes = Array.from(this.chatInner.childNodes) as HTMLDivElement[];
nodes.filter((node) => {
let childElementCount = node.childElementCount;
-
+
if(!childElementCount) {
node.remove();
return false;
@@ -627,7 +763,7 @@ export class AppImManager {
return false;
}
}
-
+
return true;
}).forEach(node => {
let nextNode = node.nextElementSibling;
@@ -635,65 +771,33 @@ export class AppImManager {
(Array.from(node.childNodes) as HTMLDivElement[]).reverse().forEach(div => {
nextNode.prepend(div);
});
-
+
node.remove();
}
});
}
-
+
public loadMediaQueuePush(cb: () => Promise) {
this.loadMediaQueue.push(cb);
this.loadMediaQueueProcess();
}
-
- public async loadMediaQueueProcessOld(): Promise {
- if(this.loadMediaQueuePromise /* || 1 == 1 */) return this.loadMediaQueuePromise;
-
- let woo = this.loadMediaQueue.splice(-5, 5).reverse().map(f => f());
-
- if(woo.length) {
- ///this.log('Will load more media:', woo.length);
-
- woo.forEach(async(promise) => {
- try {
- await promise;
- } catch(err) {
- this.log.error('loadMediaQueue error:', err);
- }
-
- this.loadingMedia--;
- });
-
- try {
- this.loadMediaQueuePromise = Promise.all(woo);
- await this.loadMediaQueuePromise;
- } catch(err) {
- this.log.error('loadMediaQueue error:', err);
- }
- }
-
- this.loadMediaQueuePromise = null;
-
- if(this.loadMediaQueue.length) return this.loadMediaQueueProcess();
- return this.loadMediaQueuePromise;
- }
-
+
public async loadMediaQueueProcess(): Promise {
- if(this.loadingMedia >= 5) return;
-
+ if(this.loadingMedia >= 5/* || 1 == 1 */) return;
+
let item = this.loadMediaQueue.pop();
if(item) {
this.loadingMedia++;
-
+
let peerID = this.peerID;
-
+
let promise = item();
try {
await promise;
} catch(err) {
this.log.error('loadMediaQueue error:', err);
}
-
+
if(peerID == this.peerID) {
this.loadingMedia--;
}
@@ -701,155 +805,130 @@ export class AppImManager {
if(this.loadMediaQueue.length) return this.loadMediaQueueProcess();
}
-
+
public updateStatus() {
if(!this.myID) return Promise.resolve();
-
+
appUsersManager.setUserStatus(this.myID, this.offline);
return apiManager.invokeApi('account.updateStatus', {offline: this.offline});
}
+ public loadMoreHistory(top: boolean) {
+ // load more history
+ // возможно нужно добавить разные таймауты для верха и низа
+ if(!this.getHistoryPromise && !this.getHistoryTimeout && this.peerID && !testScroll) {
+ this.getHistoryTimeout = setTimeout(() => { // must be
+ let history = Object.keys(this.bubbles).map(id => +id).sort();
+
+ /* let history = appMessagesManager.historiesStorage[this.peerID].history;
+ let length = history.length; */
+
+ // filter negative ids
+ let lastBadIndex = -1;
+ for(let i = 0; i < history.length; ++i) {
+ if(history[i] <= 0) lastBadIndex = i;
+ else break;
+ }
+ if(lastBadIndex != -1) {
+ history = history.slice(lastBadIndex + 1);
+ }
+
+ this.getHistoryTimeout = 0;
+
+ if(!this.scrolledAll && top) {
+ this.log('Will load more (up) history by id:', history[0], 'maxID:', history[history.length - 1], history);
+ /* false && */!testScroll && this.getHistory(history[0], true).then(() => { // uncomment
+ this.onScroll();
+ }).catch(err => {
+ this.log.warn('Could not load more history, err:', err);
+ });
+ }
+
+ if(this.scrolledAllDown) return;
+
+ let dialog = appMessagesManager.getDialogByPeerID(this.peerID)[0];
+ /* if(!dialog) {
+ this.log.warn('no dialog for load history');
+ return;
+ } */
+
+ // if scroll down after search
+ if(!top && (!dialog || history.indexOf(dialog.top_message) === -1)) {
+ this.log('Will load more (down) history by maxID:', history[history.length - 1], history);
+ /* false && */!testScroll && this.getHistory(history[history.length - 1], false, true).then(() => { // uncomment
+ this.onScroll();
+ }).catch(err => {
+ this.log.warn('Could not load more history, err:', err);
+ });
+ }
+ }, 0);
+ }
+ }
+
public onScroll() {
let readed: number[] = [];
-
+
this.unreaded.forEachReverse((msgID, idx) => {
let bubble = this.bubbles[msgID];
-
+
if(isElementInViewport(bubble)) {
readed.push(msgID);
this.unreaded.splice(idx, 1);
}
});
-
+
lottieLoader.checkAnimations();
-
+
if(readed.length) {
let max = Math.max(...readed);
let min = Math.min(...readed);
-
+
if(this.peerID < 0) {
max = appMessagesIDsManager.getMessageIDInfo(max)[0];
min = appMessagesIDsManager.getMessageIDInfo(min)[0];
}
-
+
//appMessagesManager.readMessages(readed);
appMessagesManager.readHistory(this.peerID, max, min).catch((err: any) => {
this.log.error('readHistory err:', err);
appMessagesManager.readHistory(this.peerID, max, min);
});
}
-
+
if(this.scroll.scrollHeight - (this.scroll.scrollTop + this.scroll.offsetHeight) == 0/* <= 5 */) {
this.scroll.parentElement.classList.add('scrolled-down');
} else if(this.scroll.parentElement.classList.contains('scrolled-down')) {
this.scroll.parentElement.classList.remove('scrolled-down');
}
-
- // load more history
- if(!this.getHistoryPromise && !this.getHistoryTimeout && !testScroll) {
- this.getHistoryTimeout = setTimeout(() => { // must be
- let history = Object.keys(this.bubbles).map(id => +id).sort();
-
- /* let history = appMessagesManager.historiesStorage[this.peerID].history;
- let length = history.length; */
-
- // filter negative ids
- let lastBadIndex = -1;
- for(let i = 0; i < history.length; ++i) {
- if(history[i] <= 0) lastBadIndex = i;
- else break;
- }
- if(lastBadIndex != -1) {
- history = history.slice(lastBadIndex + 1);
- }
-
- this.getHistoryTimeout = 0;
-
- let willLoad = false;
- if(!this.scrolledAll) {
- let length = history.length < 10 ? history.length : 10;
- for(let i = 0; i < length; ++i) {
- let msgID = history[i];
-
- let bubble = this.bubbles[msgID];
-
- if(!bubble) {
- this.log.error('no bubble by msgID:', msgID);
- continue;
- }
-
- if(isElementInViewport(bubble)) {
- willLoad = true;
-
- ////this.log('Will load more (up) history by id:', history[0], 'maxID:', history[history.length - 1], history, bubble);
- /* false && */!testScroll && this.getHistory(history[0], true).then(() => { // uncomment
- this.onScroll();
- }).catch(err => {
- this.log.warn('Could not load more history, err:', err);
- });
-
- break;
- }
- }
- }
-
- if(this.scrolledAllDown) return;
-
- let dialog = appMessagesManager.getDialogByPeerID(this.peerID)[0];
- /* if(!dialog) {
- this.log.warn('no dialog for load history');
- return;
- } */
-
- // if scroll down after search
- if(!willLoad && (!dialog || history.indexOf(dialog.top_message) === -1)) {
- let lastMsgIDs = history.slice(-10);
- for(let msgID of lastMsgIDs) {
- let bubble = this.bubbles[msgID];
-
- if(isElementInViewport(bubble)) {
- willLoad = true;
-
- ////this.log('Will load more (down) history by maxID:', lastMsgIDs[lastMsgIDs.length - 1], lastMsgIDs, bubble);
- /* false && */!testScroll && this.getHistory(lastMsgIDs[lastMsgIDs.length - 1], false, true).then(() => { // uncomment
- this.onScroll();
- }).catch(err => {
- this.log.warn('Could not load more history, err:', err);
- });
-
- break;
- }
- }
- }
- }, 0);
- }
}
-
+
public setScroll() {
- this.scrollable = new Scrollable(this.bubblesContainer, false, true, 750, 'IM'/* 1500 */);
+ this.scrollable = new Scrollable(this.bubblesContainer, false, true, 750, 'IM', this.chatInner/* 1500 */, 300);
this.scroll = this.scrollable.container;
-
+
this.scrollable.setVirtualContainer(this.chatInner);
-
+ this.scrollable.onScrolledTop = () => this.loadMoreHistory(true);
+ this.scrollable.onScrolledBottom = () => this.loadMoreHistory(false);
+
this.scrollPosition = new ScrollPosition(this.chatInner);
this.scroll.addEventListener('scroll', this.onScroll.bind(this));
this.scroll.parentElement.classList.add('scrolled-down');
}
-
+
public setPeerStatus() {
if(!this.myID) return;
-
+
// set subtitle
this.subtitleEl.innerText = appSidebarRight.profileElements.subtitle.innerText = '';
this.subtitleEl.classList.remove('online');
appSidebarRight.profileElements.subtitle.classList.remove('online');
-
+
if(this.peerID < 0) { // not human
let chat = appPeersManager.getPeer(this.peerID);
let isChannel = appPeersManager.isChannel(this.peerID) && !appPeersManager.isMegagroup(this.peerID);
-
+
///////this.log('setPeerStatus', chat);
-
+
Promise.all([
appPeersManager.isMegagroup(this.peerID) ? apiManager.invokeApi('messages.getOnlines', {
peer: appPeersManager.getInputPeerByID(this.peerID)
@@ -858,65 +937,65 @@ export class AppImManager {
appProfileManager.getChatFull(chat.id)
]).then(results => {
let [chatOnlines, chatInfo] = results;
-
+
let onlines = chatOnlines ? chatOnlines.onlines : 1;
-
+
///////////this.log('chatInfo res:', chatInfo);
-
+
if(chatInfo.pinned_msg_id) { // request pinned message
this.pinnedMsgID = chatInfo.pinned_msg_id;
appMessagesManager.wrapSingleMessage(chatInfo.pinned_msg_id);
}
-
+
let participants_count = chatInfo.participants_count || chatInfo.participants.participants.length;
let subtitle = numberWithCommas(participants_count) + ' ' + (isChannel ? 'subscribers' : 'members');
-
+
if(onlines > 1) {
subtitle += ', ' + numberWithCommas(onlines) + ' online';
}
-
+
this.subtitleEl.innerText = appSidebarRight.profileElements.subtitle.innerText = subtitle;
});
} else if(!appUsersManager.isBot(this.peerID)) { // user
let user = appUsersManager.getUser(this.peerID);
-
+
//this.subtitleEl.classList.remove('online');
-
+
if(user && user.status && this.myID != this.peerID) {
let subtitle = '';
switch(user.status._) {
case 'userStatusRecently':
- subtitle += 'last seen recently';
- break;
+ subtitle += 'last seen recently';
+ break;
case 'userStatusOffline':
- subtitle = 'last seen ';
-
- let date = user.status.was_online;
- let now = Date.now() / 1000;
-
- if((now - date) < 60) {
- subtitle += ' just now';
- } else if((now - date) < 3600) {
- subtitle += ((now - date) / 60 | 0) + ' minutes ago';
- } else if(now - date < 86400) {
- subtitle += ((now - date) / 3600 | 0) + ' hours ago';
- } else {
- let d = new Date(date * 1000);
- subtitle += ('0' + d.getDate()).slice(-2) + '.' + ('0' + (d.getMonth() + 1)).slice(-2) + ' at ' +
- ('0' + d.getHours()).slice(-2) + ':' + ('0' + d.getMinutes()).slice(-2);
- }
-
- break;
+ subtitle = 'last seen ';
+
+ let date = user.status.was_online;
+ let now = Date.now() / 1000;
+
+ if((now - date) < 60) {
+ subtitle += ' just now';
+ } else if((now - date) < 3600) {
+ subtitle += ((now - date) / 60 | 0) + ' minutes ago';
+ } else if(now - date < 86400) {
+ subtitle += ((now - date) / 3600 | 0) + ' hours ago';
+ } else {
+ let d = new Date(date * 1000);
+ subtitle += ('0' + d.getDate()).slice(-2) + '.' + ('0' + (d.getMonth() + 1)).slice(-2) + ' at ' +
+ ('0' + d.getHours()).slice(-2) + ':' + ('0' + d.getMinutes()).slice(-2);
+ }
+
+ break;
case 'userStatusOnline':
- this.subtitleEl.classList.add('online');
- appSidebarRight.profileElements.subtitle.classList.add('online');
- subtitle = 'online';
- break;
+ this.subtitleEl.classList.add('online');
+ appSidebarRight.profileElements.subtitle.classList.add('online');
+ subtitle = 'online';
+ break;
}
-
+
appSidebarRight.profileElements.subtitle.innerText = subtitle;
-
+
if(this.typingUsers[this.peerID] == this.peerID) {
this.subtitleEl.innerText = 'typing...';
this.subtitleEl.classList.add('online');
@@ -924,39 +1003,40 @@ export class AppImManager {
}
}
}
-
+
public cleanup() {
this.peerID = $rootScope.selectedPeerID = 0;
this.scrolledAll = false;
this.scrolledAllDown = false;
this.muted = false;
-
+
for(let i in this.bubbles) {
let bubble = this.bubbles[i];
bubble.remove();
}
this.bubbles = {};
this.dateMessages = {};
+ this.bubbleGroups.cleanup();
this.unreaded = [];
this.unreadOut = [];
this.loadMediaQueue = [];
this.loadingMedia = 0;
this.needUpdate.length = 0;
-
+
lottieLoader.checkAnimations(false, 'chat', true);
-
+
// clear input
this.chatInputC.messageInput.innerHTML = '';
this.chatInputC.replyElements.cancelBtn.click();
-
+
// clear messages
this.chatInner.innerHTML = '';
-
+
this.scrollable.setVirtualContainer(this.chatInner);
-
+
//appSidebarRight.minMediaID = {};
}
-
+
public setPeer(peerID: number, lastMsgID = 0, forwarding = false) {
if(peerID == 0) {
appSidebarRight.toggleSidebar(false);
@@ -964,49 +1044,50 @@ export class AppImManager {
this.cleanup();
return Promise.resolve(false);
}
-
+
let samePeer = this.peerID == peerID;
-
+
if(this.setPeerPromise && samePeer) return this.setPeerPromise;
-
+
if(lastMsgID) {
appMessagesManager.readHistory(peerID, lastMsgID); // lol
}
-
+
if(samePeer) {
if(!testScroll && !lastMsgID) {
return Promise.resolve(true);
}
-
+
if(this.bubbles[lastMsgID]) {
let dialog = appMessagesManager.getDialogByPeerID(peerID)[0];
-
+
if(dialog && lastMsgID == dialog.top_message) {
this.scroll.scrollTop = this.scroll.scrollHeight;
} else {
- this.bubbles[lastMsgID].scrollIntoView();
+ //this.bubbles[lastMsgID].scrollIntoView();
+ this.scrollable.scrollIntoView(this.bubbles[lastMsgID]);
}
-
+
return Promise.resolve(true);
}
}
-
+
// clear
this.cleanup();
-
+
// set new
this.peerID = $rootScope.selectedPeerID = peerID;
-
+
// no dialog
/* if(!appMessagesManager.getDialogByPeerID(this.peerID).length) {
this.log.error('No dialog by peerID:', this.peerID);
return Promise.reject();
} */
-
+
this.pinnedMessageContainer.style.display = 'none';
-
+
this.preloader.attach(this.chatInner);
-
+
let dialog = appMessagesManager.getDialogByPeerID(this.peerID)[0] || null;
//////this.log('setPeer peerID:', this.peerID, dialog, lastMsgID);
appDialogsManager.loadDialogPhoto(this.avatarEl, this.peerID);
@@ -1014,9 +1095,9 @@ export class AppImManager {
if(!samePeer && appDialogsManager.lastActiveListElement) {
appDialogsManager.lastActiveListElement.classList.remove('active');
}
-
+
this.firstTopMsgID = dialog ? dialog.top_message : 0;
-
+
/* let dom = appDialogsManager.getDialogDom(this.peerID);
if(!dom) {
this.log.warn('No rendered dialog by peerID:', this.peerID);
@@ -1025,9 +1106,9 @@ export class AppImManager {
}
// warning need check
dom.listEl.classList.add('active'); */
-
+
this.setPeerStatus();
-
+
let title = '';
if(this.peerID == this.myID) {
title = 'Saved Messages';
@@ -1036,18 +1117,20 @@ export class AppImManager {
}
//this.titleEl.innerHTML = appSidebarRight.profileElements.name.innerHTML = dom.titleSpan.innerHTML;
this.titleEl.innerHTML = appSidebarRight.profileElements.name.innerHTML = title;
-
+
this.topbar.style.display = this.goDownBtn.style.display = '';
- //appSidebarRight.toggleSidebar(true);
-
+ appSidebarRight.toggleSidebar(true);
+
this.chatInput.style.display = appPeersManager.isChannel(peerID) && !appPeersManager.isMegagroup(peerID) ? 'none' : '';
-
+
if(appPeersManager.isAnyGroup(peerID)) {
this.chatInner.classList.add('is-chat');
} else {
this.chatInner.classList.remove('is-chat');
}
+ //this.scroll.scrollTop = this.scroll.scrollHeight;
+
return this.setPeerPromise = Promise.all([
this.getHistory(forwarding ? lastMsgID + 1 : lastMsgID).then(() => {
////this.log('setPeer removing preloader');
@@ -1058,7 +1141,7 @@ export class AppImManager {
//////this.log('setPeer render last message:', message, lastMsgID);
this.renderMessage(message);
}
-
+
if(!dialog || lastMsgID != dialog.top_message) {
let bubble = this.bubbles[lastMsgID];
@@ -1068,62 +1151,61 @@ export class AppImManager {
this.scroll.scrollTop = this.scroll.scrollHeight;
}
} else if(dialog && dialog.top_message) { // add last message, bc in getHistory will load < max_id
- this.renderMessage(appMessagesManager.getMessage(dialog.top_message));
+ this.renderMessage(appMessagesManager.getMessage(dialog.top_message), false, true);
+ //this.scroll.scrollTop = this.scroll.scrollHeight;
}
- if(this.scroll) {
- this.onScroll();
- }
+ this.onScroll();
+ this.scrollable.onScroll();
this.preloader.detach();
-
+
//setTimeout(() => {
- //appSidebarRight.fillProfileElements();
- appSidebarRight.loadSidebarMedia();
+ //appSidebarRight.fillProfileElements();
+ appSidebarRight.loadSidebarMedia(true);
//}, 500);
return true;
})/* .catch(err => {
this.log.error(err);
}) */,
-
+
appSidebarRight.fillProfileElements()
]).then(() => {
if(this.peerID == peerID) {
this.setPeerPromise = null;
}
-
+
return true;
}).catch(err => {
if(this.peerID == peerID) {
this.setPeerPromise = null;
}
-
+
this.log.error('setPeer promises error:', err);
return false;
});
}
-
+
public setTyping(action: any): Promise {
if(!this.peerID) return Promise.resolve(false);
-
+
if(typeof(action) == 'string') {
action = {_: action};
}
-
+
let input = appPeersManager.getInputPeerByID(this.peerID);
return apiManager.invokeApi('messages.setTyping', {
peer: input,
action: action
}) as Promise;
}
-
+
public updateUnreadByDialog(dialog: any) {
let maxID = this.peerID == this.myID ? dialog.read_inbox_max_id : dialog.read_outbox_max_id;
-
+
///////this.log('updateUnreadByDialog', maxID, dialog, this.unreadOut);
-
- let length = this.unreadOut.length;
+
this.unreadOut.forEachReverse((msgID, idx) => {
if(msgID > 0 && msgID <= maxID) {
let bubble = this.bubbles[msgID];
@@ -1133,72 +1215,68 @@ export class AppImManager {
}
});
}
-
+
public deleteMessagesByIDs(msgIDs: number[]) {
msgIDs.forEach(id => {
if(this.firstTopMsgID == id) {
let dialog = appMessagesManager.getDialogByPeerID(this.peerID)[0];
-
+
if(dialog) {
///////this.log('setting firstTopMsgID after delete:', id, dialog.top_message, dialog);
this.firstTopMsgID = dialog.top_message;
}
}
-
+
if(!(id in this.bubbles)) return;
let bubble = this.bubbles[id];
- let parent = bubble.parentNode as HTMLDivElement;
delete this.bubbles[id];
- bubble.remove();
-
- if(!parent.childNodes.length) {
- parent.remove();
- }
+ this.scrollable.removeElement(bubble);
+ //bubble.remove();
});
-
+
lottieLoader.checkAnimations();
}
-
+
public renderMessagesByIDs(msgIDs: number[]) {
if(!this.bubbles[this.firstTopMsgID] && Object.keys(this.bubbles).length) { // seems search active
//////this.log('seems search is active, skipping render:', msgIDs);
return;
}
-
+
msgIDs.forEach((msgID: number) => {
let message = appMessagesManager.getMessage(msgID);
-
+
/////////this.log('got new message to append:', message);
-
+
//this.unreaded.push(msgID);
this.renderMessage(message);
});
}
-
+
public renderMessage(message: any, reverse = false, multipleRender?: boolean, bubble: HTMLDivElement = null, updatePosition = true) {
/////this.log('message to render:', message);
if(message.deleted) return;
-
+
let peerID = this.peerID;
let our = message.fromID == this.myID;
-
+
let messageDiv = document.createElement('div');
messageDiv.classList.add('message');
-
+
//messageDiv.innerText = message.message;
-
+
if(!multipleRender) {
this.scrollPosition.prepareFor(reverse ? 'up' : 'down'); // лагает из-за этого
}
-
+
let bubbleContainer: HTMLDivElement;
-
+
// bubble
if(!bubble) {
bubbleContainer = document.createElement('div');
bubbleContainer.classList.add('bubble__container');
-
+
bubble = document.createElement('div');
bubble.classList.add('bubble');
bubble.appendChild(bubbleContainer);
@@ -1209,53 +1287,78 @@ export class AppImManager {
bubbleContainer.innerHTML = '';
//bubble.innerHTML = '';
}
-
+
+ if(message._ == 'messageService') {
+ bubble.className = 'bubble service';
+
+ let action = message.action;
+
+ let title = appPeersManager.getPeerTitle(message.fromID);
+ let name = document.createElement('div');
+ name.classList.add('name');
+ name.dataset.peerID = message.fromID;
+ name.innerHTML = title;
+
+ let _ = action._;
+ if(_ == "messageActionPhoneCall") {
+ _ += '.' + action.type;
+ }
+ // @ts-ignore
+ let str = (name.innerText ? name.outerHTML + ' ' : '') + langPack[_];
+ bubbleContainer.innerHTML = `${str}
`;
+
+ if(!multipleRender) {
+ this.scrollPosition.restore(); // лагает из-за этого
+ }
+
+ return;
+ }
+
// time section
-
+
let date = new Date(message.date * 1000);
- let time = ('0' + date.getHours()).slice(-2) +
- ':' + ('0' + date.getMinutes()).slice(-2);
-
+ let time = ('0' + date.getHours()).slice(-2) + ':' + ('0' + date.getMinutes()).slice(-2);
+
if(message.views) {
bubble.classList.add('channel-post');
time = formatNumber(message.views, 1) + ' ' + time;
}
-
+
if(message.edit_date) {
bubble.classList.add('is-edited');
time = 'edited ' + time;
}
-
+
let timeSpan = document.createElement('span');
timeSpan.classList.add('time');
-
+
let timeInner = document.createElement('div');
timeInner.classList.add('inner', 'tgico');
timeInner.innerHTML = time;
-
+
let richText = RichTextProcessor.wrapRichText(message.message, {
entities: message.totalEntities
});
-
+
if(message.totalEntities) {
let emojiEntities = message.totalEntities.filter((e: any) => e._ == 'messageEntityEmoji');
let strLength = message.message.length;
let emojiStrLength = emojiEntities.reduce((acc: number, curr: any) => acc + curr.length, 0);
-
+
if(emojiStrLength == strLength && emojiEntities.length <= 3) {
let attachmentDiv = document.createElement('div');
attachmentDiv.classList.add('attachment');
-
+
attachmentDiv.innerHTML = richText;
-
+
messageDiv.classList.add('message-empty');
bubble.classList.add('emoji-' + emojiEntities.length + 'x', 'emoji-big');
-
+
bubbleContainer.append(attachmentDiv);
} else {
messageDiv.innerHTML = richText;
}
-
+
/* if(strLength == emojiStrLength) {
messageDiv.classList.add('emoji-only');
messageDiv.classList.add('message-empty');
@@ -1263,14 +1366,14 @@ export class AppImManager {
} else {
messageDiv.innerHTML = richText;
}
-
+
//messageDiv.innerHTML = 'samsung samsung samsung';
-
+
timeSpan.appendChild(timeInner);
messageDiv.append(timeSpan);
bubbleContainer.prepend(messageDiv);
//bubble.prepend(timeSpan, messageDiv); // that's bad
-
+
if(our) {
if(message.pFlags.unread || message.mid < 0) this.unreadOut.push(message.mid); // message.mid < 0 added 11.02.2020
let status = '';
@@ -1281,164 +1384,164 @@ export class AppImManager {
//this.log('not our message', message, message.pFlags.unread);
if(message.pFlags.unread) this.unreaded.push(message.mid);
}
-
+
// media
if(message.media) {
let attachmentDiv = document.createElement('div');
attachmentDiv.classList.add('attachment');
-
+
if(!message.message) {
messageDiv.classList.add('message-empty');
}
-
+
let processingWebPage = false;
switch(message.media._) {
case 'messageMediaPending': {
let pending = message.media;
let preloader = pending.preloader as ProgressivePreloader;
-
+
switch(pending.type) {
case 'photo': {
if(pending.size < 5e6) {
let img = new Image();
img.src = URL.createObjectURL(pending.file);
-
+
let {w, h} = calcImageInBox(pending.w, pending.h, 380, 380);
-
+
attachmentDiv.style.width = w + 'px';
attachmentDiv.style.height = h + 'px';
-
+
attachmentDiv.append(img);
preloader.attach(attachmentDiv, false);
bubble.classList.add('hide-name', 'photo');
-
+
break;
}
}
-
+
case 'audio':
case 'document': {
let docDiv = wrapDocument(pending, false, true);
-
+
let icoDiv = docDiv.querySelector('.document-ico');
preloader.attach(icoDiv, false);
-
+
messageDiv.classList.remove('message-empty');
messageDiv.append(docDiv);
processingWebPage = true;
break;
}
-
+
}
-
+
break;
}
-
+
case 'messageMediaPhoto': {
let photo = message.media.photo;
////////this.log('messageMediaPhoto', photo);
-
+
bubble.classList.add('hide-name', 'photo');
-
+
wrapPhoto.call(this, photo, message, attachmentDiv);
break;
}
-
+
case 'messageMediaWebPage': {
processingWebPage = true;
-
+
let webpage = message.media.webpage;
////////this.log('messageMediaWebPage', webpage);
if(webpage._ == 'webPageEmpty') {
break;
}
-
+
bubble.classList.add('webpage');
-
+
let box = document.createElement('div');
box.classList.add('box', 'web');
-
+
let quote = document.createElement('div');
quote.classList.add('quote');
-
+
let nameEl = document.createElement('a');
nameEl.classList.add('name');
-
+
let titleDiv = document.createElement('div');
titleDiv.classList.add('title');
-
+
let textDiv = document.createElement('div');
textDiv.classList.add('text');
-
+
let preview: HTMLDivElement = null;
if(webpage.photo || webpage.document) {
preview = document.createElement('div');
preview.classList.add('preview');
}
-
+
let doc: any = null;
if(webpage.document) {
doc = webpage.document;
-
+
if(doc.type == 'gif' || doc.type == 'video') {
//if(doc.size <= 20e6) {
- bubble.classList.add('video');
- wrapVideo.call(this, doc, preview, message);
+ bubble.classList.add('video');
+ wrapVideo.call(this, doc, preview, message);
//}
} else {
doc = null;
}
}
-
+
if(webpage.photo && !doc) {
bubble.classList.add('photo');
//appPhotosManager.savePhoto(webpage.photo); // hot-fix because no webpage manager
-
+
wrapPhoto.call(this, webpage.photo, message, preview);
}
-
+
if(preview) {
quote.append(preview);
}
-
+
nameEl.setAttribute('target', '_blank');
nameEl.href = webpage.url || '#';
nameEl.innerHTML = webpage.site_name ? RichTextProcessor.wrapEmojiText(webpage.site_name) : '';
-
+
if(webpage.description) {
textDiv.innerHTML = RichTextProcessor.wrapRichText(webpage.description);
}
-
+
if(webpage.title) {
titleDiv.innerHTML = RichTextProcessor.wrapRichText(webpage.title);
}
-
+
quote.append(nameEl, titleDiv, textDiv);
box.append(quote);
-
+
//bubble.prepend(box);
bubbleContainer.prepend(timeSpan, box);
-
+
//this.log('night running', bubble.scrollHeight);
-
+
break;
}
-
+
case 'messageMediaDocument': {
let doc = message.media.document;
/* if(document.size > 1e6) { // 1mb
break;
} */
-
+
////////this.log('messageMediaDocument', doc);
-
+
if(doc.sticker && doc.size <= 1e6) {
bubble.classList.add('sticker');
-
+
if(doc.animated) {
bubble.classList.add('sticker-animated');
}
-
+
appPhotosManager.setAttachmentSize(doc, attachmentDiv, undefined, undefined, true);
let preloader = new ProgressivePreloader(attachmentDiv, false);
bubbleContainer.style.height = attachmentDiv.style.height;
@@ -1449,55 +1552,65 @@ export class AppImManager {
this.log.warn('peer changed, canceling sticker attach');
return false;
}
-
+
return true;
}, null, 'chat', false, !!message.pending || !multipleRender).then(() => {
preloader.detach();
/* attachmentDiv.style.width = '';
attachmentDiv.style.height = ''; */
});
-
+
this.loadMediaQueuePush(load);
-
+
break;
} else if(doc.mime_type == 'video/mp4' && doc.size <= 20e6) {
- ////////this.log('never get free 2', doc);
-
+ this.log('never get free 2', doc);
+
if(doc.type == 'round') {
bubble.classList.add('round');
}
-
+
bubble.classList.add('video');
wrapVideo.call(this, doc, attachmentDiv, message, true, null, false, doc.type == 'round');
-
+
+ break;
+ } else if(doc.mime_type == 'audio/ogg') {
+ let docDiv = wrapDocument(doc);
+
+ messageDiv.classList.remove('message-empty');
+
+ bubble.classList.add('bubble-audio');
+ messageDiv.append(docDiv);
+ processingWebPage = true;
+
break;
} else {
let docDiv = wrapDocument(doc);
-
+
messageDiv.classList.remove('message-empty');
messageDiv.append(docDiv);
processingWebPage = true;
-
+
break;
}
}
-
+
default:
- messageDiv.classList.remove('message-empty');
- messageDiv.innerHTML = 'unrecognized media type: ' + message.media._;
- messageDiv.append(timeSpan);
- this.log.warn('unrecognized media type:', message.media._, message);
- break;
+ messageDiv.classList.remove('message-empty');
+ messageDiv.innerHTML = 'unrecognized media type: ' + message.media._;
+ messageDiv.append(timeSpan);
+ this.log.warn('unrecognized media type:', message.media._, message);
+ break;
}
-
+
if(!processingWebPage) {
bubbleContainer.append(attachmentDiv);
}
}
-
+
if((this.peerID < 0 && !our) || message.fwd_from || message.reply_to_mid) { // chat
let title = appPeersManager.getPeerTitle(message.fwdFromID || message.fromID);
-
+
let isHidden = message.fwd_from && !message.fwd_from.from_id && !message.fwd_from.channel_id;
if(isHidden) {
///////this.log('message to render hidden', message);
@@ -1506,24 +1619,19 @@ export class AppImManager {
}
//this.log(title);
-
+
if(message.fwdFromID || message.fwd_from) {
bubble.classList.add('forwarded');
-
+
if(message.savedFrom) {
let fwd = document.createElement('div');
fwd.classList.add('forward'/* , 'tgico-forward' */);
- fwd.innerHTML = `
- `;
+ fwd.innerHTML = ``;
bubbleContainer.append(fwd);
bubble.dataset.savedFrom = message.savedFrom;
}
-
+
if(!bubble.classList.contains('sticker')) {
let nameDiv = document.createElement('div');
nameDiv.classList.add('name');
@@ -1536,28 +1644,28 @@ export class AppImManager {
if(message.reply_to_mid) {
let originalMessage = appMessagesManager.getMessage(message.reply_to_mid);
let originalPeerTitle = appPeersManager.getPeerTitle(originalMessage.fromID, true) || '';
-
+
/////////this.log('message to render reply', originalMessage, originalPeerTitle, bubble, message);
-
+
// need to download separately
if(originalMessage._ == 'messageEmpty') {
//////////this.log('message to render reply empty, need download', message, message.reply_to_mid);
appMessagesManager.wrapSingleMessage(message.reply_to_mid);
this.needUpdate.push({replyMid: message.reply_to_mid, mid: message.mid});
-
+
originalPeerTitle = 'Loading...';
}
-
+
if(originalMessage.mid) {
bubble.setAttribute('data-original-mid', originalMessage.mid);
} else {
bubble.setAttribute('data-original-mid', message.reply_to_mid);
}
-
+
bubbleContainer.append(wrapReply(originalPeerTitle, originalMessage.message || '', originalMessage.media));
bubble.classList.add('is-reply');
}
-
+
if(!bubble.classList.contains('sticker') && (peerID < 0 && peerID != message.fromID)) {
let nameDiv = document.createElement('div');
nameDiv.classList.add('name');
@@ -1568,57 +1676,29 @@ export class AppImManager {
} else /* if(!message.reply_to_mid) */ {
bubble.classList.add('hide-name');
}
-
- //bubble.prepend(avatarDiv);
- /* if(messageDiv.nextElementSibling) {
- bubble.insertBefore(avatarDiv, messageDiv.nextElementSibling);
- } else { */
-
- //}
}
-
- if(!our && this.peerID < 0 &&
- (!appPeersManager.isChannel(this.peerID) || appPeersManager.isMegagroup(this.peerID))) {
+
+ if(!our && this.peerID < 0 && (!appPeersManager.isChannel(this.peerID) || appPeersManager.isMegagroup(this.peerID))) {
let avatarDiv = document.createElement('div');
avatarDiv.classList.add('user-avatar');
-
+
/////////this.log('exec loadDialogPhoto', message);
if(message.fromID) { // if no - user hidden
appDialogsManager.loadDialogPhoto(avatarDiv, message.fromID);
} else if(!title && message.fwd_from && message.fwd_from.from_name) {
title = message.fwd_from.from_name;
-
+
appDialogsManager.loadDialogPhoto(avatarDiv, title);
}
-
+
avatarDiv.dataset.peerID = message.fromID;
-
+
bubbleContainer.append(avatarDiv);
}
} else {
bubble.classList.add('hide-name');
}
-
- if(message._ == 'messageService') {
- bubble.className = 'bubble service';
-
- let action = message.action;
-
- let title = appPeersManager.getPeerTitle(message.fromID);
- let name = document.createElement('div');
- name.classList.add('name');
- name.dataset.peerID = message.fromID;
- name.innerHTML = title;
-
- let _ = action._;
- if(_ == "messageActionPhoneCall") {
- _ += '.' + action.type;
- }
- // @ts-ignore
- let str = (name.innerText ? name.outerHTML + ' ' : '') + langPack[_];
- bubbleContainer.innerHTML = `${str}
`;
- }
-
+
bubble.classList.add(our ? 'is-out' : 'is-in');
if(updatePosition) {
if(reverse) {
@@ -1627,26 +1707,27 @@ export class AppImManager {
this.scrollable.append(bubble);
}
+ this.bubbleGroups.addBubble(bubble, message, reverse);
+
let justDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
let dateTimestamp = justDate.getTime();
if(!(dateTimestamp in this.dateMessages)) {
let str = '';
-
+
let today = new Date();
today.setHours(0);
today.setMinutes(0);
today.setSeconds(0);
-
+
if(today < date) {
str = 'Today';
} else {
- const months = ['January', 'February', 'March', 'April', 'May', 'June',
- 'July', 'August', 'September', 'October', 'November', 'December'];
+ const months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
str = justDate.getFullYear() == new Date().getFullYear() ?
- months[justDate.getMonth()] + ' ' + justDate.getDate() :
- justDate.toISOString().split('T')[0].split('-').reverse().join('.');
+ months[justDate.getMonth()] + ' ' + justDate.getDate() :
+ justDate.toISOString().split('T')[0].split('-').reverse().join('.');
}
-
+
let div = document.createElement('div');
div.className = 'bubble service';
div.innerHTML = `${str}
`;
@@ -1656,7 +1737,7 @@ export class AppImManager {
div,
firstTimestamp: date.getTime()
};
-
+
this.scrollable.insertBefore(div, bubble);
} else {
let dateMessage = this.dateMessages[dateTimestamp];
@@ -1664,67 +1745,65 @@ export class AppImManager {
this.scrollable.insertBefore(dateMessage.div, bubble);
}
}
+ } else {
+ this.bubbleGroups.updateGroupByMessageID(message.mid);
}
-
+
/* if(bubble.classList.contains('webpage')) {
this.log('night running', bubble, bubble.scrollHeight);
} */
-
+
//return //this.scrollPosition.restore();
-
+
if(!multipleRender) {
this.scrollPosition.restore(); // лагает из-за этого
}
-
- //this.log('history msg', message);
}
-
+
// reverse means scroll up
public getHistory(maxID = 0, reverse = false, isBackLimit = false) {
let peerID = this.peerID;
-
+
let dialog = appMessagesManager.getDialogByPeerID(peerID)[0];
if(!maxID && dialog && dialog.top_message) {
maxID = dialog.top_message/* + 1 */;
}
-
- let loadCount = Object.keys(this.bubbles).length > 0 ?
- 20 :
- this.scrollable.container.parentElement.scrollHeight / 30 * 1.25 | 0;
-
+
+ let loadCount = Object.keys(this.bubbles).length > 0 ? 20 : this.scrollable.container.parentElement.scrollHeight / 30 * 1.25 | 0;
+
/* if(testScroll) {
loadCount = 1;
if(Object.keys(this.bubbles).length > 0)
return Promise.resolve(true);
} */
-
+
//console.time('render getHistory');
//console.time('render history total');
-
+
let backLimit = 0;
if(isBackLimit) {
backLimit = loadCount;
loadCount = 0;
maxID += 1;
}
-
+
return this.getHistoryPromise = appMessagesManager.getHistory(this.peerID, maxID, loadCount, backLimit)
.then((result: any) => {
this.log('getHistory result by maxID:', maxID, reverse, isBackLimit, result);
-
+
//console.timeEnd('render getHistory');
-
+
if(this.peerID != peerID) {
this.log.warn('peer changed');
//console.timeEnd('render history total');
return Promise.reject();
}
-
+
if(!result || !result.history) {
//console.timeEnd('render history total');
return true;
}
-
+
// commented bot getProfile in getHistory!
if(!result.history/* .filter((id: number) => id > 0) */.length) {
if(!isBackLimit) {
@@ -1733,45 +1812,45 @@ export class AppImManager {
this.scrolledAllDown = true;
}
}
-
+
//this.chatInner.innerHTML = '';
-
+
let history = result.history.slice();
if(reverse) history.reverse();
-
+
//console.time('render history');
-
+
if(!isBackLimit) {
this.scrollPosition.prepareFor(reverse ? 'up' : 'down');
}
-
+
/* for(let i = 0; i < 25; ++i) */ history.forEachReverse((msgID: number) => {
let message = appMessagesManager.getMessage(msgID);
-
+
this.renderMessage(message, reverse, true);
});
-
+
if(!isBackLimit) {
this.scrollPosition.restore();
}
-
+
//console.timeEnd('render history');
-
+
this.getHistoryPromise = undefined;
-
+
//console.timeEnd('render history total');
-
+
return true;
});
}
-
+
public setMutedState(muted = false) {
appSidebarRight.profileElements.notificationsCheckbox.checked = !muted;
appSidebarRight.profileElements.notificationsStatus.innerText = muted ? 'Disabled' : 'Enabled';
-
+
let peerID = this.peerID;
-
+
this.muted = muted;
if(peerID < 0) { // not human
let isChannel = appPeersManager.isChannel(peerID) && !appPeersManager.isMegagroup(peerID);
@@ -1785,47 +1864,47 @@ export class AppImManager {
} else {
this.btnMute.style.display = 'none';
}
-
+
this.btnMenuMute.classList.remove('tgico-mute', 'tgico-unmute');
this.btnMenuMute.classList.add(muted ? 'tgico-unmute' : 'tgico-mute');
let rp = this.btnMenuMute.firstElementChild;
this.btnMenuMute.innerText = muted ? 'Unmute' : 'Mute';
this.btnMenuMute.appendChild(rp);
}
-
+
public mutePeer() {
let inputPeer = appPeersManager.getInputPeerByID(this.peerID);
let inputNotifyPeer = {
_: 'inputNotifyPeer',
peer: inputPeer
};
-
- let settings: any = {
+
+ let settings = {
_: 'inputPeerNotifySettings',
flags: 0,
mute_until: 0
};
-
+
if(!this.muted) {
settings.flags |= 1 << 2;
settings.mute_until = 2147483646;
} else {
settings.flags |= 2;
}
-
+
apiManager.invokeApi('account.updateNotifySettings', {
peer: inputNotifyPeer,
settings: settings
}).then(res => {
this.handleUpdate({_: 'updateNotifySettings', peer: inputNotifyPeer, notify_settings: settings});
});
-
+
/* return apiManager.invokeApi('account.getNotifySettings', {
peer: inputNotifyPeer
}).then((settings: any) => {
settings.flags |= 2 << 1;
settings.mute_until = 2000000000; // 2147483646
-
+
return apiManager.invokeApi('account.updateNotifySettings', {
peer: inputNotifyPeer,
settings: Object.assign(settings, {
@@ -1837,90 +1916,88 @@ export class AppImManager {
}); */
}
-
+
public handleUpdate(update: any) {
switch(update._) {
case 'updateUserTyping':
case 'updateChatUserTyping':
- if(this.myID == update.user_id) {
- return;
+ if(this.myID == update.user_id) {
+ return;
+ }
+
+ var peerID = update._ == 'updateUserTyping' ? update.user_id : -update.chat_id;
+ this.typingUsers[update.user_id] = peerID;
+
+ if(!appUsersManager.hasUser(update.user_id)) {
+ if(update.chat_id && appChatsManager.hasChat(update.chat_id) && !appChatsManager.isChannel(update.chat_id)) {
+ appProfileManager.getChatFull(update.chat_id);
}
-
- var peerID = update._ == 'updateUserTyping' ? update.user_id : -update.chat_id;
- this.typingUsers[update.user_id] = peerID;
-
- if(!appUsersManager.hasUser(update.user_id)) {
- if(update.chat_id &&
- appChatsManager.hasChat(update.chat_id) &&
- !appChatsManager.isChannel(update.chat_id)) {
- appProfileManager.getChatFull(update.chat_id);
- }
-
- //return;
+
+ //return;
+ }
+
+ appUsersManager.forceUserOnline(update.user_id);
+
+ let dialog = appMessagesManager.getDialogByPeerID(peerID)[0];
+ let currentPeer = this.peerID == peerID;
+
+ if(this.typingTimeouts[peerID]) clearTimeout(this.typingTimeouts[peerID]);
+ else if(dialog) {
+ appDialogsManager.setTyping(dialog, appUsersManager.getUser(update.user_id));
+
+ if(currentPeer) { // user
+ this.setPeerStatus();
}
-
- appUsersManager.forceUserOnline(update.user_id);
-
- let dialog = appMessagesManager.getDialogByPeerID(peerID)[0];
- let currentPeer = this.peerID == peerID;
-
- if(this.typingTimeouts[peerID]) clearTimeout(this.typingTimeouts[peerID]);
- else if(dialog) {
- appDialogsManager.setTyping(dialog, appUsersManager.getUser(update.user_id));
-
- if(currentPeer) { // user
- this.setPeerStatus();
- }
+ }
+
+ this.typingTimeouts[peerID] = setTimeout(() => {
+ this.typingTimeouts[peerID] = 0;
+ delete this.typingUsers[update.user_id];
+
+ if(dialog) {
+ appDialogsManager.unsetTyping(dialog);
}
-
- this.typingTimeouts[peerID] = setTimeout(() => {
- this.typingTimeouts[peerID] = 0;
- delete this.typingUsers[update.user_id];
-
- if(dialog) {
- appDialogsManager.unsetTyping(dialog);
- }
-
- // лень просчитывать случаи
- this.setPeerStatus();
- }, 6000);
- break;
-
+
+ // лень просчитывать случаи
+ this.setPeerStatus();
+ }, 6000);
+ break;
+
case 'updateNotifySettings': {
let {peer, notify_settings} = update;
-
+
// peer was NotifyPeer
peer = peer.peer;
-
+
let peerID = appPeersManager.getPeerID(peer);
-
+
let dialog = appMessagesManager.getDialogByPeerID(peerID)[0];
if(dialog) {
dialog.notify_settings = notify_settings;
}
-
+
if(peerID == this.peerID) {
let muted = notify_settings.mute_until ? new Date(notify_settings.mute_until * 1000) > new Date() : false;
this.setMutedState(muted);
}
-
+
/////this.log('updateNotifySettings', peerID, notify_settings);
break;
}
-
+
case 'updateChatPinnedMessage':
case 'updateUserPinnedMessage': {
let {id} = update;
-
+
/////this.log('updateUserPinnedMessage', update);
-
+
this.pinnedMsgID = id;
// hz nado li tut appMessagesIDsManager.getFullMessageID(update.max_id, channelID);
let peerID = update.user_id || -update.chat_id || -update.channel_id;
if(peerID == this.peerID) {
appMessagesManager.wrapSingleMessage(id);
}
-
+
break;
}
}
diff --git a/src/lib/appManagers/appSidebarLeft.ts b/src/lib/appManagers/appSidebarLeft.ts
index 8b825a1e..4910a646 100644
--- a/src/lib/appManagers/appSidebarLeft.ts
+++ b/src/lib/appManagers/appSidebarLeft.ts
@@ -87,9 +87,7 @@ class AppSidebarLeft {
};
constructor() {
- this.chatsPreloader = document.createElement('div');
- this.chatsPreloader.classList.add('preloader');
- putPreloader(this.chatsPreloader);
+ this.chatsPreloader = putPreloader(null, true);
//this.chatsContainer.append(this.chatsPreloader);
//this.chatsLoadCount = Math.round(document.body.scrollHeight / 70 * 1.5);
@@ -98,7 +96,6 @@ class AppSidebarLeft {
this.scroll.setVirtualContainer(appDialogsManager.chatList);
this.scroll.onScrolledBottom = this.onChatsScroll.bind(this);
appDialogsManager.chatsHidden = this.scroll.hiddenElements;
- //this.scroll.container.addEventListener('scroll', this.onChatsScroll.bind(this));
this.scrollArchived = new Scrollable(this.chatsArchivedContainer as HTMLDivElement, false, true, 300, 'CLA');
this.scrollArchived.setVirtualContainer(appDialogsManager.chatListArchived);
@@ -134,7 +131,7 @@ class AppSidebarLeft {
for(let i = 0; i < 1000; ++i) {
let li = document.createElement('li');
li.dataset.id = '' + i;
- li.innerHTML = `${i}18:33
Ильяс: Гагагагга
`;
+ li.innerHTML = ``;
this.scroll.append(li);
}
}
diff --git a/src/lib/appManagers/appSidebarRight.ts b/src/lib/appManagers/appSidebarRight.ts
index f0130343..79c85023 100644
--- a/src/lib/appManagers/appSidebarRight.ts
+++ b/src/lib/appManagers/appSidebarRight.ts
@@ -1,6 +1,6 @@
-import { horizontalMenu, formatPhoneNumber } from "../../components/misc";
+import { horizontalMenu, formatPhoneNumber, putPreloader } from "../../components/misc";
import Scrollable from '../../components/scrollable';
-import { isElementInViewport, $rootScope } from "../utils";
+import { $rootScope } from "../utils";
import appMessagesManager from "./appMessagesManager";
import appPhotosManager from "./appPhotosManager";
import appPeersManager from "./appPeersManager";
@@ -38,13 +38,13 @@ class AppSidebarRight {
contentLinks: this.profileContentEl.querySelector('#content-links') as HTMLDivElement,
contentAudio: this.profileContentEl.querySelector('#content-audio') as HTMLDivElement,
};
-
+
public lastSharedMediaDiv: HTMLDivElement = null;
-
+
private loadSidebarMediaPromises: {
[type: string]: Promise
} = {};
-
+
public sharedMediaTypes = [
'inputMessagesFilterContacts',
'inputMessagesFilterPhotoVideo',
@@ -54,7 +54,7 @@ class AppSidebarRight {
];
public sharedMediaType: string = '';
private sharedMediaSelected: HTMLDivElement = null;
-
+
private lazyLoadQueueSidebar = new LazyLoadQueue(5);
/* public minMediaID: {
[type: string]: number
@@ -62,17 +62,17 @@ class AppSidebarRight {
public cleared: {
[type: string]: boolean
} = {};
-
+
public historiesStorage: {
[peerID: number]: {
[type: string]: number[]
}
} = {};
-
+
private log = logger('SR');
-
+
private peerID = 0;
-
+
public sidebarScroll: Scrollable = null;
private savedVirtualStates: {
[id: number]: {
@@ -80,25 +80,37 @@ class AppSidebarRight {
paddings: any
}
} = {};
-
+
private profileTabs: HTMLUListElement;
private prevTabID = -1;
-
+
private mediaDivsByIDs: {
[mid: number]: HTMLDivElement
} = {};
-
+
constructor() {
let container = this.profileContentEl.querySelector('.profile-tabs-content') as HTMLDivElement;
this.profileTabs = this.profileContentEl.querySelector('.profile-tabs') as HTMLUListElement;
-
+
this.sidebarScroll = new Scrollable(this.sidebarEl, false, true, 500, 'SR');
this.sidebarScroll.container.addEventListener('scroll', this.onSidebarScroll.bind(this));
-
+ this.sidebarScroll.onScrolledBottom = () => {
+ if(this.sharedMediaSelected && !this.sidebarScroll.hiddenElements.down.length
+ && this.sharedMediaSelected.childElementCount/* && false */) {
+ this.loadSidebarMedia(true);
+ }
+ };
+
horizontalMenu(this.profileTabs, container, (id, tabContent) => {
+ if(this.prevTabID == id) return;
+
this.sharedMediaType = this.sharedMediaTypes[id];
this.sharedMediaSelected = tabContent.firstElementChild as HTMLDivElement;
+ if(this.prevTabID != -1 && !this.sharedMediaSelected.childElementCount) { // quick brown fix
+ this.loadSidebarMedia(true);
+ }
+
if(this.prevTabID != -1) {
this.savedVirtualStates[this.prevTabID] = {
hiddenElements: {
@@ -111,254 +123,248 @@ class AppSidebarRight {
}
};
}
-
+
this.prevTabID = id;
-
- //this.log('setVirtualContainer', id, this.sharedMediaSelected);
+
+ this.log('setVirtualContainer', id, this.sharedMediaSelected);
this.sidebarScroll.setVirtualContainer(this.sharedMediaSelected);
-
+
if(this.savedVirtualStates[id]) {
this.log(this.savedVirtualStates[id]);
this.sidebarScroll.hiddenElements = this.savedVirtualStates[id].hiddenElements;
this.sidebarScroll.paddings = this.savedVirtualStates[id].paddings;
}
}, this.onSidebarScroll.bind(this));
-
- //(this.profileTabs.children[1] as HTMLLIElement).click(); // set media
-
+
let sidebarCloseBtn = this.sidebarEl.querySelector('.sidebar-close-button') as HTMLButtonElement;
sidebarCloseBtn.addEventListener('click', () => {
this.toggleSidebar(false);
});
-
+
this.sharedMedia.contentMedia.addEventListener('click', (e) => {
let target = e.target as HTMLDivElement;
-
+
let messageID = +target.getAttribute('message-id');
if(!messageID) {
this.log.warn('no messageID by click on target:', target);
return;
}
-
+
let message = appMessagesManager.getMessage(messageID);
-
+
let ids = Object.keys(this.mediaDivsByIDs).map(k => +k).sort();
let idx = ids.findIndex(i => i == messageID);
-
+
let prev = ids[idx + 1] || null;
let next = ids[idx - 1] || null;
-
+
appMediaViewer.openMedia(message, target, this.mediaDivsByIDs[prev] || null, this.mediaDivsByIDs[next] || null);
});
-
+
this.profileElements.notificationsCheckbox.addEventListener('change', () => {
- let checked = this.profileElements.notificationsCheckbox.checked;
+ //let checked = this.profileElements.notificationsCheckbox.checked;
appImManager.mutePeer();
});
-
+
window.addEventListener('resize', () => {
setTimeout(() => {
this.sidebarScroll.onScroll();
this.onSidebarScroll();
}, 0);
});
-
+
if(testScroll) {
let div = document.createElement('div');
for(let i = 0; i < 500; ++i) {
//div.insertAdjacentHTML('beforeend', ``);
div.insertAdjacentHTML('beforeend', `${i / 3 | 0}
`);
-
+
if((i + 1) % 3 == 0) {
this.sharedMedia.contentMedia.append(div);
div = document.createElement('div');
}
-
+
div.dataset.id = '' + (i / 3 | 0);
}
this.sharedMedia.contentMedia.append(div);
(this.profileTabs.children[1] as HTMLLIElement).click(); // set media
}
}
-
+
public onSidebarScroll() {
this.lazyLoadQueueSidebar.check();
-
- if(this.sharedMediaSelected && !this.sidebarScroll.hiddenElements.down.length/* && false */) {
- let media = Array.from(this.sharedMediaSelected.childNodes).slice(-15);
- for(let div of media) {
- if(isElementInViewport(div)) {
- //this.log('Will load more media');
- this.loadSidebarMedia(true);
-
- break;
- }
- }
- }
}
-
+
public toggleSidebar(enable?: boolean) {
/////this.log('sidebarEl', this.sidebarEl, enable, isElementInViewport(this.sidebarEl));
-
- /* if(enable !== undefined) {
- this.sidebarEl.style.display = enable ? 'block' : 'none';
- return;
- }
-
- this.sidebarEl.style.display = isElementInViewport(this.sidebarEl) ? 'none' : 'block'; */
+
if(enable !== undefined) {
- this.sidebarEl.style.width = enable ? '25%' : '0%';
+ if(enable) this.sidebarEl.classList.add('active');
+ else this.sidebarEl.classList.remove('active');
return;
}
-
- this.sidebarEl.style.width = isElementInViewport(this.sidebarEl) ? '0%' : '25%';
+
+ if(this.sidebarEl.classList.contains('active')) {
+ this.sidebarEl.classList.remove('active');
+ } else {
+ this.sidebarEl.classList.add('active');
+ }
}
-
+
public loadSidebarMedia(single = false) {
- if(testScroll) {
+ if(testScroll /* || 1 == 1 */) {
return;
}
+ //this.log('loadSidebarMedia', single, this.peerID);
+
let peerID = this.peerID;
let typesToLoad = single ? [this.sharedMediaType] : this.sharedMediaTypes;
-
+
if(!this.historiesStorage[peerID]) this.historiesStorage[peerID] = {};
let historyStorage = this.historiesStorage[peerID];
-
+
let promises = typesToLoad.map(type => {
if(this.loadSidebarMediaPromises[type]) return this.loadSidebarMediaPromises[type];
-
+
if(!historyStorage[type]) historyStorage[type] = [];
let history = historyStorage[type];
-
+
// заливать новую картинку сюда только после полной отправки!
//let maxID = this.minMediaID[type] || 0;
let maxID = history[history.length - 1] || 0;
-
+
let ids = !maxID && appMessagesManager.historiesStorage[peerID]
- ? appMessagesManager.historiesStorage[peerID].history.slice() : [];
-
+ ? appMessagesManager.historiesStorage[peerID].history.slice() : [];
+
maxID = !maxID && ids.length ? ids[ids.length - 1] : maxID;
//this.log('search house of glass pre', type, ids, maxID);
-
- return this.loadSidebarMediaPromises[type] = appMessagesManager.getSearch(peerID, '', {_: type}, maxID, 50)
+
+ return this.loadSidebarMediaPromises[type] = appMessagesManager.getSearch(peerID, '', {_: type}, maxID, history.length ? 50 : 15)
.then(value => {
ids = ids.concat(value.history);
history.push(...ids);
-
+
//this.log('search house of glass', type, value, ids, this.cleared);
-
+
if($rootScope.selectedPeerID != peerID) {
this.log.warn('peer changed');
return;
}
-
+
if(this.cleared[type]) {
ids = history;
delete this.cleared[type];
}
-
- ids.forEach(mid => {
- //this.minMediaID[type] = mid;
+
+ let sharedMediaDiv: HTMLDivElement;
+ let messages: any[] = [];
+ for(let mid of ids) {
let message = appMessagesManager.getMessage(mid);
- if(!message.media) return;
-
- /*'inputMessagesFilterContacts',
- 'inputMessagesFilterPhotoVideo',
- 'inputMessagesFilterDocument',
- 'inputMessagesFilterUrl',
- 'inputMessagesFilterVoice'*/
- switch(type) {
- case 'inputMessagesFilterPhotoVideo': {
- /* if(!(message.media.photo || message.media.document || message.media.webpage.document)) {
- this.log.error('no media!', message);
- break;
- } */
-
+ if(message.media) messages.push(message);
+ }
+
+ /*'inputMessagesFilterContacts',
+ 'inputMessagesFilterPhotoVideo',
+ 'inputMessagesFilterDocument',
+ 'inputMessagesFilterUrl',
+ 'inputMessagesFilterVoice'*/
+ switch(type) {
+ case 'inputMessagesFilterPhotoVideo': {
+ sharedMediaDiv = this.sharedMedia.contentMedia;
+
+ for(let message of messages) {
let media = message.media.photo || message.media.document || (message.media.webpage && message.media.webpage.document);
-
if(!media) {
//this.log('no media!', message);
- break;
+ continue;;
}
-
+
if(media._ == 'document' && media.type != 'video'/* && media.type != 'gif' */) {
//this.log('broken video', media);
- break;
+ continue;
}
-
+
let div = document.createElement('div');
//console.log(message, photo);
-
+
let sizes = media.sizes || media.thumbs;
if(sizes && sizes[0].bytes) {
appPhotosManager.setAttachmentPreview(sizes[0].bytes, div, false, true);
} /* else {
this.log('no stripped size', message, media);
} */
-
+
//this.log('inputMessagesFilterPhotoVideo', message, media);
-
+
let load = () => appPhotosManager.preloadPhoto(media, appPhotosManager.choosePhotoSize(media, 380, 0))
.then((blob) => {
if($rootScope.selectedPeerID != peerID) {
this.log.warn('peer changed');
return;
}
-
+
div.style.backgroundImage = 'url(' + URL.createObjectURL(blob) + ')';
});
-
- div.setAttribute('message-id', '' + mid);
-
+
+ div.setAttribute('message-id', '' + message.mid);
+
this.lazyLoadQueueSidebar.push({div, load});
-
+
this.lastSharedMediaDiv.append(div);
if(this.lastSharedMediaDiv.childElementCount == 3) {
- this.sharedMedia.contentMedia.append(this.lastSharedMediaDiv);
+ this.sidebarScroll.append(this.lastSharedMediaDiv);
this.lastSharedMediaDiv = document.createElement('div');
}
-
- this.mediaDivsByIDs[mid] = div;
-
- //this.sharedMedia.contentMedia.append(div);
-
- break;
+
+ this.mediaDivsByIDs[message.mid] = div;
+
+ //sharedMediaDiv.append(div);
}
- case 'inputMessagesFilterDocument': {
+ break;
+ }
+
+ case 'inputMessagesFilterDocument': {
+ sharedMediaDiv = this.sharedMedia.contentDocuments;
+
+ for(let message of messages) {
if(!message.media.document || message.media.document.type == 'voice') {
- break;
+ continue;
}
-
+
let doc = message.media.document;
if(doc.attributes) {
if(doc.attributes.find((a: any) => a._ == "documentAttributeSticker")) {
- break;
+ continue;
}
}
-
+
//this.log('come back down to my knees', message);
-
+
let div = wrapDocument(message.media.document, true);
- this.sharedMedia.contentDocuments.append(div);
- break;
+ this.sidebarScroll.append(div);
}
+ break;
+ }
+
+ case 'inputMessagesFilterUrl': {
+ sharedMediaDiv = this.sharedMedia.contentLinks;
- case 'inputMessagesFilterUrl': {
+ for(let message of messages) {
if(!message.media.webpage || message.media.webpage._ == 'webPageEmpty') {
- break;
+ continue;
}
-
+
let webpage = message.media.webpage;
let div = document.createElement('div');
let previewDiv = document.createElement('div');
previewDiv.classList.add('preview');
-
+
//this.log('wrapping webpage', webpage);
-
+
if(webpage.photo) {
let load = () => appPhotosManager.preloadPhoto(webpage.photo.id, appPhotosManager.choosePhotoSize(webpage.photo, 380, 0))
.then((blob) => {
@@ -366,61 +372,69 @@ class AppSidebarRight {
this.log.warn('peer changed');
return;
}
-
+
previewDiv.style.backgroundImage = 'url(' + URL.createObjectURL(blob) + ')';
});
-
+
this.lazyLoadQueueSidebar.push({div: previewDiv, load});
} else {
previewDiv.innerText = (webpage.title || webpage.description || webpage.url || webpage.display_url).slice(0, 1);
previewDiv.classList.add('empty');
}
-
+
let title = webpage.rTitle || '';
let subtitle = webpage.rDescription || '';
let url = RichTextProcessor.wrapRichText(webpage.url || '');
-
+
if(!title) {
//title = new URL(webpage.url).hostname;
title = webpage.display_url.split('/', 1)[0];
}
-
+
div.append(previewDiv);
div.insertAdjacentHTML('beforeend', `
- ${title}
- ${subtitle}
- ${url}
+ ${title}
+ ${subtitle}
+ ${url}
`);
-
+
if(div.innerText.trim().length) {
- this.sharedMedia.contentLinks.append(div);
+ this.sidebarScroll.append(div);
}
-
- break;
+
}
-
- /* case 'inputMessagesFilterVoice': {
- //this.log('wrapping audio', message.media);
- if(!message.media || !message.media.document || message.media.document.type != 'voice') {
- break;
- }
-
- let doc = message.media.document;
-
- this.log('wrapping audio', doc);
-
- let audioDiv = wrapAudio(doc);
-
- this.sharedMedia.contentAudio.append(audioDiv);
-
- break;
- } */
- default:
- //console.warn('death is my friend', message);
+ break;
+ }
+
+ /* case 'inputMessagesFilterVoice': {
+ //this.log('wrapping audio', message.media);
+ if(!message.media || !message.media.document || message.media.document.type != 'voice') {
break;
+ }
+
+ let doc = message.media.document;
+
+ this.log('wrapping audio', doc);
+
+ let audioDiv = wrapAudio(doc);
+
+ this.sharedMedia.contentAudio.append(audioDiv);
+
+ break;
+ } */
+
+ default:
+ //console.warn('death is my friend', message);
+ break;
+ }
+
+ if(sharedMediaDiv) {
+ let parent = sharedMediaDiv.parentElement;
+ if(parent.lastElementChild.classList.contains('preloader')) {
+ parent.lastElementChild.remove();
}
- });
+ }
this.onSidebarScroll();
}).then(() => {
@@ -430,26 +444,17 @@ class AppSidebarRight {
this.loadSidebarMediaPromises[type] = null;
});
});
-
+
return promises;
}
-
+
public fillProfileElements() {
let peerID = this.peerID = $rootScope.selectedPeerID;
this.loadSidebarMediaPromises = {};
this.lastSharedMediaDiv = document.createElement('div');
-
+
//this.log('fillProfileElements');
-
- this.savedVirtualStates = {};
- this.prevTabID = -1;
- this.sidebarScroll.setVirtualContainer(null);
- (this.profileTabs.children[1] as HTMLLIElement).click(); // set media
-
- if(this.sharedMediaSelected) {
- //this.sidebarScroll.setVirtualContainer(this.sharedMediaSelected);
- }
-
+
this.profileContentEl.parentElement.scrollTop = 0;
this.profileElements.bio.style.display = 'none';
this.profileElements.phone.style.display = 'none';
@@ -457,40 +462,48 @@ class AppSidebarRight {
this.profileElements.notificationsRow.style.display = '';
this.profileElements.notificationsCheckbox.checked = true;
this.profileElements.notificationsStatus.innerText = 'Enabled';
-
+
this.mediaDivsByIDs = {};
-
+
this.lazyLoadQueueSidebar.clear();
-
+
Object.keys(this.sharedMedia).forEach(key => {
this.sharedMedia[key].innerHTML = '';
+
+ let parent = this.sharedMedia[key].parentElement;
+ if(!parent.querySelector('.preloader')) {
+ putPreloader(parent, true);
+ }
});
-
+
this.sharedMediaTypes.forEach(type => {
//this.minMediaID[type] = 0;
this.cleared[type] = true;
});
-
+
+ this.savedVirtualStates = {};
+ this.prevTabID = -1;
+ this.sidebarScroll.setVirtualContainer(null);
+ (this.profileTabs.children[1] as HTMLLIElement).click(); // set media
+
let setText = (text: string, el: HTMLDivElement) => {
el.style.display = '';
if(el.childElementCount > 1) {
el.firstElementChild.remove();
}
-
+
let p = document.createElement('p');
p.innerHTML = text;
el.prepend(p);
};
-
+
// username
if(peerID != appImManager.myID) {
let username = appPeersManager.getPeerUsername(peerID);
if(username) {
setText(appPeersManager.getPeerUsername(peerID), this.profileElements.username);
}
- }
-
- if(peerID != appImManager.myID) {
+
let dialog: any = appMessagesManager.getDialogByPeerID(peerID);
if(dialog.length) {
dialog = dialog[0];
@@ -498,57 +511,57 @@ class AppSidebarRight {
if(dialog.notify_settings && dialog.notify_settings.mute_until) {
muted = new Date(dialog.notify_settings.mute_until * 1000) > new Date();
}
-
+
appImManager.setMutedState(muted);
}
} else {
this.profileElements.notificationsRow.style.display = 'none';
}
-
+
if(peerID > 0) {
let user = appUsersManager.getUser(peerID);
if(user.phone && peerID != appImManager.myID) {
setText('+' + formatPhoneNumber(user.phone).formatted, this.profileElements.phone);
}
-
+
appProfileManager.getProfile(peerID, true).then(userFull => {
if(this.peerID != peerID) {
this.log.warn('peer changed');
return;
}
-
+
if(userFull.rAbout && peerID != appImManager.myID) {
setText(userFull.rAbout, this.profileElements.bio);
}
-
+
//this.log('userFull', userFull);
-
+
if(userFull.pinned_msg_id) { // request pinned message
appImManager.pinnedMsgID = userFull.pinned_msg_id;
appMessagesManager.wrapSingleMessage(userFull.pinned_msg_id);
}
-
+
this.sidebarScroll.getScrollTopOffset();
});
} else {
let chat = appPeersManager.getPeer(peerID);
-
+
appProfileManager.getChatFull(chat.id).then((chatFull: any) => {
if(this.peerID != peerID) {
this.log.warn('peer changed');
return;
}
-
+
//this.log('chatInfo res 2:', chatFull);
-
+
if(chatFull.about) {
setText(RichTextProcessor.wrapRichText(chatFull.about), this.profileElements.bio);
}
-
+
this.sidebarScroll.getScrollTopOffset();
});
}
-
+
this.sidebarScroll.getScrollTopOffset();
//this.loadSidebarMedia();
}
diff --git a/src/lib/ckin.js b/src/lib/ckin.js
index 8070fa4b..6de7eb17 100644
--- a/src/lib/ckin.js
+++ b/src/lib/ckin.js
@@ -3,18 +3,6 @@
NodeList.prototype.forEach = Array.prototype.forEach;
})();
-String.prototype.toHHMMSS = function(leadZero) {
- let sec_num = parseInt(this, 10);
- let hours = Math.floor(sec_num / 3600);
- let minutes = Math.floor((sec_num - (hours * 3600)) / 60);
- let seconds = sec_num - (hours * 3600) - (minutes * 60);
-
- if(hours < 10) hours = "0" + hours;
- if(minutes < 10) minutes = leadZero ? "0" + minutes : minutes;
- if(seconds < 10) seconds = "0" + seconds;
- return minutes + ':' + seconds;
-}
-
function stylePlayer(player, video) {
let skin = attachSkin(video.dataset.ckin);
player.classList.add(skin);
diff --git a/src/lib/lottieLoader.ts b/src/lib/lottieLoader.ts
index 835fd146..7ebcd1d4 100644
--- a/src/lib/lottieLoader.ts
+++ b/src/lib/lottieLoader.ts
@@ -33,9 +33,9 @@ class LottieLoader {
for(let i = length - 1; i >= 0; --i) {
let {animation, container, paused, autoplay, canvas} = animations[i];
- if(canvas && isElementInViewport(container)) {
+ if(canvas) {
let c = container.firstElementChild as HTMLCanvasElement;
- if(!c.height && !c.width) {
+ if(!c.height && !c.width && isElementInViewport(container)) {
//console.log('lottie need resize');
animation.resize();
}
diff --git a/src/lib/polyfill.ts b/src/lib/polyfill.ts
index dafe952a..81cf9c88 100644
--- a/src/lib/polyfill.ts
+++ b/src/lib/polyfill.ts
@@ -53,6 +53,23 @@ Array.prototype.forEachReverse = function(callback: (value: T, index?: number
}
};
+Array.prototype.findAndSplice = function(verify: (value: T, index?: number, array?: Array) => boolean) {
+ let index = this.findIndex(verify);
+ return index !== -1 ? this.splice(index, 1)[0] : undefined;
+};
+
+String.prototype.toHHMMSS = function(leadZero = false) {
+ let sec_num = parseInt(this + '', 10);
+ let hours: any = Math.floor(sec_num / 3600);
+ let minutes: any = Math.floor((sec_num - (hours * 3600)) / 60);
+ let seconds: any = sec_num - (hours * 3600) - (minutes * 60);
+
+ if(hours < 10) hours = "0" + hours;
+ if(minutes < 10) minutes = leadZero ? "0" + minutes : minutes;
+ if(seconds < 10) seconds = "0" + seconds;
+ return minutes + ':' + seconds;
+}
+
declare global {
interface Uint8Array {
hex: string;
@@ -62,5 +79,10 @@ declare global {
interface Array {
forEachReverse(callback: (value: T, index?: number, array?: Array) => void): void;
+ findAndSplice(verify: (value: T, index?: number, array?: Array) => boolean): T;
+ }
+
+ interface String {
+ toHHMMSS(leadZero?: boolean): string;
}
}
diff --git a/src/lib/utils.js b/src/lib/utils.js
index 563116b7..6597269b 100644
--- a/src/lib/utils.js
+++ b/src/lib/utils.js
@@ -297,7 +297,7 @@ export function getSelectedText() {
export const $rootScope = {
$broadcast: (name/* : string */, detail/*? : any */) => {
- ////console.log(dT(), 'Broadcasting ' + name + ' event, with args:', detail);
+ //console.log(dT(), 'Broadcasting ' + name + ' event, with args:', detail);
//console.trace();
let myCustomEvent = new CustomEvent(name, {detail});
document.dispatchEvent(myCustomEvent);
diff --git a/src/scss/partials/_chat.scss b/src/scss/partials/_chat.scss
index 5eedc733..165d6439 100644
--- a/src/scss/partials/_chat.scss
+++ b/src/scss/partials/_chat.scss
@@ -370,8 +370,8 @@
cursor: pointer;
background: none!important;
box-shadow: none;
- max-width: 300px;
- max-height: 300px;
+ /* max-width: 300px;
+ max-height: 300px; */
}
img {
@@ -387,6 +387,13 @@
}
}
+ &.sticker {
+ .bubble__container {
+ max-width: 200px;
+ max-height: 200px;
+ }
+ }
+
&.round {
.attachment {
max-width: 200px;
@@ -702,11 +709,11 @@
/* padding-bottom: 4px; */
color: $darkblue;
font-size: .9rem;
- width: max-content;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
- white-space: nowrap;
+ //width: max-content;
+ //white-space: nowrap;
}
&:not(.webpage) {
@@ -732,16 +739,25 @@
margin-top: 6px;
}
- &:not(.sticker):not(.emoji-big):not(.round):last-child .bubble__container:after {
+ &:not(.sticker):not(.emoji-big):not(.round).is-group-last .bubble__container:after {
position: absolute;
- bottom: -1px;
+ bottom: 0;
width: 11px;
height: 20px;
background-repeat: no-repeat repeat;
content: '';
background-size: 11px 20px;
+ background-position-y: 1px;
}
}
+
+ .bubble-audio.is-in .time {
+ width: inherit;
+ }
+
+ .bubble-audio.is-out .time {
+ width: inherit;
+ }
/* .bubble + .bubble {
margin-top: 5px;
@@ -761,11 +777,11 @@
border-radius: 6px 12px 12px 6px;
}
- &:first-child .bubble__container {
+ &.is-group-first .bubble__container {
border-radius: 12px 12px 12px 6px;
}
- &:last-child .bubble__container {
+ &.is-group-last .bubble__container {
border-radius: 6px 12px 12px 0px;
//border-radius: 12px 12px 12px 0px;
@@ -775,7 +791,7 @@
}
}
- &:first-child:last-child .bubble__container {
+ &.is-group-first.is-group-last .bubble__container {
border-radius: 12px 12px 12px 0px;
}
@@ -835,11 +851,11 @@
border-radius: 12px 6px 6px 12px;
}
- &:first-child .bubble__container {
+ &.is-group-first .bubble__container {
border-radius: 12px 12px 6px 12px;
}
- &:last-child .bubble__container {
+ &.is-group-last .bubble__container {
border-radius: 12px 6px 0px 12px;
&:after {
@@ -848,7 +864,7 @@
}
}
- &:first-child:last-child .bubble__container {
+ &.is-group-first.is-group-last .bubble__container {
border-radius: 12px 12px 0px 12px;
}
diff --git a/src/scss/partials/_rightSIdebar.scss b/src/scss/partials/_rightSIdebar.scss
new file mode 100644
index 00000000..3293c30d
--- /dev/null
+++ b/src/scss/partials/_rightSIdebar.scss
@@ -0,0 +1,286 @@
+.profile-container {
+ width: 0%;
+ /* grid-column: 3; */
+ position: relative;
+ transition: .2s ease-in-out;
+
+ > .scrollable {
+ min-width: 25vw;
+ display: flex;
+ flex-direction: column;
+ }
+
+ @media (min-width: $large-screen) {
+ > .scrollable {
+ min-width: calc(#{$large-screen} / 4 - 1px);
+ }
+ }
+
+ &:not(.active) {
+ border-left-width: 0;
+ }
+
+ &.active {
+ width: 25%;
+ }
+
+ .sidebar-header {
+ flex: 0 0 auto;
+ }
+}
+
+.profile-content {
+ flex: 1 1 auto;
+ display: flex;
+ flex-direction: column;
+
+ .profile-name {
+ text-align: center;
+ font-size: 23px;
+ font-weight: 500;
+ margin-bottom: 3px;
+
+ span.emoji {
+ vertical-align: inherit;
+ min-width: min-content;
+ }
+ }
+
+ .profile-subtitle {
+ text-align: center;
+ color: $darkgrey;
+ font-size: 14px;
+
+ &.online {
+ color: $darkblue;
+ }
+ }
+
+ .profile-row {
+ display: flex;
+ width: 100%;
+ flex-direction: column;
+ padding-left: 80px;
+ padding-top: 2px;
+ padding-right: 12px;
+ font-size: 15px;
+ position: relative;
+ margin-top: 1.75rem;
+
+ &:before {
+ position: absolute;
+ left: 24px;
+ /* top: 0; */
+ font-size: 24px;
+ color: $darkgrey;
+ }
+
+ p {
+ color: #000;
+ margin: 0;
+ }
+
+ &-bio {
+ .emoji {
+ width: 24px;
+ height: 24px;
+ }
+ }
+ }
+
+ p.profile-row-label {
+ color: $placeholder-color;
+ font-size: 14px;
+ margin-top: 1px;
+ }
+
+ .user-avatar {
+ width: 120px;
+ height: 120px;
+ margin: 0 auto 20px;
+ font-size: 4rem!important;
+ }
+
+ [type="checkbox"] + span {
+ padding-left: 54px;
+ margin-left: -54px;
+ }
+
+ .content-container {
+ width: 100%;
+ max-width: 100%;
+ overflow: hidden;
+ flex: 1;
+ }
+
+ .profile-tabs {
+ margin-top: 40px;
+ }
+
+ .profile-tabs-content {
+ height: 100%;
+ /* width: 500%;
+ margin-left: -100%;
+ */
+ /* > div {
+ height: 0;
+
+ &.active {
+ height: auto;
+ }
+ } */
+
+ > div {
+ height: 100%;
+ position: relative;
+ }
+
+ /* > div > div:not(.scroll-padding) {
+ height: 100%;
+ } */
+
+ .preloader {
+ padding: 0;
+ position: absolute;
+ height: 100%;
+
+ > svg {
+ height: 50px;
+ width: 50px;
+ }
+ }
+
+ #content-media {
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ padding-top: 4px;
+
+ > div {
+ display: grid;
+ grid-template-columns: 1fr 1fr 1fr;
+ grid-auto-rows: max-content;
+ grid-gap: 3.5px;
+ place-items: start;
+ padding-top: 3.5px;
+
+ > div {
+ width: 100%;
+ cursor: pointer;
+
+ background-repeat: no-repeat;
+ background-size: cover;
+ background-position: center center;
+
+ display: flex;
+ background-color: #cecece;
+ justify-content: center;
+ align-items: center;
+
+ &::before {
+ content: "";
+ display: inline-block;
+ width: 1px;
+ height: 0;
+ padding-bottom: 100%;
+ }
+ }
+ }
+ }
+
+ #content-docs {
+ padding: 7px 20px;
+
+ .document {
+ padding-left: 4rem;
+ padding-right: 1rem;
+ //height: 54px;
+ height: calc(50px + 1.5rem);
+
+ &-ico, &-download {
+ width: 48px;
+ height: 48px;
+ }
+
+ /* & + .document {
+ margin-top: 1.5rem;
+ } */
+ }
+
+ .document-name {
+ font-weight: normal;
+
+ width: 100%;
+ max-width: 100%;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+ }
+
+ #content-links {
+ padding: 0 30px 15px 15px;
+
+ > div {
+ display: flex;
+ flex-direction: column;
+ margin-top: 20px;
+ margin-left: 5px;
+ padding-bottom: 2px;
+ //padding-bottom: 10px;
+ position: relative;
+ padding-left: 60px;
+ overflow: hidden;
+ //min-height: 48px;
+ min-height: 58px;
+
+ .preview {
+ height: 48px;
+ width: 48px;
+ border-radius: 5px;
+ overflow: hidden;
+ position: absolute;
+ left: 0;
+ top: 0;
+ background-repeat: no-repeat;
+ background-size: cover;
+ background-position: center center;
+
+ &.empty {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 2rem;
+ color: #fff;
+ text-transform: uppercase;
+ background-color: $blue;
+ }
+ }
+
+ .url {
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ }
+ }
+
+ .title {
+ font-size: 16px;
+ margin-top: 3px;
+ }
+
+ .subtitle {
+ font-size: 14px;
+ }
+ }
+
+ #content-audio {
+ padding: 0 15px 15px 15px;
+
+ > div {
+ margin-top: 15px;
+ padding-bottom: 10px;
+ min-height: 60px;
+ }
+ }
+ }
+}
diff --git a/src/scss/partials/_sidebar.scss b/src/scss/partials/_sidebar.scss
index 99247fe6..757da4ea 100644
--- a/src/scss/partials/_sidebar.scss
+++ b/src/scss/partials/_sidebar.scss
@@ -29,234 +29,3 @@
margin-left: .5rem;
}
}
-
-.profile-content {
- .profile-name {
- text-align: center;
- font-size: 23px;
- font-weight: 500;
- margin: 3px 0;
-
- span.emoji {
- vertical-align: inherit;
- min-width: min-content;
- }
- }
-
- .profile-subtitle {
- text-align: center;
- color: $darkgrey;
- font-size: 14px;
- margin: 0 0 18px;
-
- &.online {
- color: $darkblue;
- }
- }
-
- .profile-row {
- display: flex;
- width: 100%;
- flex-direction: column;
- padding-left: 80px;
- padding-top: 2px;
- padding-right: 12px;
- font-size: 15px;
- position: relative;
- margin: 1.75rem 0;
-
- &:before {
- position: absolute;
- left: 24px;
- /* top: 0; */
- font-size: 24px;
- color: $darkgrey;
- }
-
- p {
- color: #000;
- margin: 0;
- }
-
- .profile-row-label {
- color: $placeholder-color;
- font-size: 14px;
- margin-top: 1px;
- }
- }
-
- .profile-row-bio {
- .emoji {
- width: 24px;
- height: 24px;
- }
- }
-
- .user-avatar {
- width: 120px;
- height: 120px;
- margin: 0 auto 20px;
- font-size: 4rem!important;
- }
-
- [type="checkbox"] + span {
- padding-left: 54px;
- margin-left: -54px;
- }
-
- .content-container {
- width: 100%;
- max-width: 100%;
- overflow: hidden;
- }
-
- .profile-tabs {
- margin-top: 40px;
- }
-
- .profile-tabs-content {
- /* width: 500%;
- margin-left: -100%;
- */
- /* > div {
- height: 0;
-
- &.active {
- height: auto;
- }
- } */
-
- #content-media {
- width: 100%;
- display: flex;
- flex-direction: column;
- padding-top: 4px;
-
- > div {
- display: grid;
- grid-template-columns: 1fr 1fr 1fr;
- grid-auto-rows: max-content;
- grid-gap: 3.5px;
- place-items: start;
- padding-top: 3.5px;
-
- > div {
- width: 100%;
- cursor: pointer;
-
- background-repeat: no-repeat;
- background-size: cover;
- background-position: center center;
-
- display: flex;
- background-color: #cecece;
- justify-content: center;
- align-items: center;
-
- &::before {
- content: "";
- display: inline-block;
- width: 1px;
- height: 0;
- padding-bottom: 100%;
- }
- }
- }
- }
-
- #content-docs {
- padding: 7px 20px;
-
- .document {
- padding-left: 4rem;
- padding-right: 1rem;
- //height: 54px;
- height: calc(50px + 1.5rem);
-
- &-ico, &-download {
- width: 48px;
- height: 48px;
- }
-
- /* & + .document {
- margin-top: 1.5rem;
- } */
- }
-
- .document-name {
- font-weight: normal;
-
- width: 100%;
- max-width: 100%;
- overflow: hidden;
- text-overflow: ellipsis;
- }
- }
-
- #content-links {
- padding: 0 30px 15px 15px;
-
- > div {
- display: flex;
- flex-direction: column;
- margin-top: 20px;
- margin-left: 5px;
- padding-bottom: 2px;
- //padding-bottom: 10px;
- position: relative;
- padding-left: 60px;
- overflow: hidden;
- //min-height: 48px;
- min-height: 58px;
-
- .preview {
- height: 48px;
- width: 48px;
- border-radius: 5px;
- overflow: hidden;
- position: absolute;
- left: 0;
- top: 0;
- background-repeat: no-repeat;
- background-size: cover;
- background-position: center center;
-
- &.empty {
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 2rem;
- color: #fff;
- text-transform: uppercase;
- background-color: $blue;
- }
- }
-
- .url {
- white-space: nowrap;
- text-overflow: ellipsis;
- overflow: hidden;
- }
- }
-
- .title {
- font-size: 16px;
- margin-top: 3px;
- }
-
- .subtitle {
- font-size: 14px;
- }
- }
-
- #content-audio {
- padding: 0 15px 15px 15px;
-
- > div {
- margin-top: 15px;
- padding-bottom: 10px;
- min-height: 60px;
- }
- }
- }
-}
diff --git a/src/scss/style.scss b/src/scss/style.scss
index 2d193472..43aeb85b 100644
--- a/src/scss/style.scss
+++ b/src/scss/style.scss
@@ -29,11 +29,15 @@ $bg: #ffffff;
$text-size: 16px;
$time-size: 12px;
+//$large-screen: 1680px;
+$large-screen: 16800px;
+
@import "partials/ico";
@import "partials/chatlist";
@import "partials/chat";
@import "partials/sidebar";
@import "partials/leftSidebar";
+@import "partials/rightSidebar";
@import "partials/mediaViewer";
@import "partials/ckin";
@import "partials/emojiDropdown";
@@ -59,7 +63,18 @@ button, input, optgroup, select, textarea, html {
height: 100vh;
min-height: 100vh;
width: 100%;
- min-width: 100%;
+ //min-width: 100%;
+ margin: 0 auto;
+ max-width: $large-screen;
+
+ @media (min-width: $large-screen) {
+ border-top-width: 0;
+ border-bottom-width: 0;
+ border-left-width: 1px;
+ border-right-width: 1px;
+ border-style: solid;
+ border-color: #DADCE0;
+ }
}
.container {
@@ -481,13 +496,13 @@ input {
position: relative;
padding-left: 67px;
min-height: 58px;
- max-width: 286px;
+ max-width: 244px;
overflow: visible!important;
&-toggle, &-download {
border-radius: 50%;
background-color: $blue;
- font-size: 2.2rem;
+ font-size: 2.3rem;
align-items: center;
}
@@ -1563,19 +1578,6 @@ div.scrollable::-webkit-scrollbar-thumb {
flex: 1;
}
- .profile-container {
- //display: none;
- width: 0%;
- /* grid-column: 3; */
- position: relative;
-
- transition: .2s ease-in-out;
-
- > .scrollable {
- min-width: 25vw;
- }
- }
-
.preloader {
width: 50px;
height: 50px;
diff --git a/tsconfig.json b/tsconfig.json
index 83a369f9..b345a110 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -65,9 +65,9 @@
"node_modules",
"public",
"coverage",
- "./src/lib/StackBlur.js",
+ /* "./src/lib/StackBlur.js",
"./src/lib/*.js",
"./src/*.js",
- "*.js",
+ "*.js", */
]
}
diff --git a/webpack.prod.js b/webpack.prod.js
index b181c6bc..5785e64b 100644
--- a/webpack.prod.js
+++ b/webpack.prod.js
@@ -59,7 +59,7 @@ module.exports = merge(common, {
files.forEach(file => {
//console.log('to unlink 1:', file);
- if(file.includes('mitm.') || file.includes('sw.js')) return;
+ if(file.includes('mitm.') || file.includes('sw.js') || file.includes('.xml') || file.includes('.webmanifest')) return;
let p = path.resolve(buildDir + file);
if(!newlyCreatedAssets[file] && ['.gz', '.js'].find(ext => file.endsWith(ext)) !== undefined) {