This repository has been archived on 2023-03-18. You can view files and clone it, but cannot push or open issues or pull requests.
osr-discourse-src/app/assets/javascripts/discourse/components/composer-body.js.es6
Penar Musaraj 30b7006ca2 DEV: Eliminate "post bounce" after creating a post
Fix has two parts:
a) skips jumping to post if post is in view
b) debounces layout calculation when composer changes state
2020-02-11 14:04:46 -05:00

192 lines
5.2 KiB
JavaScript

import {
run,
cancel,
scheduleOnce,
later,
debounce,
throttle
} from "@ember/runloop";
import Component from "@ember/component";
import discourseComputed, { observes } from "discourse-common/utils/decorators";
import Composer from "discourse/models/composer";
import afterTransition from "discourse/lib/after-transition";
import positioningWorkaround from "discourse/lib/safari-hacks";
import { headerHeight } from "discourse/components/site-header";
import KeyEnterEscape from "discourse/mixins/key-enter-escape";
import { iOSWithVisualViewport } from "discourse/lib/utilities";
const START_EVENTS = "touchstart mousedown";
const DRAG_EVENTS = "touchmove mousemove";
const END_EVENTS = "touchend mouseup";
const MIN_COMPOSER_SIZE = 240;
const THROTTLE_RATE = 20;
function mouseYPos(e) {
return e.clientY || (e.touches && e.touches[0] && e.touches[0].clientY);
}
export default Component.extend(KeyEnterEscape, {
elementId: "reply-control",
classNameBindings: [
"composer.creatingPrivateMessage:private-message",
"composeState",
"composer.loading",
"composer.canEditTitle:edit-title",
"composer.createdPost:created-post",
"composer.creatingTopic:topic",
"composer.whisper:composing-whisper",
"composer.sharedDraft:composing-shared-draft",
"showPreview:show-preview:hide-preview",
"currentUserPrimaryGroupClass"
],
@discourseComputed("currentUser.primary_group_name")
currentUserPrimaryGroupClass(primaryGroupName) {
return primaryGroupName && `group-${primaryGroupName}`;
},
@discourseComputed("composer.composeState")
composeState(composeState) {
return composeState || Composer.CLOSED;
},
movePanels(size) {
$("#main-outlet").css("padding-bottom", size ? size : "");
// signal the progress bar it should move!
this.appEvents.trigger("composer:resized");
},
@observes(
"composeState",
"composer.action",
"composer.canEditTopicFeaturedLink"
)
resize() {
scheduleOnce("afterRender", () => {
if (!this.element || this.isDestroying || this.isDestroyed) {
return;
}
debounce(this, this.debounceMove, 300);
});
},
debounceMove() {
const h = $("#reply-control:not(.saving)").height() || 0;
this.movePanels(h);
},
keyUp() {
this.typed();
const lastKeyUp = new Date();
this._lastKeyUp = lastKeyUp;
// One second from now, check to see if the last key was hit when
// we recorded it. If it was, the user paused typing.
cancel(this._lastKeyTimeout);
this._lastKeyTimeout = later(() => {
if (lastKeyUp !== this._lastKeyUp) {
return;
}
this.appEvents.trigger("composer:find-similar");
}, 1000);
},
@observes("composeState")
disableFullscreen() {
if (this.composeState !== Composer.OPEN && positioningWorkaround.blur) {
positioningWorkaround.blur();
}
},
setupComposerResizeEvents() {
const $composer = $(this.element);
const $grippie = $(this.element.querySelector(".grippie"));
const $document = $(document);
let origComposerSize = 0;
let lastMousePos = 0;
const performDrag = event => {
$composer.trigger("div-resizing");
$composer.addClass("clear-transitions");
const currentMousePos = mouseYPos(event);
let size = origComposerSize + (lastMousePos - currentMousePos);
const winHeight = $(window).height();
size = Math.min(size, winHeight - headerHeight());
size = Math.max(size, MIN_COMPOSER_SIZE);
this.movePanels(size);
$composer.height(size);
};
const throttledPerformDrag = (event => {
event.preventDefault();
throttle(this, performDrag, event, THROTTLE_RATE);
}).bind(this);
const endDrag = () => {
$document.off(DRAG_EVENTS, throttledPerformDrag);
$document.off(END_EVENTS, endDrag);
$composer.removeClass("clear-transitions");
$composer.focus();
};
$grippie.on(START_EVENTS, event => {
event.preventDefault();
origComposerSize = $composer.height();
lastMousePos = mouseYPos(event);
$document.on(DRAG_EVENTS, throttledPerformDrag);
$document.on(END_EVENTS, endDrag);
});
if (iOSWithVisualViewport()) {
this.viewportResize();
window.visualViewport.addEventListener("resize", this.viewportResize);
}
},
viewportResize() {
const composerVH = window.visualViewport.height * 0.01;
document.documentElement.style.setProperty(
"--composer-vh",
`${composerVH}px`
);
},
didInsertElement() {
this._super(...arguments);
this.setupComposerResizeEvents();
const resize = () => run(() => this.resize());
const triggerOpen = () => {
if (this.get("composer.composeState") === Composer.OPEN) {
this.appEvents.trigger("composer:opened");
}
};
triggerOpen();
afterTransition($(this.element), () => {
resize();
triggerOpen();
});
positioningWorkaround($(this.element));
},
willDestroyElement() {
this._super(...arguments);
this.appEvents.off("composer:resize", this, this.resize);
if (iOSWithVisualViewport()) {
window.visualViewport.removeEventListener("resize", this.viewportResize);
}
},
click() {
this.openIfDraft();
}
});