661eedc03a
* only consider short-heights when not smallscreen; hide status bar when small screen, but leave shadow; * fix max char counting bugs with paste, yet be still be able to use modifier keys even when max chars reached * rmeove 'chat' button; move into textarea * use image for emoji picker for sizing consitency * cleanup unused things * - totally unecessary emoji picker style improvements - totally necessary doctype added to emoji picker so it shows up more stable-y on mobile views * more stable layout positioning for chat panel without hacky margins, so that the bottom of the message list will always be on top of the form input, and not behind it at any point. * hide header on touch screens when screns are small and screen height is short (possibly when keyboard is up), so that there's more visibliity to see messages. this only works on chrome, not ios safari right now, due to the position: fixed of things. * move char counting to keyup instead * address message text horiz overflow (#157) * dont jumpToBottom if user has scrolled about 200px from the bottom (#101) * scroll to bottom on resize too * cleanup * revert test bool * typo * re-readjust short-wide case again * - add focus to input field after emoji is selected, put cursor at end - instead of smooth scrolling to bottom, just jump there.
145 lines
3.7 KiB
JavaScript
145 lines
3.7 KiB
JavaScript
export function getLocalStorage(key) {
|
|
try {
|
|
return localStorage.getItem(key);
|
|
} catch (e) {
|
|
}
|
|
return null;
|
|
}
|
|
|
|
export function setLocalStorage(key, value) {
|
|
try {
|
|
if (value !== "" && value !== null) {
|
|
localStorage.setItem(key, value);
|
|
} else {
|
|
localStorage.removeItem(key);
|
|
}
|
|
return true;
|
|
} catch (e) {}
|
|
return false;
|
|
}
|
|
|
|
export function clearLocalStorage(key) {
|
|
localStorage.removeItem(key);
|
|
}
|
|
|
|
// jump down to the max height of a div, with a slight delay
|
|
export function jumpToBottom(element) {
|
|
if (!element) return;
|
|
|
|
setTimeout(() => {
|
|
element.scrollTo({
|
|
top: element.scrollHeight,
|
|
left: 0,
|
|
behavior: 'auto'
|
|
});
|
|
}, 50, element);
|
|
}
|
|
|
|
// convert newlines to <br>s
|
|
export function addNewlines(str) {
|
|
return str.replace(/(?:\r\n|\r|\n)/g, '<br />');
|
|
}
|
|
|
|
export function pluralize(string, count) {
|
|
if (count === 1) {
|
|
return string;
|
|
} else {
|
|
return string + "s";
|
|
}
|
|
}
|
|
|
|
|
|
// Trying to determine if browser is mobile/tablet.
|
|
// Source: https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent
|
|
export function hasTouchScreen() {
|
|
let hasTouch = false;
|
|
if ("maxTouchPoints" in navigator) {
|
|
hasTouch = navigator.maxTouchPoints > 0;
|
|
} else if ("msMaxTouchPoints" in navigator) {
|
|
hasTouch = navigator.msMaxTouchPoints > 0;
|
|
} else {
|
|
var mQ = window.matchMedia && matchMedia("(pointer:coarse)");
|
|
if (mQ && mQ.media === "(pointer:coarse)") {
|
|
hasTouch = !!mQ.matches;
|
|
} else if ('orientation' in window) {
|
|
hasTouch = true; // deprecated, but good fallback
|
|
} else {
|
|
// Only as a last resort, fall back to user agent sniffing
|
|
var UA = navigator.userAgent;
|
|
hasTouch = (
|
|
/\b(BlackBerry|webOS|iPhone|IEMobile)\b/i.test(UA) ||
|
|
/\b(Android|Windows Phone|iPad|iPod)\b/i.test(UA)
|
|
);
|
|
}
|
|
}
|
|
return hasTouch;
|
|
}
|
|
|
|
// generate random avatar from https://robohash.org
|
|
export function generateAvatar(hash) {
|
|
const avatarSource = 'https://robohash.org/';
|
|
const optionSize = '?size=80x80';
|
|
const optionSet = '&set=set2';
|
|
const optionBg = ''; // or &bgset=bg1 or bg2
|
|
|
|
return avatarSource + hash + optionSize + optionSet + optionBg;
|
|
}
|
|
|
|
export function generateUsername() {
|
|
return `User ${(Math.floor(Math.random() * 42) + 1)}`;
|
|
}
|
|
|
|
export function secondsToHMMSS(seconds = 0) {
|
|
const finiteSeconds = Number.isFinite(+seconds) ? Math.abs(seconds) : 0;
|
|
|
|
const hours = Math.floor(finiteSeconds / 3600);
|
|
const hoursString = hours ? `${hours}:` : '';
|
|
|
|
const mins = Math.floor((finiteSeconds / 60) % 60);
|
|
const minString = mins < 10 ? `0${mins}:` : `${mins}:`;
|
|
|
|
const secs = Math.floor(finiteSeconds % 60);
|
|
const secsString = secs < 10 ? `0${secs}` : `${secs}`;
|
|
|
|
return hoursString + minString + secsString;
|
|
}
|
|
|
|
export function setVHvar() {
|
|
var vh = window.innerHeight * 0.01;
|
|
// Then we set the value in the --vh custom property to the root of the document
|
|
document.documentElement.style.setProperty('--vh', `${vh}px`);
|
|
console.log("== new vh", vh)
|
|
}
|
|
|
|
export function doesObjectSupportFunction(object, functionName) {
|
|
return typeof object[functionName] === "function";
|
|
}
|
|
|
|
// return a string of css classes
|
|
export function classNames(json) {
|
|
const classes = [];
|
|
|
|
Object.entries(json).map(function(item) {
|
|
const [ key, value ] = item;
|
|
if (value) {
|
|
classes.push(key);
|
|
}
|
|
return null;
|
|
});
|
|
return classes.join(' ');
|
|
}
|
|
|
|
|
|
// taken from
|
|
// https://medium.com/@TCAS3/debounce-deep-dive-javascript-es6-e6f8d983b7a1
|
|
export function debounce(fn, time) {
|
|
let timeout;
|
|
|
|
return function() {
|
|
const functionCall = () => fn.apply(this, arguments);
|
|
|
|
clearTimeout(timeout);
|
|
timeout = setTimeout(functionCall, time);
|
|
}
|
|
}
|