mirror of
https://github.com/philomena-dev/philomena.git
synced 2024-12-02 15:48:00 +01:00
Merge remote-tracking branch 'origin/master' into redesign
This commit is contained in:
commit
0de3d98c82
41 changed files with 627 additions and 224 deletions
|
@ -86,10 +86,12 @@ function pickAndResize(elem) {
|
||||||
clearEl(elem);
|
clearEl(elem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const muted = store.get('unmute_videos') ? '' : 'muted';
|
||||||
|
|
||||||
if (imageFormat === 'mp4') {
|
if (imageFormat === 'mp4') {
|
||||||
elem.classList.add('full-height');
|
elem.classList.add('full-height');
|
||||||
elem.insertAdjacentHTML('afterbegin',
|
elem.insertAdjacentHTML('afterbegin',
|
||||||
`<video controls autoplay loop muted playsinline preload="auto" id="image-display"
|
`<video controls autoplay loop ${muted} playsinline preload="auto" id="image-display"
|
||||||
width="${imageWidth}" height="${imageHeight}">
|
width="${imageWidth}" height="${imageHeight}">
|
||||||
<source src="${uris.webm}" type="video/webm">
|
<source src="${uris.webm}" type="video/webm">
|
||||||
<source src="${uris.mp4}" type="video/mp4">
|
<source src="${uris.mp4}" type="video/mp4">
|
||||||
|
@ -102,7 +104,7 @@ function pickAndResize(elem) {
|
||||||
}
|
}
|
||||||
else if (imageFormat === 'webm') {
|
else if (imageFormat === 'webm') {
|
||||||
elem.insertAdjacentHTML('afterbegin',
|
elem.insertAdjacentHTML('afterbegin',
|
||||||
`<video controls autoplay loop muted playsinline id="image-display">
|
`<video controls autoplay loop ${muted} playsinline id="image-display">
|
||||||
<source src="${uri}" type="video/webm">
|
<source src="${uri}" type="video/webm">
|
||||||
<source src="${uri.replace(/webm$/, 'mp4')}" type="video/mp4">
|
<source src="${uri.replace(/webm$/, 'mp4')}" type="video/mp4">
|
||||||
<p class="block block--fixed block--warning">
|
<p class="block block--fixed block--warning">
|
||||||
|
|
|
@ -83,7 +83,7 @@ describe('DOM Utilities', () => {
|
||||||
it(`should remove the ${hiddenClass} class from the provided element`, () => {
|
it(`should remove the ${hiddenClass} class from the provided element`, () => {
|
||||||
const mockElement = createHiddenElement('div');
|
const mockElement = createHiddenElement('div');
|
||||||
showEl(mockElement);
|
showEl(mockElement);
|
||||||
expect(mockElement).not.to.have.class(hiddenClass);
|
expect(mockElement).not.toHaveClass(hiddenClass);
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should remove the ${hiddenClass} class from all provided elements`, () => {
|
it(`should remove the ${hiddenClass} class from all provided elements`, () => {
|
||||||
|
@ -93,9 +93,9 @@ describe('DOM Utilities', () => {
|
||||||
createHiddenElement('strong'),
|
createHiddenElement('strong'),
|
||||||
];
|
];
|
||||||
showEl(mockElements);
|
showEl(mockElements);
|
||||||
expect(mockElements[0]).not.to.have.class(hiddenClass);
|
expect(mockElements[0]).not.toHaveClass(hiddenClass);
|
||||||
expect(mockElements[1]).not.to.have.class(hiddenClass);
|
expect(mockElements[1]).not.toHaveClass(hiddenClass);
|
||||||
expect(mockElements[2]).not.to.have.class(hiddenClass);
|
expect(mockElements[2]).not.toHaveClass(hiddenClass);
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should remove the ${hiddenClass} class from elements provided in multiple arrays`, () => {
|
it(`should remove the ${hiddenClass} class from elements provided in multiple arrays`, () => {
|
||||||
|
@ -108,10 +108,10 @@ describe('DOM Utilities', () => {
|
||||||
createHiddenElement('em'),
|
createHiddenElement('em'),
|
||||||
];
|
];
|
||||||
showEl(mockElements1, mockElements2);
|
showEl(mockElements1, mockElements2);
|
||||||
expect(mockElements1[0]).not.to.have.class(hiddenClass);
|
expect(mockElements1[0]).not.toHaveClass(hiddenClass);
|
||||||
expect(mockElements1[1]).not.to.have.class(hiddenClass);
|
expect(mockElements1[1]).not.toHaveClass(hiddenClass);
|
||||||
expect(mockElements2[0]).not.to.have.class(hiddenClass);
|
expect(mockElements2[0]).not.toHaveClass(hiddenClass);
|
||||||
expect(mockElements2[1]).not.to.have.class(hiddenClass);
|
expect(mockElements2[1]).not.toHaveClass(hiddenClass);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ describe('DOM Utilities', () => {
|
||||||
it(`should add the ${hiddenClass} class to the provided element`, () => {
|
it(`should add the ${hiddenClass} class to the provided element`, () => {
|
||||||
const mockElement = document.createElement('div');
|
const mockElement = document.createElement('div');
|
||||||
hideEl(mockElement);
|
hideEl(mockElement);
|
||||||
expect(mockElement).to.have.class(hiddenClass);
|
expect(mockElement).toHaveClass(hiddenClass);
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should add the ${hiddenClass} class to all provided elements`, () => {
|
it(`should add the ${hiddenClass} class to all provided elements`, () => {
|
||||||
|
@ -129,9 +129,9 @@ describe('DOM Utilities', () => {
|
||||||
document.createElement('strong'),
|
document.createElement('strong'),
|
||||||
];
|
];
|
||||||
hideEl(mockElements);
|
hideEl(mockElements);
|
||||||
expect(mockElements[0]).to.have.class(hiddenClass);
|
expect(mockElements[0]).toHaveClass(hiddenClass);
|
||||||
expect(mockElements[1]).to.have.class(hiddenClass);
|
expect(mockElements[1]).toHaveClass(hiddenClass);
|
||||||
expect(mockElements[2]).to.have.class(hiddenClass);
|
expect(mockElements[2]).toHaveClass(hiddenClass);
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should add the ${hiddenClass} class to elements provided in multiple arrays`, () => {
|
it(`should add the ${hiddenClass} class to elements provided in multiple arrays`, () => {
|
||||||
|
@ -144,10 +144,10 @@ describe('DOM Utilities', () => {
|
||||||
document.createElement('em'),
|
document.createElement('em'),
|
||||||
];
|
];
|
||||||
hideEl(mockElements1, mockElements2);
|
hideEl(mockElements1, mockElements2);
|
||||||
expect(mockElements1[0]).to.have.class(hiddenClass);
|
expect(mockElements1[0]).toHaveClass(hiddenClass);
|
||||||
expect(mockElements1[1]).to.have.class(hiddenClass);
|
expect(mockElements1[1]).toHaveClass(hiddenClass);
|
||||||
expect(mockElements2[0]).to.have.class(hiddenClass);
|
expect(mockElements2[0]).toHaveClass(hiddenClass);
|
||||||
expect(mockElements2[1]).to.have.class(hiddenClass);
|
expect(mockElements2[1]).toHaveClass(hiddenClass);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -155,7 +155,7 @@ describe('DOM Utilities', () => {
|
||||||
it('should set the disabled attribute to true', () => {
|
it('should set the disabled attribute to true', () => {
|
||||||
const mockElement = document.createElement('button');
|
const mockElement = document.createElement('button');
|
||||||
disableEl(mockElement);
|
disableEl(mockElement);
|
||||||
expect(mockElement).to.have.property('disabled', true);
|
expect(mockElement).toBeDisabled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set the disabled attribute to true on all provided elements', () => {
|
it('should set the disabled attribute to true on all provided elements', () => {
|
||||||
|
@ -164,8 +164,8 @@ describe('DOM Utilities', () => {
|
||||||
document.createElement('button'),
|
document.createElement('button'),
|
||||||
];
|
];
|
||||||
disableEl(mockElements);
|
disableEl(mockElements);
|
||||||
expect(mockElements[0]).to.have.property('disabled', true);
|
expect(mockElements[0]).toBeDisabled();
|
||||||
expect(mockElements[1]).to.have.property('disabled', true);
|
expect(mockElements[1]).toBeDisabled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set the disabled attribute to true on elements provided in multiple arrays', () => {
|
it('should set the disabled attribute to true on elements provided in multiple arrays', () => {
|
||||||
|
@ -178,10 +178,10 @@ describe('DOM Utilities', () => {
|
||||||
document.createElement('button'),
|
document.createElement('button'),
|
||||||
];
|
];
|
||||||
disableEl(mockElements1, mockElements2);
|
disableEl(mockElements1, mockElements2);
|
||||||
expect(mockElements1[0]).to.have.property('disabled', true);
|
expect(mockElements1[0]).toBeDisabled();
|
||||||
expect(mockElements1[1]).to.have.property('disabled', true);
|
expect(mockElements1[1]).toBeDisabled();
|
||||||
expect(mockElements2[0]).to.have.property('disabled', true);
|
expect(mockElements2[0]).toBeDisabled();
|
||||||
expect(mockElements2[1]).to.have.property('disabled', true);
|
expect(mockElements2[1]).toBeDisabled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -189,7 +189,7 @@ describe('DOM Utilities', () => {
|
||||||
it('should set the disabled attribute to false', () => {
|
it('should set the disabled attribute to false', () => {
|
||||||
const mockElement = document.createElement('button');
|
const mockElement = document.createElement('button');
|
||||||
enableEl(mockElement);
|
enableEl(mockElement);
|
||||||
expect(mockElement).to.have.property('disabled', false);
|
expect(mockElement).toBeEnabled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set the disabled attribute to false on all provided elements', () => {
|
it('should set the disabled attribute to false on all provided elements', () => {
|
||||||
|
@ -198,8 +198,8 @@ describe('DOM Utilities', () => {
|
||||||
document.createElement('button'),
|
document.createElement('button'),
|
||||||
];
|
];
|
||||||
enableEl(mockElements);
|
enableEl(mockElements);
|
||||||
expect(mockElements[0]).to.have.property('disabled', false);
|
expect(mockElements[0]).toBeEnabled();
|
||||||
expect(mockElements[1]).to.have.property('disabled', false);
|
expect(mockElements[1]).toBeEnabled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set the disabled attribute to false on elements provided in multiple arrays', () => {
|
it('should set the disabled attribute to false on elements provided in multiple arrays', () => {
|
||||||
|
@ -212,10 +212,10 @@ describe('DOM Utilities', () => {
|
||||||
document.createElement('button'),
|
document.createElement('button'),
|
||||||
];
|
];
|
||||||
enableEl(mockElements1, mockElements2);
|
enableEl(mockElements1, mockElements2);
|
||||||
expect(mockElements1[0]).to.have.property('disabled', false);
|
expect(mockElements1[0]).toBeEnabled();
|
||||||
expect(mockElements1[1]).to.have.property('disabled', false);
|
expect(mockElements1[1]).toBeEnabled();
|
||||||
expect(mockElements2[0]).to.have.property('disabled', false);
|
expect(mockElements2[0]).toBeEnabled();
|
||||||
expect(mockElements2[1]).to.have.property('disabled', false);
|
expect(mockElements2[1]).toBeEnabled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -223,11 +223,11 @@ describe('DOM Utilities', () => {
|
||||||
it(`should toggle the ${hiddenClass} class on the provided element`, () => {
|
it(`should toggle the ${hiddenClass} class on the provided element`, () => {
|
||||||
const mockVisibleElement = document.createElement('div');
|
const mockVisibleElement = document.createElement('div');
|
||||||
toggleEl(mockVisibleElement);
|
toggleEl(mockVisibleElement);
|
||||||
expect(mockVisibleElement).to.have.class(hiddenClass);
|
expect(mockVisibleElement).toHaveClass(hiddenClass);
|
||||||
|
|
||||||
const mockHiddenElement = createHiddenElement('div');
|
const mockHiddenElement = createHiddenElement('div');
|
||||||
toggleEl(mockHiddenElement);
|
toggleEl(mockHiddenElement);
|
||||||
expect(mockHiddenElement).not.to.have.class(hiddenClass);
|
expect(mockHiddenElement).not.toHaveClass(hiddenClass);
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should toggle the ${hiddenClass} class on all provided elements`, () => {
|
it(`should toggle the ${hiddenClass} class on all provided elements`, () => {
|
||||||
|
@ -238,10 +238,10 @@ describe('DOM Utilities', () => {
|
||||||
createHiddenElement('em'),
|
createHiddenElement('em'),
|
||||||
];
|
];
|
||||||
toggleEl(mockElements);
|
toggleEl(mockElements);
|
||||||
expect(mockElements[0]).to.have.class(hiddenClass);
|
expect(mockElements[0]).toHaveClass(hiddenClass);
|
||||||
expect(mockElements[1]).not.to.have.class(hiddenClass);
|
expect(mockElements[1]).not.toHaveClass(hiddenClass);
|
||||||
expect(mockElements[2]).to.have.class(hiddenClass);
|
expect(mockElements[2]).toHaveClass(hiddenClass);
|
||||||
expect(mockElements[3]).not.to.have.class(hiddenClass);
|
expect(mockElements[3]).not.toHaveClass(hiddenClass);
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should toggle the ${hiddenClass} class on elements provided in multiple arrays`, () => {
|
it(`should toggle the ${hiddenClass} class on elements provided in multiple arrays`, () => {
|
||||||
|
@ -254,10 +254,10 @@ describe('DOM Utilities', () => {
|
||||||
document.createElement('em'),
|
document.createElement('em'),
|
||||||
];
|
];
|
||||||
toggleEl(mockElements1, mockElements2);
|
toggleEl(mockElements1, mockElements2);
|
||||||
expect(mockElements1[0]).not.to.have.class(hiddenClass);
|
expect(mockElements1[0]).not.toHaveClass(hiddenClass);
|
||||||
expect(mockElements1[1]).to.have.class(hiddenClass);
|
expect(mockElements1[1]).toHaveClass(hiddenClass);
|
||||||
expect(mockElements2[0]).not.to.have.class(hiddenClass);
|
expect(mockElements2[0]).not.toHaveClass(hiddenClass);
|
||||||
expect(mockElements2[1]).to.have.class(hiddenClass);
|
expect(mockElements2[1]).toHaveClass(hiddenClass);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -361,8 +361,8 @@ describe('DOM Utilities', () => {
|
||||||
const mockClassTwo = 'class-two';
|
const mockClassTwo = 'class-two';
|
||||||
const el = makeEl('p', { className: `${mockClassOne} ${mockClassTwo}` });
|
const el = makeEl('p', { className: `${mockClassOne} ${mockClassTwo}` });
|
||||||
expect(el.nodeName).toEqual('P');
|
expect(el.nodeName).toEqual('P');
|
||||||
expect(el).to.have.class(mockClassOne);
|
expect(el).toHaveClass(mockClassOne);
|
||||||
expect(el).to.have.class(mockClassTwo);
|
expect(el).toHaveClass(mockClassTwo);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ describe('Draggable Utilities', () => {
|
||||||
|
|
||||||
fireEvent(mockDraggable, mockEvent);
|
fireEvent(mockDraggable, mockEvent);
|
||||||
|
|
||||||
expect(mockDraggable).to.have.class(draggingClass);
|
expect(mockDraggable).toHaveClass(draggingClass);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add dummy data to the dragstart event if it\'s empty', () => {
|
it('should add dummy data to the dragstart event if it\'s empty', () => {
|
||||||
|
@ -147,7 +147,7 @@ describe('Draggable Utilities', () => {
|
||||||
|
|
||||||
fireEvent(mockDraggable, mockEvent);
|
fireEvent(mockDraggable, mockEvent);
|
||||||
|
|
||||||
expect(mockDraggable).to.have.class(dragOverClass);
|
expect(mockDraggable).toHaveClass(dragOverClass);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -160,7 +160,7 @@ describe('Draggable Utilities', () => {
|
||||||
|
|
||||||
fireEvent(mockDraggable, mockEvent);
|
fireEvent(mockDraggable, mockEvent);
|
||||||
|
|
||||||
expect(mockDraggable).not.to.have.class(dragOverClass);
|
expect(mockDraggable).not.toHaveClass(dragOverClass);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -171,13 +171,13 @@ describe('Draggable Utilities', () => {
|
||||||
const mockStartEvent = createDragEvent('dragstart');
|
const mockStartEvent = createDragEvent('dragstart');
|
||||||
fireEvent(mockDraggable, mockStartEvent);
|
fireEvent(mockDraggable, mockStartEvent);
|
||||||
|
|
||||||
expect(mockDraggable).to.have.class(draggingClass);
|
expect(mockDraggable).toHaveClass(draggingClass);
|
||||||
|
|
||||||
const mockDropEvent = createDragEvent('drop');
|
const mockDropEvent = createDragEvent('drop');
|
||||||
fireEvent(mockDraggable, mockDropEvent);
|
fireEvent(mockDraggable, mockDropEvent);
|
||||||
|
|
||||||
expect(mockDropEvent.defaultPrevented).toBe(true);
|
expect(mockDropEvent.defaultPrevented).toBe(true);
|
||||||
expect(mockDraggable).not.to.have.class(draggingClass);
|
expect(mockDraggable).not.toHaveClass(draggingClass);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should cancel the event and insert source before target if dropped on left side', () => {
|
it('should cancel the event and insert source before target if dropped on left side', () => {
|
||||||
|
@ -189,7 +189,7 @@ describe('Draggable Utilities', () => {
|
||||||
const mockStartEvent = createDragEvent('dragstart');
|
const mockStartEvent = createDragEvent('dragstart');
|
||||||
fireEvent(mockSecondDraggable, mockStartEvent);
|
fireEvent(mockSecondDraggable, mockStartEvent);
|
||||||
|
|
||||||
expect(mockSecondDraggable).to.have.class(draggingClass);
|
expect(mockSecondDraggable).toHaveClass(draggingClass);
|
||||||
|
|
||||||
const mockDropEvent = createDragEvent('drop');
|
const mockDropEvent = createDragEvent('drop');
|
||||||
Object.assign(mockDropEvent, { clientX: 124 });
|
Object.assign(mockDropEvent, { clientX: 124 });
|
||||||
|
@ -201,7 +201,7 @@ describe('Draggable Utilities', () => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
expect(mockDropEvent.defaultPrevented).toBe(true);
|
expect(mockDropEvent.defaultPrevented).toBe(true);
|
||||||
expect(mockSecondDraggable).not.to.have.class(draggingClass);
|
expect(mockSecondDraggable).not.toHaveClass(draggingClass);
|
||||||
expect(mockSecondDraggable.nextElementSibling).toBe(mockDraggable);
|
expect(mockSecondDraggable.nextElementSibling).toBe(mockDraggable);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
@ -218,7 +218,7 @@ describe('Draggable Utilities', () => {
|
||||||
const mockStartEvent = createDragEvent('dragstart');
|
const mockStartEvent = createDragEvent('dragstart');
|
||||||
fireEvent(mockSecondDraggable, mockStartEvent);
|
fireEvent(mockSecondDraggable, mockStartEvent);
|
||||||
|
|
||||||
expect(mockSecondDraggable).to.have.class(draggingClass);
|
expect(mockSecondDraggable).toHaveClass(draggingClass);
|
||||||
|
|
||||||
const mockDropEvent = createDragEvent('drop');
|
const mockDropEvent = createDragEvent('drop');
|
||||||
Object.assign(mockDropEvent, { clientX: 125 });
|
Object.assign(mockDropEvent, { clientX: 125 });
|
||||||
|
@ -230,7 +230,7 @@ describe('Draggable Utilities', () => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
expect(mockDropEvent.defaultPrevented).toBe(true);
|
expect(mockDropEvent.defaultPrevented).toBe(true);
|
||||||
expect(mockSecondDraggable).not.to.have.class(draggingClass);
|
expect(mockSecondDraggable).not.toHaveClass(draggingClass);
|
||||||
expect(mockDraggable.nextElementSibling).toBe(mockSecondDraggable);
|
expect(mockDraggable.nextElementSibling).toBe(mockSecondDraggable);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
@ -260,7 +260,7 @@ describe('Draggable Utilities', () => {
|
||||||
const mockStartEvent = createDragEvent('dragstart');
|
const mockStartEvent = createDragEvent('dragstart');
|
||||||
fireEvent(mockDraggable, mockStartEvent);
|
fireEvent(mockDraggable, mockStartEvent);
|
||||||
|
|
||||||
expect(mockDraggable).to.have.class(draggingClass);
|
expect(mockDraggable).toHaveClass(draggingClass);
|
||||||
|
|
||||||
const mockOverElement = createDraggableElement();
|
const mockOverElement = createDraggableElement();
|
||||||
mockOverElement.classList.add(dragOverClass);
|
mockOverElement.classList.add(dragOverClass);
|
||||||
|
@ -271,8 +271,8 @@ describe('Draggable Utilities', () => {
|
||||||
const mockDropEvent = createDragEvent('dragend');
|
const mockDropEvent = createDragEvent('dragend');
|
||||||
fireEvent(mockDraggable, mockDropEvent);
|
fireEvent(mockDraggable, mockDropEvent);
|
||||||
|
|
||||||
expect(mockDraggable).not.to.have.class(draggingClass);
|
expect(mockDraggable).not.toHaveClass(draggingClass);
|
||||||
expect(mockOverElement).not.to.have.class(dragOverClass);
|
expect(mockOverElement).not.toHaveClass(dragOverClass);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -146,7 +146,7 @@ describe('Image utils', () => {
|
||||||
|
|
||||||
const result = showThumb(mockElement);
|
const result = showThumb(mockElement);
|
||||||
|
|
||||||
expect(mockImage).to.have.class(hiddenClass);
|
expect(mockImage).toHaveClass(hiddenClass);
|
||||||
expect(mockVideo.children).toHaveLength(2);
|
expect(mockVideo.children).toHaveLength(2);
|
||||||
|
|
||||||
const webmSourceElement = mockVideo.children[0];
|
const webmSourceElement = mockVideo.children[0];
|
||||||
|
@ -160,10 +160,10 @@ describe('Image utils', () => {
|
||||||
expect(mp4SourceElement.getAttribute('type')).toEqual('video/mp4');
|
expect(mp4SourceElement.getAttribute('type')).toEqual('video/mp4');
|
||||||
expect(mp4SourceElement.getAttribute('src')).toEqual(webmSource.replace('webm', 'mp4'));
|
expect(mp4SourceElement.getAttribute('src')).toEqual(webmSource.replace('webm', 'mp4'));
|
||||||
|
|
||||||
expect(mockVideo).not.to.have.class(hiddenClass);
|
expect(mockVideo).not.toHaveClass(hiddenClass);
|
||||||
expect(playSpy).toHaveBeenCalledTimes(1);
|
expect(playSpy).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
expect(mockSpoilerOverlay).to.have.class(hiddenClass);
|
expect(mockSpoilerOverlay).toHaveClass(hiddenClass);
|
||||||
|
|
||||||
expect(result).toBe(true);
|
expect(result).toBe(true);
|
||||||
});
|
});
|
||||||
|
@ -238,7 +238,7 @@ describe('Image utils', () => {
|
||||||
expect(mockSizeImage.src).toBe(mockSizeUrls[mockSize]);
|
expect(mockSizeImage.src).toBe(mockSizeUrls[mockSize]);
|
||||||
expect(mockSizeImage.srcset).toBe('');
|
expect(mockSizeImage.srcset).toBe('');
|
||||||
|
|
||||||
expect(mockSpoilerOverlay).to.have.class(hiddenClass);
|
expect(mockSpoilerOverlay).toHaveClass(hiddenClass);
|
||||||
expect(result).toBe(true);
|
expect(result).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -255,7 +255,7 @@ describe('Image utils', () => {
|
||||||
expect(mockSizeImage.src).toBe(mockSizeUrls[mockSize]);
|
expect(mockSizeImage.src).toBe(mockSizeUrls[mockSize]);
|
||||||
expect(mockSizeImage.srcset).toBe('');
|
expect(mockSizeImage.srcset).toBe('');
|
||||||
|
|
||||||
expect(mockSpoilerOverlay).to.have.class(hiddenClass);
|
expect(mockSpoilerOverlay).toHaveClass(hiddenClass);
|
||||||
expect(result).toBe(true);
|
expect(result).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -272,8 +272,8 @@ describe('Image utils', () => {
|
||||||
expect(mockSizeImage.src).toBe(mockSizeUrls[mockSize].replace('webm', 'gif'));
|
expect(mockSizeImage.src).toBe(mockSizeUrls[mockSize].replace('webm', 'gif'));
|
||||||
expect(mockSizeImage.srcset).toBe('');
|
expect(mockSizeImage.srcset).toBe('');
|
||||||
|
|
||||||
expect(mockSpoilerOverlay).not.to.have.class(hiddenClass);
|
expect(mockSpoilerOverlay).not.toHaveClass(hiddenClass);
|
||||||
expect(mockSpoilerOverlay).to.have.text('WebM');
|
expect(mockSpoilerOverlay).toHaveTextContent('WebM');
|
||||||
|
|
||||||
expect(result).toBe(true);
|
expect(result).toBe(true);
|
||||||
});
|
});
|
||||||
|
@ -296,7 +296,7 @@ describe('Image utils', () => {
|
||||||
expect(mockSizeImage.srcset).toContain(`${mockSizeUrls[size]} 1x`);
|
expect(mockSizeImage.srcset).toContain(`${mockSizeUrls[size]} 1x`);
|
||||||
expect(mockSizeImage.srcset).toContain(`${mockSizeUrls[x2size]} 2x`);
|
expect(mockSizeImage.srcset).toContain(`${mockSizeUrls[x2size]} 2x`);
|
||||||
|
|
||||||
expect(mockSpoilerOverlay).to.have.class(hiddenClass);
|
expect(mockSpoilerOverlay).toHaveClass(hiddenClass);
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -323,7 +323,7 @@ describe('Image utils', () => {
|
||||||
expect(mockSizeImage.src).toBe(mockSizeUrls[mockSize]);
|
expect(mockSizeImage.src).toBe(mockSizeUrls[mockSize]);
|
||||||
expect(mockSizeImage.srcset).toBe('');
|
expect(mockSizeImage.srcset).toBe('');
|
||||||
|
|
||||||
expect(mockSpoilerOverlay).to.have.class(hiddenClass);
|
expect(mockSpoilerOverlay).toHaveClass(hiddenClass);
|
||||||
expect(result).toBe(true);
|
expect(result).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -364,9 +364,9 @@ describe('Image utils', () => {
|
||||||
|
|
||||||
showBlock(mockElement);
|
showBlock(mockElement);
|
||||||
|
|
||||||
expect(mockFilteredImageElement).to.have.class(hiddenClass);
|
expect(mockFilteredImageElement).toHaveClass(hiddenClass);
|
||||||
expect(mockShowElement).not.to.have.class(hiddenClass);
|
expect(mockShowElement).not.toHaveClass(hiddenClass);
|
||||||
expect(mockShowElement).to.have.class(spoilerPendingClass);
|
expect(mockShowElement).toHaveClass(spoilerPendingClass);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not throw if image-filtered element is missing', () => {
|
it('should not throw if image-filtered element is missing', () => {
|
||||||
|
@ -416,7 +416,7 @@ describe('Image utils', () => {
|
||||||
expect(querySelectorSpy).toHaveBeenNthCalledWith(2, 'video');
|
expect(querySelectorSpy).toHaveBeenNthCalledWith(2, 'video');
|
||||||
expect(querySelectorSpy).toHaveBeenNthCalledWith(3, 'img');
|
expect(querySelectorSpy).toHaveBeenNthCalledWith(3, 'img');
|
||||||
expect(querySelectorSpy).toHaveBeenNthCalledWith(4, `.${spoilerOverlayClass}`);
|
expect(querySelectorSpy).toHaveBeenNthCalledWith(4, `.${spoilerOverlayClass}`);
|
||||||
expect(mockVideo).not.to.have.class(hiddenClass);
|
expect(mockVideo).not.toHaveClass(hiddenClass);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
querySelectorSpy.mockRestore();
|
querySelectorSpy.mockRestore();
|
||||||
|
@ -439,11 +439,11 @@ describe('Image utils', () => {
|
||||||
hideThumb(mockElement, mockSpoilerUri, mockSpoilerReason);
|
hideThumb(mockElement, mockSpoilerUri, mockSpoilerReason);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
expect(mockImage).not.to.have.class(hiddenClass);
|
expect(mockImage).not.toHaveClass(hiddenClass);
|
||||||
expect(mockImage).to.have.attribute('src', mockSpoilerUri);
|
expect(mockImage).toHaveAttribute('src', mockSpoilerUri);
|
||||||
expect(mockOverlay).to.have.text(mockSpoilerReason);
|
expect(mockOverlay).toHaveTextContent(mockSpoilerReason);
|
||||||
expect(mockVideo).not.to.have.descendants('*');
|
expect(mockVideo).toBeEmptyDOMElement();
|
||||||
expect(mockVideo).to.have.class(hiddenClass);
|
expect(mockVideo).toHaveClass(hiddenClass);
|
||||||
expect(pauseSpy).toHaveBeenCalled();
|
expect(pauseSpy).toHaveBeenCalled();
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
@ -488,10 +488,10 @@ describe('Image utils', () => {
|
||||||
|
|
||||||
hideThumb(mockElement, mockSpoilerUri, mockSpoilerReason);
|
hideThumb(mockElement, mockSpoilerUri, mockSpoilerReason);
|
||||||
|
|
||||||
expect(mockImage).to.have.attribute('srcset', '');
|
expect(mockImage).toHaveAttribute('srcset', '');
|
||||||
expect(mockImage).to.have.attribute('src', mockSpoilerUri);
|
expect(mockImage).toHaveAttribute('src', mockSpoilerUri);
|
||||||
expect(mockOverlay).to.contain.html(mockSpoilerReason);
|
expect(mockOverlay).toContainHTML(mockSpoilerReason);
|
||||||
expect(mockOverlay).not.to.have.class(hiddenClass);
|
expect(mockOverlay).not.toHaveClass(hiddenClass);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -503,9 +503,9 @@ describe('Image utils', () => {
|
||||||
spoilerThumb(mockElement, mockSpoilerUri, mockSpoilerReason);
|
spoilerThumb(mockElement, mockSpoilerUri, mockSpoilerReason);
|
||||||
|
|
||||||
// Element should be hidden by the call
|
// Element should be hidden by the call
|
||||||
expect(mockSizeImage).to.have.attribute('src', mockSpoilerUri);
|
expect(mockSizeImage).toHaveAttribute('src', mockSpoilerUri);
|
||||||
expect(mockSpoilerOverlay).not.to.have.class(hiddenClass);
|
expect(mockSpoilerOverlay).not.toHaveClass(hiddenClass);
|
||||||
expect(mockSpoilerOverlay).to.contain.html(mockSpoilerReason);
|
expect(mockSpoilerOverlay).toContainHTML(mockSpoilerReason);
|
||||||
|
|
||||||
// If addEventListener calls are not expected, bail
|
// If addEventListener calls are not expected, bail
|
||||||
if (!handlers) {
|
if (!handlers) {
|
||||||
|
@ -526,8 +526,8 @@ describe('Image utils', () => {
|
||||||
if (firstHandler === 'click') {
|
if (firstHandler === 'click') {
|
||||||
expect(clickEvent.defaultPrevented).toBe(true);
|
expect(clickEvent.defaultPrevented).toBe(true);
|
||||||
}
|
}
|
||||||
expect(mockSizeImage).not.to.have.attribute('src', mockSpoilerUri);
|
expect(mockSizeImage).not.toHaveAttribute('src', mockSpoilerUri);
|
||||||
expect(mockSpoilerOverlay).to.have.class(hiddenClass);
|
expect(mockSpoilerOverlay).toHaveClass(hiddenClass);
|
||||||
|
|
||||||
if (firstHandler === 'click') {
|
if (firstHandler === 'click') {
|
||||||
// Second attempt to click a shown spoiler should not cause default prevention
|
// Second attempt to click a shown spoiler should not cause default prevention
|
||||||
|
@ -539,9 +539,9 @@ describe('Image utils', () => {
|
||||||
// Moving the mouse away should hide the image and show the overlay again
|
// Moving the mouse away should hide the image and show the overlay again
|
||||||
const mouseLeaveEvent = createEvent.mouseLeave(mockElement);
|
const mouseLeaveEvent = createEvent.mouseLeave(mockElement);
|
||||||
fireEvent(mockElement, mouseLeaveEvent);
|
fireEvent(mockElement, mouseLeaveEvent);
|
||||||
expect(mockSizeImage).to.have.attribute('src', mockSpoilerUri);
|
expect(mockSizeImage).toHaveAttribute('src', mockSpoilerUri);
|
||||||
expect(mockSpoilerOverlay).not.to.have.class(hiddenClass);
|
expect(mockSpoilerOverlay).not.toHaveClass(hiddenClass);
|
||||||
expect(mockSpoilerOverlay).to.contain.html(mockSpoilerReason);
|
expect(mockSpoilerOverlay).toContainHTML(mockSpoilerReason);
|
||||||
};
|
};
|
||||||
let lastSpoilerType: SpoilerType;
|
let lastSpoilerType: SpoilerType;
|
||||||
|
|
||||||
|
@ -618,10 +618,10 @@ describe('Image utils', () => {
|
||||||
|
|
||||||
spoilerBlock(mockElement, mockSpoilerUri, mockSpoilerReason);
|
spoilerBlock(mockElement, mockSpoilerUri, mockSpoilerReason);
|
||||||
|
|
||||||
expect(mockImage).to.have.attribute('src', mockSpoilerUri);
|
expect(mockImage).toHaveAttribute('src', mockSpoilerUri);
|
||||||
expect(mockExplanation).to.contain.html(mockSpoilerReason);
|
expect(mockExplanation).toContainHTML(mockSpoilerReason);
|
||||||
expect(mockImageShow).to.have.class(hiddenClass);
|
expect(mockImageShow).toHaveClass(hiddenClass);
|
||||||
expect(mockImageFiltered).not.to.have.class(hiddenClass);
|
expect(mockImageFiltered).not.toHaveClass(hiddenClass);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not throw if image-filtered element is missing', () => {
|
it('should not throw if image-filtered element is missing', () => {
|
||||||
|
|
482
assets/package-lock.json
generated
482
assets/package-lock.json
generated
|
@ -23,16 +23,22 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@testing-library/dom": "^10.1.0",
|
"@testing-library/dom": "^10.1.0",
|
||||||
|
"@testing-library/jest-dom": "^6.4.2",
|
||||||
"@types/chai-dom": "^1.11.3",
|
"@types/chai-dom": "^1.11.3",
|
||||||
"@vitest/coverage-v8": "^1.5.3",
|
"@vitest/coverage-v8": "^1.5.3",
|
||||||
"chai": "^4.4",
|
"chai": "^5",
|
||||||
"chai-dom": "^1.12.0",
|
|
||||||
"eslint-plugin-vitest": "^0.5.4",
|
"eslint-plugin-vitest": "^0.5.4",
|
||||||
"jsdom": "^24.0.0",
|
"jsdom": "^24.0.0",
|
||||||
"vitest": "^1.5.3",
|
"vitest": "^1.5.3",
|
||||||
"vitest-fetch-mock": "^0.2.2"
|
"vitest-fetch-mock": "^0.2.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@adobe/css-tools": {
|
||||||
|
"version": "4.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.3.tgz",
|
||||||
|
"integrity": "sha512-rE0Pygv0sEZ4vBWHlAgJLGDU7Pm8xoO6p3wsEceb7GYAjScrOHpEo8KK/eVkAcnSM+slAEtXjA2JpdjLp4fJQQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@ampproject/remapping": {
|
"node_modules/@ampproject/remapping": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
|
||||||
|
@ -1229,6 +1235,70 @@
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@testing-library/jest-dom": {
|
||||||
|
"version": "6.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.4.2.tgz",
|
||||||
|
"integrity": "sha512-CzqH0AFymEMG48CpzXFriYYkOjk6ZGPCLMhW9e9jg3KMCn5OfJecF8GtGW7yGfR/IgCe3SX8BSwjdzI6BBbZLw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@adobe/css-tools": "^4.3.2",
|
||||||
|
"@babel/runtime": "^7.9.2",
|
||||||
|
"aria-query": "^5.0.0",
|
||||||
|
"chalk": "^3.0.0",
|
||||||
|
"css.escape": "^1.5.1",
|
||||||
|
"dom-accessibility-api": "^0.6.3",
|
||||||
|
"lodash": "^4.17.15",
|
||||||
|
"redent": "^3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14",
|
||||||
|
"npm": ">=6",
|
||||||
|
"yarn": ">=1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@jest/globals": ">= 28",
|
||||||
|
"@types/bun": "latest",
|
||||||
|
"@types/jest": ">= 28",
|
||||||
|
"jest": ">= 28",
|
||||||
|
"vitest": ">= 0.32"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@jest/globals": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/bun": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/jest": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"jest": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"vitest": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@testing-library/jest-dom/node_modules/chalk": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-styles": "^4.1.0",
|
||||||
|
"supports-color": "^7.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": {
|
||||||
|
"version": "0.6.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz",
|
||||||
|
"integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@tootallnate/once": {
|
"node_modules/@tootallnate/once": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz",
|
||||||
|
@ -1576,6 +1646,66 @@
|
||||||
"url": "https://opencollective.com/vitest"
|
"url": "https://opencollective.com/vitest"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@vitest/expect/node_modules/assertion-error": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@vitest/expect/node_modules/chai": {
|
||||||
|
"version": "4.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz",
|
||||||
|
"integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"assertion-error": "^1.1.0",
|
||||||
|
"check-error": "^1.0.3",
|
||||||
|
"deep-eql": "^4.1.3",
|
||||||
|
"get-func-name": "^2.0.2",
|
||||||
|
"loupe": "^2.3.6",
|
||||||
|
"pathval": "^1.1.1",
|
||||||
|
"type-detect": "^4.0.8"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@vitest/expect/node_modules/check-error": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"get-func-name": "^2.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@vitest/expect/node_modules/deep-eql": {
|
||||||
|
"version": "4.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz",
|
||||||
|
"integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"type-detect": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@vitest/expect/node_modules/pathval": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@vitest/runner": {
|
"node_modules/@vitest/runner": {
|
||||||
"version": "1.5.3",
|
"version": "1.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.5.3.tgz",
|
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.5.3.tgz",
|
||||||
|
@ -1836,12 +1966,12 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/assertion-error": {
|
"node_modules/assertion-error": {
|
||||||
"version": "1.1.0",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz",
|
||||||
"integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
|
"integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "*"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/asynckit": {
|
"node_modules/asynckit": {
|
||||||
|
@ -1985,33 +2115,28 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/chai": {
|
"node_modules/chai": {
|
||||||
"version": "4.4.1",
|
"version": "5.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/chai/-/chai-5.1.0.tgz",
|
||||||
"integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==",
|
"integrity": "sha512-kDZ7MZyM6Q1DhR9jy7dalKohXQ2yrlXkk59CR52aRKxJrobmlBNqnFQxX9xOX8w+4mz8SYlKJa/7D7ddltFXCw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"assertion-error": "^1.1.0",
|
"assertion-error": "^2.0.1",
|
||||||
"check-error": "^1.0.3",
|
"check-error": "^2.0.0",
|
||||||
"deep-eql": "^4.1.3",
|
"deep-eql": "^5.0.1",
|
||||||
"get-func-name": "^2.0.2",
|
"loupe": "^3.1.0",
|
||||||
"loupe": "^2.3.6",
|
"pathval": "^2.0.0"
|
||||||
"pathval": "^1.1.1",
|
|
||||||
"type-detect": "^4.0.8"
|
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=4"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/chai-dom": {
|
"node_modules/chai/node_modules/loupe": {
|
||||||
"version": "1.12.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/chai-dom/-/chai-dom-1.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.0.tgz",
|
||||||
"integrity": "sha512-pLP8h6IBR8z1AdeQ+EMcJ7dXPdsax/1Q7gdGZjsnAmSBl3/gItQUYSCo32br1qOy4SlcBjvqId7ilAf3uJ2K1w==",
|
"integrity": "sha512-qKl+FrLXUhFuHUoDJG7f8P8gEMHq9NFS0c6ghXG1J0rldmZFQZoNVv/vyirE9qwCIhWZDsvEFd1sbFu3GvRQFg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"dependencies": {
|
||||||
"node": ">= 0.12.0"
|
"get-func-name": "^2.0.1"
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"chai": ">= 3"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/chalk": {
|
"node_modules/chalk": {
|
||||||
|
@ -2030,15 +2155,12 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/check-error": {
|
"node_modules/check-error": {
|
||||||
"version": "1.0.3",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/check-error/-/check-error-2.0.0.tgz",
|
||||||
"integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==",
|
"integrity": "sha512-tjLAOBHKVxtPoHe/SA7kNOMvhCRdCJ3vETdeY0RuAc9popf+hyaSV6ZEg9hr4cpWF7jmo/JSWEnLDrnijS9Tog==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
|
||||||
"get-func-name": "^2.0.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "*"
|
"node": ">= 16"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/ci-info": {
|
"node_modules/ci-info": {
|
||||||
|
@ -2132,6 +2254,12 @@
|
||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/css.escape": {
|
||||||
|
"version": "1.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz",
|
||||||
|
"integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/cssom": {
|
"node_modules/cssom": {
|
||||||
"version": "0.5.0",
|
"version": "0.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz",
|
||||||
|
@ -2184,13 +2312,10 @@
|
||||||
"integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA=="
|
"integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA=="
|
||||||
},
|
},
|
||||||
"node_modules/deep-eql": {
|
"node_modules/deep-eql": {
|
||||||
"version": "4.1.3",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.1.tgz",
|
||||||
"integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==",
|
"integrity": "sha512-nwQCf6ne2gez3o1MxWifqkciwt0zhl0LO1/UwVu4uMBuPmflWM4oQ70XMqHqnBJA+nhzncaqL9HVL6KkHJ28lw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
|
||||||
"type-detect": "^4.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
|
@ -2267,9 +2392,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/electron-to-chromium": {
|
"node_modules/electron-to-chromium": {
|
||||||
"version": "1.4.752",
|
"version": "1.4.751",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.752.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.751.tgz",
|
||||||
"integrity": "sha512-P3QJreYI/AUTcfBVrC4zy9KvnZWekViThgQMX/VpJ+IsOBbcX5JFpORM4qWapwWQ+agb2nYAOyn/4PMXOk0m2Q=="
|
"integrity": "sha512-2DEPi++qa89SMGRhufWTiLmzqyuGmNF3SK4+PQetW1JKiZdEpF4XQonJXJCzyuYSA6mauiMhbyVhqYAP45Hvfw=="
|
||||||
},
|
},
|
||||||
"node_modules/entities": {
|
"node_modules/entities": {
|
||||||
"version": "4.5.0",
|
"version": "4.5.0",
|
||||||
|
@ -2944,6 +3069,15 @@
|
||||||
"node": ">=0.8.19"
|
"node": ">=0.8.19"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/indent-string": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/inflight": {
|
"node_modules/inflight": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||||
|
@ -3470,6 +3604,12 @@
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/lodash": {
|
||||||
|
"version": "4.17.21",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||||
|
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/lodash.merge": {
|
"node_modules/lodash.merge": {
|
||||||
"version": "4.6.2",
|
"version": "4.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
||||||
|
@ -3584,16 +3724,13 @@
|
||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mimic-fn": {
|
"node_modules/min-indent": {
|
||||||
"version": "4.0.0",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
|
||||||
"integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==",
|
"integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=4"
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/minimatch": {
|
"node_modules/minimatch": {
|
||||||
|
@ -3869,12 +4006,12 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/pathval": {
|
"node_modules/pathval": {
|
||||||
"version": "1.1.1",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz",
|
||||||
"integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==",
|
"integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "*"
|
"node": ">= 14.16"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/picocolors": {
|
"node_modules/picocolors": {
|
||||||
|
@ -4073,6 +4210,30 @@
|
||||||
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
|
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/readdirp": {
|
||||||
|
"version": "3.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||||
|
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
||||||
|
"dependencies": {
|
||||||
|
"picomatch": "^2.2.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/redent": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"indent-string": "^4.0.0",
|
||||||
|
"strip-indent": "^3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/regenerator-runtime": {
|
"node_modules/regenerator-runtime": {
|
||||||
"version": "0.14.1",
|
"version": "0.14.1",
|
||||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
|
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
|
||||||
|
@ -4311,16 +4472,16 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/strip-final-newline": {
|
"node_modules/strip-indent": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
|
||||||
"integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==",
|
"integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"dependencies": {
|
||||||
"node": ">=12"
|
"min-indent": "^1.0.0"
|
||||||
},
|
},
|
||||||
"funding": {
|
"engines": {
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/strip-json-comments": {
|
"node_modules/strip-json-comments": {
|
||||||
|
@ -4768,6 +4929,200 @@
|
||||||
"vitest": ">=0.16.0"
|
"vitest": ">=0.16.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/vitest/node_modules/assertion-error": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/vitest/node_modules/chai": {
|
||||||
|
"version": "4.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz",
|
||||||
|
"integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"assertion-error": "^1.1.0",
|
||||||
|
"check-error": "^1.0.3",
|
||||||
|
"deep-eql": "^4.1.3",
|
||||||
|
"get-func-name": "^2.0.2",
|
||||||
|
"loupe": "^2.3.6",
|
||||||
|
"pathval": "^1.1.1",
|
||||||
|
"type-detect": "^4.0.8"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/vitest/node_modules/check-error": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"get-func-name": "^2.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/vitest/node_modules/deep-eql": {
|
||||||
|
"version": "4.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz",
|
||||||
|
"integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"type-detect": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/vitest/node_modules/execa": {
|
||||||
|
"version": "8.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz",
|
||||||
|
"integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"cross-spawn": "^7.0.3",
|
||||||
|
"get-stream": "^8.0.1",
|
||||||
|
"human-signals": "^5.0.0",
|
||||||
|
"is-stream": "^3.0.0",
|
||||||
|
"merge-stream": "^2.0.0",
|
||||||
|
"npm-run-path": "^5.1.0",
|
||||||
|
"onetime": "^6.0.0",
|
||||||
|
"signal-exit": "^4.1.0",
|
||||||
|
"strip-final-newline": "^3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.17"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sindresorhus/execa?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/vitest/node_modules/get-stream": {
|
||||||
|
"version": "8.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz",
|
||||||
|
"integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/vitest/node_modules/human-signals": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.17.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/vitest/node_modules/is-stream": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/vitest/node_modules/mimic-fn": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/vitest/node_modules/npm-run-path": {
|
||||||
|
"version": "5.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz",
|
||||||
|
"integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"path-key": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/vitest/node_modules/onetime": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"mimic-fn": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/vitest/node_modules/path-key": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/vitest/node_modules/pathval": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/vitest/node_modules/signal-exit": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/vitest/node_modules/strip-final-newline": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/w3c-xmlserializer": {
|
"node_modules/w3c-xmlserializer": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz",
|
||||||
|
@ -4899,11 +5254,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
|
||||||
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw=="
|
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw=="
|
||||||
},
|
},
|
||||||
"node_modules/yallist": {
|
|
||||||
"version": "4.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
|
||||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
|
||||||
},
|
|
||||||
"node_modules/yocto-queue": {
|
"node_modules/yocto-queue": {
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
||||||
|
|
|
@ -28,10 +28,10 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@testing-library/dom": "^10.1.0",
|
"@testing-library/dom": "^10.1.0",
|
||||||
|
"@testing-library/jest-dom": "^6.4.2",
|
||||||
"@types/chai-dom": "^1.11.3",
|
"@types/chai-dom": "^1.11.3",
|
||||||
"@vitest/coverage-v8": "^1.5.3",
|
"@vitest/coverage-v8": "^1.5.3",
|
||||||
"chai": "^4.4",
|
"chai": "^5",
|
||||||
"chai-dom": "^1.12.0",
|
|
||||||
"eslint-plugin-vitest": "^0.5.4",
|
"eslint-plugin-vitest": "^0.5.4",
|
||||||
"jsdom": "^24.0.0",
|
"jsdom": "^24.0.0",
|
||||||
"vitest": "^1.5.3",
|
"vitest": "^1.5.3",
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
import { matchNone } from '../js/query/boolean';
|
import { matchNone } from '../js/query/boolean';
|
||||||
import chai from 'chai';
|
import '@testing-library/jest-dom/vitest';
|
||||||
import chaiDom from 'chai-dom';
|
|
||||||
import { URL } from 'node:url';
|
import { URL } from 'node:url';
|
||||||
import { Blob } from 'node:buffer';
|
import { Blob } from 'node:buffer';
|
||||||
import { fireEvent } from '@testing-library/dom';
|
import { fireEvent } from '@testing-library/dom';
|
||||||
|
|
||||||
chai.use(chaiDom);
|
|
||||||
|
|
||||||
window.booru = {
|
window.booru = {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||||
timeAgo: () => {},
|
timeAgo: () => {},
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"baseUrl": "./js",
|
"baseUrl": "./js",
|
||||||
"target": "ES2020",
|
"target": "ES2016",
|
||||||
"useDefineForClassFields": true,
|
"useDefineForClassFields": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"lib": [
|
"lib": [
|
||||||
"ES2020",
|
"ES2016",
|
||||||
"DOM",
|
"DOM",
|
||||||
"DOM.Iterable"
|
"DOM.Iterable"
|
||||||
],
|
],
|
||||||
|
|
|
@ -37,7 +37,7 @@ export default defineConfig(({ command, mode }: ConfigEnv): UserConfig => {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
build: {
|
build: {
|
||||||
target: 'es2020',
|
target: ['es2016', 'chrome67', 'firefox62', 'edge18', 'safari12'],
|
||||||
outDir: path.resolve(__dirname, '../priv/static'),
|
outDir: path.resolve(__dirname, '../priv/static'),
|
||||||
emptyOutDir: false,
|
emptyOutDir: false,
|
||||||
sourcemap: isDev,
|
sourcemap: isDev,
|
||||||
|
|
|
@ -72,6 +72,12 @@ config :philomena, PhilomenaWeb.Endpoint,
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Relax CSP rules in development
|
||||||
|
config :philomena, csp_relaxed: true
|
||||||
|
|
||||||
|
# Enable Vite HMR
|
||||||
|
config :philomena, vite_reload: true
|
||||||
|
|
||||||
# Do not include metadata nor timestamps in development logs
|
# Do not include metadata nor timestamps in development logs
|
||||||
config :logger, :console, format: "[$level] $message\n"
|
config :logger, :console, format: "[$level] $message\n"
|
||||||
|
|
||||||
|
|
|
@ -76,6 +76,7 @@
|
||||||
"image macro",
|
"image macro",
|
||||||
"monochrome",
|
"monochrome",
|
||||||
"oc",
|
"oc",
|
||||||
|
"oc only",
|
||||||
"photo",
|
"photo",
|
||||||
"Tag original characters oc:name"
|
"Tag original characters oc:name"
|
||||||
]
|
]
|
||||||
|
|
|
@ -134,22 +134,10 @@ if config_env() == :prod do
|
||||||
url: [host: System.fetch_env!("APP_HOSTNAME"), scheme: "https", port: 443],
|
url: [host: System.fetch_env!("APP_HOSTNAME"), scheme: "https", port: 443],
|
||||||
secret_key_base: System.fetch_env!("SECRET_KEY_BASE"),
|
secret_key_base: System.fetch_env!("SECRET_KEY_BASE"),
|
||||||
server: not is_nil(System.get_env("START_ENDPOINT"))
|
server: not is_nil(System.get_env("START_ENDPOINT"))
|
||||||
|
|
||||||
# Do not relax CSP in production
|
|
||||||
config :philomena, csp_relaxed: false
|
|
||||||
|
|
||||||
# Disable Vite HMR in prod
|
|
||||||
config :philomena, vite_reload: false
|
|
||||||
else
|
else
|
||||||
# Don't send email in development
|
# Don't send email in development
|
||||||
config :philomena, Philomena.Mailer, adapter: Bamboo.LocalAdapter
|
config :philomena, Philomena.Mailer, adapter: Bamboo.LocalAdapter
|
||||||
|
|
||||||
# Use this to debug slime templates
|
# Use this to debug slime templates
|
||||||
# config :slime, :keep_lines, true
|
# config :slime, :keep_lines, true
|
||||||
|
|
||||||
# Relax CSP rules in development and test servers
|
|
||||||
config :philomena, csp_relaxed: true
|
|
||||||
|
|
||||||
# Enable Vite HMR
|
|
||||||
config :philomena, vite_reload: true
|
|
||||||
end
|
end
|
||||||
|
|
12
lib/philomena_web/config.ex
Normal file
12
lib/philomena_web/config.ex
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
defmodule PhilomenaWeb.Config do
|
||||||
|
@reload_enabled Application.compile_env(:philomena, :vite_reload, false)
|
||||||
|
@csp_relaxed Application.compile_env(:philomena, :csp_relaxed, false)
|
||||||
|
|
||||||
|
defmacro vite_hmr?(do: do_clause, else: else_clause) do
|
||||||
|
if(@reload_enabled, do: do_clause, else: else_clause)
|
||||||
|
end
|
||||||
|
|
||||||
|
defmacro csp_relaxed?(do: do_clause, else: else_clause) do
|
||||||
|
if(@csp_relaxed, do: do_clause, else: else_clause)
|
||||||
|
end
|
||||||
|
end
|
|
@ -14,7 +14,7 @@ defmodule PhilomenaWeb.Profile.TagChangeController do
|
||||||
def index(conn, params) do
|
def index(conn, params) do
|
||||||
user = conn.assigns.user
|
user = conn.assigns.user
|
||||||
|
|
||||||
tag_changes =
|
common_query =
|
||||||
TagChange
|
TagChange
|
||||||
|> join(:inner, [tc], i in Image, on: tc.image_id == i.id)
|
|> join(:inner, [tc], i in Image, on: tc.image_id == i.id)
|
||||||
|> only_tag_join(params)
|
|> only_tag_join(params)
|
||||||
|
@ -24,10 +24,18 @@ defmodule PhilomenaWeb.Profile.TagChangeController do
|
||||||
)
|
)
|
||||||
|> added_filter(params)
|
|> added_filter(params)
|
||||||
|> only_tag_filter(params)
|
|> only_tag_filter(params)
|
||||||
|
|
||||||
|
tag_changes =
|
||||||
|
common_query
|
||||||
|> preload([:tag, :user, image: [:user, :sources, tags: :aliases]])
|
|> preload([:tag, :user, image: [:user, :sources, tags: :aliases]])
|
||||||
|> order_by(desc: :id)
|
|> order_by(desc: :id)
|
||||||
|> Repo.paginate(conn.assigns.scrivener)
|
|> Repo.paginate(conn.assigns.scrivener)
|
||||||
|
|
||||||
|
image_count =
|
||||||
|
common_query
|
||||||
|
|> select([_, i], count(i.id, :distinct))
|
||||||
|
|> Repo.one()
|
||||||
|
|
||||||
# params.permit(:added, :only_tag) ...
|
# params.permit(:added, :only_tag) ...
|
||||||
pagination_params =
|
pagination_params =
|
||||||
[added: conn.params["added"], only_tag: conn.params["only_tag"]]
|
[added: conn.params["added"], only_tag: conn.params["only_tag"]]
|
||||||
|
@ -37,7 +45,8 @@ defmodule PhilomenaWeb.Profile.TagChangeController do
|
||||||
title: "Tag Changes for User `#{user.name}'",
|
title: "Tag Changes for User `#{user.name}'",
|
||||||
user: user,
|
user: user,
|
||||||
tag_changes: tag_changes,
|
tag_changes: tag_changes,
|
||||||
pagination_params: pagination_params
|
pagination_params: pagination_params,
|
||||||
|
image_count: image_count
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ defmodule PhilomenaWeb.SettingController do
|
||||||
|> set_cookie(user_params, "hidpi", "hidpi")
|
|> set_cookie(user_params, "hidpi", "hidpi")
|
||||||
|> set_cookie(user_params, "webm", "webm")
|
|> set_cookie(user_params, "webm", "webm")
|
||||||
|> set_cookie(user_params, "serve_webm", "serve_webm")
|
|> set_cookie(user_params, "serve_webm", "serve_webm")
|
||||||
|
|> set_cookie(user_params, "unmute_videos", "unmute_videos")
|
||||||
|> set_cookie(user_params, "chan_nsfw", "chan_nsfw")
|
|> set_cookie(user_params, "chan_nsfw", "chan_nsfw")
|
||||||
|> set_cookie(user_params, "hide_staff_tools", "hide_staff_tools")
|
|> set_cookie(user_params, "hide_staff_tools", "hide_staff_tools")
|
||||||
|> set_cookie(user_params, "hide_uploader", "hide_uploader")
|
|> set_cookie(user_params, "hide_uploader", "hide_uploader")
|
||||||
|
|
|
@ -10,6 +10,8 @@ defmodule PhilomenaWeb.MarkdownRenderer do
|
||||||
hd(render_collection([item], conn))
|
hd(render_collection([item], conn))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# This is rendered Markdown
|
||||||
|
# sobelow_skip ["XSS.Raw"]
|
||||||
def render_collection(collection, conn) do
|
def render_collection(collection, conn) do
|
||||||
representations =
|
representations =
|
||||||
collection
|
collection
|
||||||
|
@ -19,15 +21,21 @@ defmodule PhilomenaWeb.MarkdownRenderer do
|
||||||
|> render_representations(conn)
|
|> render_representations(conn)
|
||||||
|
|
||||||
Enum.map(collection, fn %{body: text} ->
|
Enum.map(collection, fn %{body: text} ->
|
||||||
Markdown.to_html(text || "", representations)
|
(text || "")
|
||||||
|
|> Markdown.to_html(representations)
|
||||||
|
|> Phoenix.HTML.raw()
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# This is rendered Markdown for use on static pages
|
||||||
|
# sobelow_skip ["XSS.Raw"]
|
||||||
def render_unsafe(text, conn) do
|
def render_unsafe(text, conn) do
|
||||||
images = find_images(text)
|
images = find_images(text)
|
||||||
representations = render_representations(images, conn)
|
representations = render_representations(images, conn)
|
||||||
|
|
||||||
Markdown.to_html_unsafe(text, representations)
|
text
|
||||||
|
|> Markdown.to_html_unsafe(representations)
|
||||||
|
|> Phoenix.HTML.raw()
|
||||||
end
|
end
|
||||||
|
|
||||||
defp find_images(text) do
|
defp find_images(text) do
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
defmodule PhilomenaWeb.ContentSecurityPolicyPlug do
|
defmodule PhilomenaWeb.ContentSecurityPolicyPlug do
|
||||||
|
import PhilomenaWeb.Config
|
||||||
import Plug.Conn
|
import Plug.Conn
|
||||||
|
|
||||||
@allowed_sources [
|
@allowed_sources [
|
||||||
|
@ -42,13 +43,17 @@ defmodule PhilomenaWeb.ContentSecurityPolicyPlug do
|
||||||
|> Enum.map(&cspify_element/1)
|
|> Enum.map(&cspify_element/1)
|
||||||
|> Enum.join("; ")
|
|> Enum.join("; ")
|
||||||
|
|
||||||
if conn.status == 500 and allow_relaxed_csp() do
|
csp_relaxed? do
|
||||||
|
if conn.status == 500 do
|
||||||
# Allow Plug.Debugger to function in this case
|
# Allow Plug.Debugger to function in this case
|
||||||
delete_resp_header(conn, "content-security-policy")
|
delete_resp_header(conn, "content-security-policy")
|
||||||
else
|
else
|
||||||
# Enforce CSP otherwise
|
# Enforce CSP otherwise
|
||||||
put_resp_header(conn, "content-security-policy", csp_value)
|
put_resp_header(conn, "content-security-policy", csp_value)
|
||||||
end
|
end
|
||||||
|
else
|
||||||
|
put_resp_header(conn, "content-security-policy", csp_value)
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -64,14 +69,13 @@ defmodule PhilomenaWeb.ContentSecurityPolicyPlug do
|
||||||
|
|
||||||
defp cdn_uri, do: Application.get_env(:philomena, :cdn_host) |> to_uri()
|
defp cdn_uri, do: Application.get_env(:philomena, :cdn_host) |> to_uri()
|
||||||
defp camo_uri, do: Application.get_env(:philomena, :camo_host) |> to_uri()
|
defp camo_uri, do: Application.get_env(:philomena, :camo_host) |> to_uri()
|
||||||
defp vite_reload?, do: Application.get_env(:philomena, :vite_reload)
|
|
||||||
|
|
||||||
defp default_script_src, do: if(vite_reload?(), do: "'self' localhost:5173", else: "'self'")
|
defp default_script_src, do: vite_hmr?(do: "'self' localhost:5173", else: "'self'")
|
||||||
|
|
||||||
defp default_connect_src,
|
defp default_connect_src,
|
||||||
do: if(vite_reload?(), do: "'self' localhost:5173 ws://localhost:5173", else: "'self'")
|
do: vite_hmr?(do: "'self' localhost:5173 ws://localhost:5173", else: "'self'")
|
||||||
|
|
||||||
defp default_style_src, do: if(vite_reload?(), do: "'self' 'unsafe-inline'", else: "'self'")
|
defp default_style_src, do: vite_hmr?(do: "'self' 'unsafe-inline'", else: "'self'")
|
||||||
|
|
||||||
defp to_uri(host) when host in [nil, ""], do: ""
|
defp to_uri(host) when host in [nil, ""], do: ""
|
||||||
defp to_uri(host), do: URI.to_string(%URI{scheme: "https", host: host})
|
defp to_uri(host), do: URI.to_string(%URI{scheme: "https", host: host})
|
||||||
|
@ -84,6 +88,4 @@ defmodule PhilomenaWeb.ContentSecurityPolicyPlug do
|
||||||
|
|
||||||
Enum.join([key | value], " ")
|
Enum.join([key | value], " ")
|
||||||
end
|
end
|
||||||
|
|
||||||
defp allow_relaxed_csp, do: Application.get_env(:philomena, :csp_relaxed, false)
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -44,7 +44,7 @@ h2 Do-Not-Post Requests
|
||||||
= request.dnp_type
|
= request.dnp_type
|
||||||
|
|
||||||
td
|
td
|
||||||
== body
|
= body
|
||||||
|
|
||||||
td class=dnp_entry_row_class(request)
|
td class=dnp_entry_row_class(request)
|
||||||
=> pretty_state(request)
|
=> pretty_state(request)
|
||||||
|
|
|
@ -13,7 +13,7 @@ table.table
|
||||||
= link_to_noted_thing(@conn, note.notable)
|
= link_to_noted_thing(@conn, note.notable)
|
||||||
|
|
||||||
td
|
td
|
||||||
== body
|
= body
|
||||||
|
|
||||||
td
|
td
|
||||||
= pretty_time note.created_at
|
= pretty_time note.created_at
|
||||||
|
|
|
@ -11,7 +11,7 @@ article.block.communication
|
||||||
br
|
br
|
||||||
= render PhilomenaWeb.UserAttributionView, "_anon_user_title.html", object: @report, conn: @conn
|
= render PhilomenaWeb.UserAttributionView, "_anon_user_title.html", object: @report, conn: @conn
|
||||||
.communication__body__text
|
.communication__body__text
|
||||||
==<> @body
|
=<> @body
|
||||||
|
|
||||||
.block__content.communication__options
|
.block__content.communication__options
|
||||||
.flex.flex--wrap.flex--spaced-out
|
.flex.flex--wrap.flex--spaced-out
|
||||||
|
|
|
@ -45,10 +45,10 @@ article.block.communication id="comment_#{@comment.id}"
|
||||||
| This comment's contents have been destroyed.
|
| This comment's contents have been destroyed.
|
||||||
- else
|
- else
|
||||||
br
|
br
|
||||||
==<> @body
|
=<> @body
|
||||||
|
|
||||||
- else
|
- else
|
||||||
==<> @body
|
=<> @body
|
||||||
|
|
||||||
.block__content.communication__options
|
.block__content.communication__options
|
||||||
.flex.flex--wrap.flex--spaced-out
|
.flex.flex--wrap.flex--spaced-out
|
||||||
|
|
|
@ -28,10 +28,10 @@ article.block.communication id="comment_#{@comment.id}"
|
||||||
| This comment's contents have been destroyed.
|
| This comment's contents have been destroyed.
|
||||||
- else
|
- else
|
||||||
br
|
br
|
||||||
==<> @body
|
=<> @body
|
||||||
|
|
||||||
- else
|
- else
|
||||||
==<> @body
|
=<> @body
|
||||||
|
|
||||||
.block__content.communication__options
|
.block__content.communication__options
|
||||||
.flex.flex--wrap.flex--spaced-out
|
.flex.flex--wrap.flex--spaced-out
|
||||||
|
|
|
@ -59,7 +59,7 @@ h3 The List
|
||||||
= entry.dnp_type
|
= entry.dnp_type
|
||||||
|
|
||||||
td
|
td
|
||||||
== body
|
= body
|
||||||
|
|
||||||
= if @status_column do
|
= if @status_column do
|
||||||
td
|
td
|
||||||
|
|
|
@ -28,19 +28,19 @@ h2
|
||||||
tr
|
tr
|
||||||
td Conditions:
|
td Conditions:
|
||||||
td
|
td
|
||||||
== @conditions
|
= @conditions
|
||||||
|
|
||||||
= if can?(@conn, :show_reason, @dnp_entry) do
|
= if can?(@conn, :show_reason, @dnp_entry) do
|
||||||
tr
|
tr
|
||||||
td Reason:
|
td Reason:
|
||||||
td
|
td
|
||||||
== @reason
|
= @reason
|
||||||
|
|
||||||
= if can?(@conn, :show_feedback, @dnp_entry) do
|
= if can?(@conn, :show_feedback, @dnp_entry) do
|
||||||
tr
|
tr
|
||||||
td Instructions:
|
td Instructions:
|
||||||
td
|
td
|
||||||
== @instructions
|
= @instructions
|
||||||
tr
|
tr
|
||||||
td Feedback:
|
td Feedback:
|
||||||
td
|
td
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
' Edit
|
' Edit
|
||||||
.block__content
|
.block__content
|
||||||
p
|
p
|
||||||
= if String.length(@body) > 0 do
|
= if String.length(@image.description) > 0 do
|
||||||
== @body
|
= @body
|
||||||
- else
|
- else
|
||||||
em No description provided.
|
em No description provided.
|
||||||
|
|
|
@ -21,7 +21,7 @@ html lang="en"
|
||||||
meta name="format-detection" content="telephone=no"
|
meta name="format-detection" content="telephone=no"
|
||||||
= csrf_meta_tag()
|
= csrf_meta_tag()
|
||||||
|
|
||||||
= if vite_reload?() do
|
= vite_hmr? do
|
||||||
script type="module" src="http://localhost:5173/@vite/client"
|
script type="module" src="http://localhost:5173/@vite/client"
|
||||||
script type="module" src="http://localhost:5173/js/app.js"
|
script type="module" src="http://localhost:5173/js/app.js"
|
||||||
- else
|
- else
|
||||||
|
|
|
@ -25,7 +25,7 @@ article.block.communication
|
||||||
= render PhilomenaWeb.UserAttributionView, "_user_title.html", object: %{user: @message.from}, conn: @conn
|
= render PhilomenaWeb.UserAttributionView, "_user_title.html", object: %{user: @message.from}, conn: @conn
|
||||||
|
|
||||||
.communication__body__text
|
.communication__body__text
|
||||||
== @body
|
= @body
|
||||||
|
|
||||||
.block__content.communication__options
|
.block__content.communication__options
|
||||||
.flex.flex--wrap.flex--spaced-out
|
.flex.flex--wrap.flex--spaced-out
|
||||||
|
|
|
@ -12,4 +12,4 @@ p
|
||||||
i.fa.fa-edit>
|
i.fa.fa-edit>
|
||||||
' Edit
|
' Edit
|
||||||
|
|
||||||
== @rendered
|
= @rendered
|
||||||
|
|
|
@ -45,10 +45,10 @@ article.block.communication id="post_#{@post.id}"
|
||||||
| This post's contents have been destroyed.
|
| This post's contents have been destroyed.
|
||||||
- else
|
- else
|
||||||
br
|
br
|
||||||
==<> @body
|
=<> @body
|
||||||
|
|
||||||
- else
|
- else
|
||||||
==<> @body
|
=<> @body
|
||||||
|
|
||||||
.block__content.communication__options
|
.block__content.communication__options
|
||||||
.flex.flex--wrap.flex--spaced-out
|
.flex.flex--wrap.flex--spaced-out
|
||||||
|
|
|
@ -7,4 +7,4 @@
|
||||||
= render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: @post, conn: @conn, awards: true
|
= render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: @post, conn: @conn, awards: true
|
||||||
|
|
||||||
.communication__body__text
|
.communication__body__text
|
||||||
== @body
|
= @body
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
.block__content.profile-about
|
.block__content.profile-about
|
||||||
= if @user.description not in [nil, ""] do
|
= cond do
|
||||||
|
- @user.description not in [nil, ""] ->
|
||||||
= @about_me
|
= @about_me
|
||||||
|
|
||||||
= if can?(@conn, :edit_description, @user) do
|
= if can?(@conn, :edit_description, @user) do
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
/ Lotta space here
|
/ Lotta space here
|
||||||
br
|
br
|
||||||
== @commission_information
|
= @commission_information
|
||||||
br
|
br
|
||||||
br
|
br
|
||||||
|
|
||||||
|
|
|
@ -42,13 +42,13 @@
|
||||||
br
|
br
|
||||||
br
|
br
|
||||||
|
|
||||||
== description
|
= description
|
||||||
td
|
td
|
||||||
| $
|
| $
|
||||||
= Decimal.round(item.base_price, 2)
|
= Decimal.round(item.base_price, 2)
|
||||||
|
|
||||||
td
|
td
|
||||||
== add_ons
|
= add_ons
|
||||||
|
|
||||||
= if can?(@conn, :edit, @commission) do
|
= if can?(@conn, :edit, @commission) do
|
||||||
td
|
td
|
||||||
|
|
|
@ -24,14 +24,14 @@
|
||||||
br
|
br
|
||||||
br
|
br
|
||||||
|
|
||||||
== @rendered.information
|
= @rendered.information
|
||||||
|
|
||||||
/ Contact information block
|
/ Contact information block
|
||||||
.block
|
.block
|
||||||
.block__header
|
.block__header
|
||||||
span Contact information
|
span Contact information
|
||||||
.block__content.commission__block_body
|
.block__content.commission__block_body
|
||||||
== @rendered.contact
|
= @rendered.contact
|
||||||
|
|
||||||
/ Categories block
|
/ Categories block
|
||||||
.block
|
.block
|
||||||
|
@ -48,7 +48,7 @@
|
||||||
.block__header
|
.block__header
|
||||||
span Will draw/create
|
span Will draw/create
|
||||||
.block__content.commission__block_body
|
.block__content.commission__block_body
|
||||||
== @rendered.will_create
|
= @rendered.will_create
|
||||||
|
|
||||||
/ Will not create block
|
/ Will not create block
|
||||||
= if @commission.will_not_create not in [nil, ""] do
|
= if @commission.will_not_create not in [nil, ""] do
|
||||||
|
@ -56,7 +56,7 @@
|
||||||
.block__header
|
.block__header
|
||||||
span Will not draw/create
|
span Will not draw/create
|
||||||
.block__content.commission__block_body
|
.block__content.commission__block_body
|
||||||
== @rendered.will_not_create
|
= @rendered.will_not_create
|
||||||
|
|
||||||
/ Artist link block
|
/ Artist link block
|
||||||
/.block
|
/.block
|
||||||
|
|
|
@ -155,7 +155,7 @@
|
||||||
tbody
|
tbody
|
||||||
= for {body, mod_note} <- @mod_notes do
|
= for {body, mod_note} <- @mod_notes do
|
||||||
tr
|
tr
|
||||||
td == body
|
td = body
|
||||||
td = pretty_time(mod_note.created_at)
|
td = pretty_time(mod_note.created_at)
|
||||||
.block__content
|
.block__content
|
||||||
a.button href=Routes.profile_detail_path(@conn, :index, @user)
|
a.button href=Routes.profile_detail_path(@conn, :index, @user)
|
||||||
|
@ -167,7 +167,7 @@
|
||||||
i.fa.fa-clipboard
|
i.fa.fa-clipboard
|
||||||
| Moderation Scratchpad
|
| Moderation Scratchpad
|
||||||
.block__content.profile-about
|
.block__content.profile-about
|
||||||
== @scratchpad
|
= @scratchpad
|
||||||
.block__content
|
.block__content
|
||||||
a.button href=Routes.profile_scratchpad_path(@conn, :edit, @user)
|
a.button href=Routes.profile_scratchpad_path(@conn, :edit, @user)
|
||||||
i.fa.fa-edit>
|
i.fa.fa-edit>
|
||||||
|
|
|
@ -16,4 +16,10 @@ h1
|
||||||
= link "Added", to: Routes.profile_tag_change_path(@conn, :index, @user, Keyword.merge(@pagination_params, added: 1))
|
= link "Added", to: Routes.profile_tag_change_path(@conn, :index, @user, Keyword.merge(@pagination_params, added: 1))
|
||||||
= link "All", to: Routes.profile_tag_change_path(@conn, :index, @user, Keyword.delete(@pagination_params, :added))
|
= link "All", to: Routes.profile_tag_change_path(@conn, :index, @user, Keyword.delete(@pagination_params, :added))
|
||||||
|
|
||||||
|
.block__header.block__header--light
|
||||||
|
span.block__header__title.page__info
|
||||||
|
' Listing changes for
|
||||||
|
=> @image_count
|
||||||
|
= pluralize("image", "images", @image_count)
|
||||||
|
|
||||||
= render PhilomenaWeb.TagChangeView, "index.html", conn: @conn, tag_changes: @tag_changes, pagination: pagination
|
= render PhilomenaWeb.TagChangeView, "index.html", conn: @conn, tag_changes: @tag_changes, pagination: pagination
|
||||||
|
|
|
@ -154,6 +154,10 @@ h1 Content Settings
|
||||||
=> label f, :webm, "Use video thumbnails"
|
=> label f, :webm, "Use video thumbnails"
|
||||||
=> checkbox f, :webm, checked: @conn.cookies["webm"] == "true"
|
=> checkbox f, :webm, checked: @conn.cookies["webm"] == "true"
|
||||||
.fieldlabel: i Use video thumbnails for WebM videos. Does not apply to GIF images.
|
.fieldlabel: i Use video thumbnails for WebM videos. Does not apply to GIF images.
|
||||||
|
.field
|
||||||
|
=> label f, :unmute_videos, "Enable video audio by default"
|
||||||
|
=> checkbox f, :unmute_videos, checked: @conn.cookies["unmute_videos"] == "true"
|
||||||
|
.fieldlabel: i Automatically enable audio on video pages when they are loaded.
|
||||||
.field
|
.field
|
||||||
=> label f, :hide_uploader
|
=> label f, :hide_uploader
|
||||||
=> checkbox f, :hide_uploader, checked: @conn.cookies["hide_uploader"] == "true"
|
=> checkbox f, :hide_uploader, checked: @conn.cookies["hide_uploader"] == "true"
|
||||||
|
|
|
@ -106,7 +106,7 @@
|
||||||
= if @tag.description not in [nil, ""] do
|
= if @tag.description not in [nil, ""] do
|
||||||
strong> Detailed description:
|
strong> Detailed description:
|
||||||
br
|
br
|
||||||
== @body
|
= @body
|
||||||
|
|
||||||
= if Enum.any?(@dnp_entries) do
|
= if Enum.any?(@dnp_entries) do
|
||||||
hr
|
hr
|
||||||
|
@ -119,7 +119,7 @@
|
||||||
strong
|
strong
|
||||||
=> entry.dnp_type
|
=> entry.dnp_type
|
||||||
|
|
||||||
==> body
|
=> body
|
||||||
|
|
||||||
| (
|
| (
|
||||||
= link "more info", to: Routes.dnp_entry_path(@conn, :show, entry)
|
= link "more info", to: Routes.dnp_entry_path(@conn, :show, entry)
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
th Action
|
th Action
|
||||||
th Timestamp
|
th Timestamp
|
||||||
th User
|
th User
|
||||||
|
th Retained?
|
||||||
= if reverts_tag_changes?(@conn) do
|
= if reverts_tag_changes?(@conn) do
|
||||||
th Moderation
|
th Moderation
|
||||||
|
|
||||||
|
@ -62,6 +63,10 @@
|
||||||
' This user is a staff member.
|
' This user is a staff member.
|
||||||
br
|
br
|
||||||
' Ask them before reverting their changes.
|
' Ask them before reverting their changes.
|
||||||
|
= if tag_change_retained(tag_change) do
|
||||||
|
td.success Yes
|
||||||
|
- else
|
||||||
|
td.danger No
|
||||||
= if reverts_tag_changes?(@conn) do
|
= if reverts_tag_changes?(@conn) do
|
||||||
td
|
td
|
||||||
a href=Routes.image_tag_change_path(@conn, :delete, tag_change.image, tag_change) data-method="delete" data-confirm="Are you really, really sure?"
|
a href=Routes.image_tag_change_path(@conn, :delete, tag_change.image, tag_change) data-method="delete" data-confirm="Are you really, really sure?"
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
defmodule PhilomenaWeb.LayoutView do
|
defmodule PhilomenaWeb.LayoutView do
|
||||||
use PhilomenaWeb, :view
|
use PhilomenaWeb, :view
|
||||||
|
|
||||||
|
import PhilomenaWeb.Config
|
||||||
alias PhilomenaWeb.ImageView
|
alias PhilomenaWeb.ImageView
|
||||||
alias Philomena.Config
|
alias Philomena.Config
|
||||||
alias Plug.Conn
|
alias Plug.Conn
|
||||||
|
|
|
@ -15,4 +15,14 @@ defmodule PhilomenaWeb.TagChangeView do
|
||||||
|
|
||||||
def reverts_tag_changes?(conn),
|
def reverts_tag_changes?(conn),
|
||||||
do: can?(conn, :revert, Philomena.TagChanges.TagChange)
|
do: can?(conn, :revert, Philomena.TagChanges.TagChange)
|
||||||
|
|
||||||
|
def tag_change_retained(%{image: image, added: added, tag: %{id: tag_id}}) do
|
||||||
|
added == Enum.any?(image.tags, &(&1.id == tag_id))
|
||||||
|
end
|
||||||
|
|
||||||
|
def tag_change_retained(%{image: image, added: added, tag_name_cache: tag_name}) do
|
||||||
|
added == Enum.any?(image.tags, &(&1.name == tag_name))
|
||||||
|
end
|
||||||
|
|
||||||
|
def tag_change_retained(_), do: false
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue