Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
163 changes: 139 additions & 24 deletions htdocs/js/PGProblemEditor/pgproblemeditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -395,27 +395,124 @@
}
});

// Synchronize the heights of the render area and the editor area for wide windows.
if (editorArea && renderArea) {
const codeMirrorResizeObserver = new ResizeObserver((entries) => {
if (document.body.clientWidth < 992) return;

for (const entry of entries) {
if (entry.borderBoxSize) {
// Note that the blockSize is the height (since width is not resizable).
const height = Array.isArray(entry.borderBoxSize)
? entry.borderBoxSize[0].blockSize
: entry.borderBoxSize.blockSize;
if (window.getComputedStyle(renderArea).getPropertyValue('height') !== `${height}px`)
renderArea.style.height = `${height}px`;
if (window.getComputedStyle(editorArea).getPropertyValue('height') !== `${height}px`) {
editorArea.style.height = `${height}px`;
}
}
const pgEditContainer = document.getElementById('pgedit-container');
const codePanel = pgEditContainer?.querySelector('.pgedit-panel.code');
const renderPanel = pgEditContainer?.querySelector('.pgedit-panel.render');

if (pgEditContainer && codePanel && renderPanel) {
if (document.body.clientWidth < 992) {
const initialCodePanelHeight = localStorage.getItem('WW.pgedit.codePanelHeight');
if (initialCodePanelHeight) codePanel.style.height = initialCodePanelHeight;
} else {
const initialResizeContainerHeight = localStorage.getItem('WW.pgedit.containerHeight');
if (initialResizeContainerHeight) pgEditContainer.style.height = initialResizeContainerHeight;
const initialCodePanelWidth = localStorage.getItem('WW.pgedit.codePanelWidth');
if (initialCodePanelWidth) codePanel.style.width = initialCodePanelWidth;
}

const verticalResizer = pgEditContainer.querySelector('.vertical-resizer');

verticalResizer?.addEventListener('pointerdown', (e) => {
verticalResizer.setPointerCapture(e.pointerId);

const startY = e.clientY;
const startHeight =
document.body.clientWidth < 992
? codePanel.getBoundingClientRect().height
: pgEditContainer.getBoundingClientRect().height;

const onPointerMove =
document.body.clientWidth < 992
? (moveEvent) => {
codePanel.style.height = `${startHeight + (moveEvent.clientY - startY)}px`;
localStorage.setItem('WW.pgedit.codePanelHeight', codePanel.style.height);
}
: (moveEvent) => {
pgEditContainer.style.height = `${startHeight + (moveEvent.clientY - startY)}px`;
localStorage.setItem('WW.pgedit.containerHeight', pgEditContainer.style.height);
};
const onPointerUp = () => {
verticalResizer.releasePointerCapture(e.pointerId);
document.removeEventListener('pointermove', onPointerMove);
document.removeEventListener('pointerup', onPointerUp);
};

document.addEventListener('pointermove', onPointerMove);
document.addEventListener('pointerup', onPointerUp);
});

const updateHeight = (delta) => {
if (document.body.clientWidth < 992) {
codePanel.style.height = `${codePanel.getBoundingClientRect().height + delta}px`;
localStorage.setItem('WW.pgedit.codePanelHeight', codePanel.style.height);
} else {
pgEditContainer.style.height = `${pgEditContainer.getBoundingClientRect().height + delta}px`;
localStorage.setItem('WW.pgedit.containerHeight', pgEditContainer.style.height);
}
};

verticalResizer?.addEventListener('keydown', (e) => {
const step = e.ctrlKey ? 1 : e.altKey ? 50 : 20;
if (e.key === 'ArrowUp') {
updateHeight(-step);
e.preventDefault();
} else if (e.key === 'ArrowDown') {
updateHeight(step);
e.preventDefault();
}
});

const horizontalResizer = pgEditContainer.querySelector('.horizontal-resizer');

horizontalResizer?.addEventListener('pointerdown', (e) => {
horizontalResizer.setPointerCapture(e.pointerId);

const startX = e.clientX;
const startWidth = codePanel.getBoundingClientRect().width;

const onPointerMove = (moveEvent) => {
codePanel.style.width = `${startWidth + (moveEvent.clientX - startX)}px`;
localStorage.setItem('WW.pgedit.codePanelWidth', codePanel.style.width);
};

const onPointerUp = () => {
horizontalResizer.releasePointerCapture(e.pointerId);
document.removeEventListener('pointermove', onPointerMove);
document.removeEventListener('pointerup', onPointerUp);
};

document.addEventListener('pointermove', onPointerMove);
document.addEventListener('pointerup', onPointerUp);
});

horizontalResizer?.addEventListener('dblclick', () => {
codePanel.style.width = 'calc(50% - 0.5rem + 1px)';
localStorage.setItem('WW.pgedit.codePanelWidth', codePanel.style.width);
});

horizontalResizer?.addEventListener('keydown', (e) => {
if (e.key === 'Enter' || e.key === ' ') {
codePanel.style.width = 'calc(50% - 0.5rem + 1px)';
localStorage.setItem('WW.pgedit.codePanelWidth', codePanel.style.width);
e.preventDefault();
}
});

const updateWidth = (delta) => {
codePanel.style.width = `${codePanel.getBoundingClientRect().width + delta}px`;
localStorage.setItem('WW.pgedit.codePanelWidth', codePanel.style.width);
};

horizontalResizer?.addEventListener('keydown', (e) => {
const step = e.ctrlKey ? 1 : e.altKey ? 50 : 20;
if (e.key === 'ArrowLeft') {
updateWidth(-step);
e.preventDefault();
} else if (e.key === 'ArrowRight') {
updateWidth(step);
e.preventDefault();
}
});
codeMirrorResizeObserver.observe(editorArea);
codeMirrorResizeObserver.observe(renderArea);
}

// Save the initial placeholder content of the render area so that it can be put back when a problem is reloaded.
Expand All @@ -425,12 +522,29 @@
iframe.id = 'pgedit-render-iframe';
iframe.style.colorScheme = 'light';

// Adjust the height of the iframe when the window is resized and when the iframe loads.
// Adjust editor dimensions when the window is resized and when the iframe loads.
const adjustIFrameHeight = () => {
if (document.body.clientWidth < 992) {
if (iframe.contentDocument)
renderArea.style.height = `${iframe.contentDocument.documentElement.offsetHeight + 2}px`;
} else renderArea.style.height = `${editorArea.offsetHeight}px`;
if (iframe.contentDocument) {
pgEditContainer.style.height = '';
codePanel.style.width = '100%';
codePanel.style.height = localStorage.getItem('WW.pgedit.codePanelHeight') ?? '';
renderArea.style.height = `${
iframe.contentDocument.documentElement.offsetHeight +
2 +
(document.getElementById('author-comment')?.offsetHeight ?? 0)
}px`;
renderPanel.style.width = '100%';
renderPanel.style.height = renderArea.style.height;
}
} else {
pgEditContainer.style.height = localStorage.getItem('WW.pgedit.containerHeight') ?? '';
codePanel.style.width = localStorage.getItem('WW.pgedit.codePanelWidth') ?? '';
renderPanel.style.width = '';
codePanel.style.height = '100%';
renderPanel.style.height = '100%';
renderArea.style.height = '100%';
}
};
window.addEventListener('resize', adjustIFrameHeight);

Expand Down Expand Up @@ -584,7 +698,8 @@
if (data.pg_flags && data.pg_flags.comment) {
// The problem has a comment, so show it.
const container = document.createElement('div');
container.classList.add('px-2', 'mb-2');
container.id = 'author-comment';
container.classList.add('p-2');
container.innerHTML = data.pg_flags.comment;
iframe.after(container);
}
Expand Down
174 changes: 174 additions & 0 deletions htdocs/js/PGProblemEditor/pgproblemeditor.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
#pgedit-container {
display: flex;
flex-direction: column;
width: 100%;
height: 600px;
min-height: 400px;

.pgedit-inner-container {
display: flex;
flex: 1;
width: 100%;
height: calc(100% - 1rem - 2px);

.pgedit-panel {
overflow: auto;
}

.code {
width: calc(50% - 0.5rem);
height: 100%;
min-width: 400px;

.code-mirror-editor {
min-height: unset;
overflow: unset;
height: 100%;
}

.text-area-editor {
min-height: unset;
overflow: unset;
height: 100%;
resize: unset;
}
}

.render {
flex: 1;
min-width: 300px;
height: 100%;

#pgedit-render-area {
border: 1px solid var(--ww-layout-border-color, #ddd);
height: 100%;
display: flex;
flex-direction: column;

#pgedit-render-iframe {
flex-grow: 1;
border: none;
width: 100%;
}
}

#author-comment {
border-top: 1px solid var(--ww-layout-border-color, #ddd);
}
}
}

.pgedit-resizer {
background-color: #fff;
transition:
background 0.2s,
box-shadow 0.2s ease-in-out;
position: relative;
border: 1px solid var(--ww-layout-border-color, #ddd);
user-select: none;
touch-action: none;
display: flex;
justify-content: center;
align-items: center;
color: black;

&:focus {
z-index: 19;
box-shadow: 0 0 0.2rem 0.25rem #aaa;
outline: none;
}

&:hover {
z-index: 19;
background-color: #444;
color: white;
box-shadow: 0 0 0.2rem 0.25rem #888;
}

&::after {
content: '';
position: absolute;
background: transparent;
}
}

.vertical-resizer {
height: 1rem;
width: 100%;
cursor: row-resize;

i {
transform: scale(4, 1);
}

&::after {
top: -4px;
left: 0;
right: 0;
bottom: -4px;
}
}

.horizontal-resizer {
height: 100%;
width: 1rem;
cursor: col-resize;

i {
transform: scale(1, 4);
}

&::after {
top: 0;
left: -4px;
right: -4px;
bottom: 0;
}
}

@media (prefers-color-scheme: dark) {
.pgedit-resizer {
background-color: #000;
color: white;

&:focus {
box-shadow: 0 0 0.2rem 0.25rem #777;
}

&:hover {
background-color: #bbb;
color: black;
box-shadow: 0 0 0.2rem 0.25rem #999;
}
}
}

@media (max-width: 991px) {
height: unset;
min-height: unset;

.pgedit-inner-container {
flex-direction: column;
row-gap: 1rem;

.code {
width: 100%;
height: 400px;
min-height: 200px;
min-width: unset;
}

.render {
flex: unset;
height: 400px;
min-height: 200px;
width: 100%;
min-width: unset;
}

.horizontal-resizer {
display: none;
}
}
}
}
22 changes: 1 addition & 21 deletions htdocs/js/System/system.scss
Original file line number Diff line number Diff line change
Expand Up @@ -836,34 +836,14 @@ input.changed[type='text'] {
}
}

/* Styles for the PGProblemEditor Page */
/* Common styles for pages containing an editor. */

#editor {
.tab-content {
min-height: 140px;
}
}

#pgedit-render-area {
border: 1px solid var(--ww-layout-border-color, #ddd);
min-height: 400px;
height: 600px;
resize: vertical;
display: flex;
flex-direction: column;

@media only screen and (max-width: 992px) {
min-height: 200px;
height: 300px;
}

#pgedit-render-iframe {
flex-grow: 1;
border: none;
width: 100%;
}
}

// Fix the style of the save file path input group.
// It is forced to be ltr, but the bootstrap rtl style makes that look wrong.
/* rtl:raw:
Expand Down
Loading
Loading