Encode urls for css background images (#7906)

* Add new utility to encode urls.
Use the encode urls utility to encode all background images in css

* need a commit to pull exampleimagery from

* skip and fix on otherside

---------

Co-authored-by: John Hill <john.c.hill@nasa.gov>
This commit is contained in:
Shefali Joshi 2024-10-18 12:59:02 -07:00 committed by GitHub
parent 078cd341a5
commit 057a5f997c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 140 additions and 16 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -96,9 +96,6 @@ test.describe('Example Imagery Object', () => {
expect(newPage.url()).toContain('.jpg');
});
// this requires CORS to be enabled in some fashion
test.fixme('Can right click on image and save it as a file', async ({ page }) => {});
test('Can adjust image brightness/contrast by dragging the sliders', async ({
page,
browserName

View File

@ -0,0 +1,93 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2024, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*
* This test suite verifies modifying the image location of the example imagery object.
*/
import { createDomainObjectWithDefaults } from '../../../../appActions.js';
import { expect, test } from '../../../../pluginFixtures.js';
test.describe('Example Imagery Object Custom Images', () => {
let exampleImagery;
test.beforeEach(async ({ page }) => {
//Go to baseURL
await page.goto('./', { waitUntil: 'domcontentloaded' });
// Create a default 'Example Imagery' object
exampleImagery = await createDomainObjectWithDefaults(page, {
name: 'Example Imagery',
type: 'Example Imagery'
});
// Verify that the created object is focused
await expect(page.locator('.l-browse-bar__object-name')).toContainText(exampleImagery.name);
await page.getByLabel('Focused Image Element').hover({ trial: true });
// Wait for image thumbnail auto-scroll to complete
await expect(page.getByLabel('Image Thumbnail from').last()).toBeInViewport();
});
// this requires CORS to be enabled in some fashion
test.fixme('Can right click on image and save it as a file', async ({ page }) => {});
test('Can provide a custom image location for the example imagery object', async ({ page }) => {
// Modify Example Imagery to create a really stable image which will never let us down
await page.getByRole('button', { name: 'More actions' }).click();
await page.getByRole('menuitem', { name: 'Edit Properties...' }).click();
await page
.locator('#imageLocation-textarea')
.fill(
'https://raw.githubusercontent.com/nasa/openmct/554f77c42fec81cf0f63e62b278012cb08d82af9/e2e/test-data/rick.jpg,https://raw.githubusercontent.com/nasa/openmct/554f77c42fec81cf0f63e62b278012cb08d82af9/e2e/test-data/rick.jpg'
);
await page.getByRole('button', { name: 'Save' }).click();
await page.reload({ waitUntil: 'domcontentloaded' });
// Wait for the thumbnails to finish their scroll animation
// (Wait until the rightmost thumbnail is in view)
await expect(page.getByLabel('Image Thumbnail from').last()).toBeInViewport();
await expect(page.getByLabel('Image Wrapper')).toBeVisible();
});
test.fixme('Can provide a custom image with spaces in name', async ({ page }) => {
test.info().annotations.push({
type: 'issue',
description: 'https://github.com/nasa/openmct/issues/7903'
});
await page.goto(exampleImagery.url, { waitUntil: 'domcontentloaded' });
// Modify Example Imagery to create a really stable image which will never let us down
await page.getByRole('button', { name: 'More actions' }).click();
await page.getByRole('menuitem', { name: 'Edit Properties...' }).click();
await page
.locator('#imageLocation-textarea')
.fill(
'https://raw.githubusercontent.com/nasa/openmct/d8c64f183400afb70137221fc1a035e091bea912/e2e/test-data/rick%20space%20roll.jpg'
);
await page.getByRole('button', { name: 'Save' }).click();
await page.reload({ waitUntil: 'domcontentloaded' });
// Wait for the thumbnails to finish their scroll animation
// (Wait until the rightmost thumbnail is in view)
await expect(page.getByLabel('Image Thumbnail from').last()).toBeInViewport();
await expect(page.getByLabel('Image Wrapper')).toBeVisible();
});
});

View File

@ -28,11 +28,7 @@
{ 'is-style-invisible': styleItem.style && styleItem.style.isStyleInvisible },
{ 'c-style-thumb--mixed': mixedStyles.indexOf('backgroundColor') > -1 }
]"
:style="[
styleItem.style.imageUrl
? { backgroundImage: 'url(' + styleItem.style.imageUrl + ')' }
: itemStyle
]"
:style="[encodedImageUrl ? { backgroundImage: 'url(' + encodedImageUrl + ')' } : itemStyle]"
class="c-style-thumb"
>
<span
@ -62,7 +58,7 @@
@change="updateStyleValue"
/>
<ToolbarButton
v-if="hasProperty(styleItem.style.imageUrl)"
v-if="hasProperty(encodedImageUrl)"
class="c-style__toolbar-button--image-url"
:options="imageUrlOption"
@change="updateStyleValue"
@ -93,6 +89,8 @@ import ToolbarButton from '@/ui/toolbar/components/ToolbarButton.vue';
import ToolbarColorPicker from '@/ui/toolbar/components/ToolbarColorPicker.vue';
import ToolbarToggleButton from '@/ui/toolbar/components/ToolbarToggleButton.vue';
import { encode_url } from '../../../../utils/encoding';
export default {
name: 'StyleEditor',
components: {
@ -183,11 +181,14 @@ export default {
},
property: 'imageUrl',
formKeys: ['url'],
value: { url: this.styleItem.style.imageUrl },
value: { url: this.encodedImageUrl },
isEditing: this.isEditing,
nonSpecific: this.mixedStyles.indexOf('imageUrl') > -1
};
},
encodedImageUrl() {
return encode_url(this.styleItem.style.imageUrl);
},
isStyleInvisibleOption() {
return {
value: this.styleItem.style.isStyleInvisible,

View File

@ -35,6 +35,7 @@
</template>
<script>
import { encode_url } from '../../../utils/encoding';
import conditionalStylesMixin from '../mixins/objectStyles-mixin.js';
import LayoutFrame from './LayoutFrame.vue';
@ -80,12 +81,12 @@ export default {
return this.isEditing || !this.itemStyle?.isStyleInvisible;
},
style() {
let backgroundImage = 'url(' + this.item.url + ')';
let backgroundImage = `url('${encode_url(this.item.url)}')`;
let border = '1px solid ' + this.item.stroke;
if (this.itemStyle) {
if (this.itemStyle.imageUrl !== undefined) {
backgroundImage = 'url(' + this.itemStyle.imageUrl + ')';
backgroundImage = `url('${encode_url(this.itemStyle.imageUrl)}')`;
}
border = this.itemStyle.border;

View File

@ -38,7 +38,7 @@
<img
ref="img"
class="c-thumb__image"
:src="`${image.thumbnailUrl || image.url}`"
:src="imageSrc"
fetchpriority="low"
@load="imageLoadCompleted"
/>
@ -54,6 +54,8 @@
</template>
<script>
import { encode_url } from '../../../utils/encoding';
const THUMB_PADDING = 4;
const BORDER_WIDTH = 2;
@ -96,6 +98,9 @@ export default {
};
},
computed: {
imageSrc() {
return `${encode_url(this.image.thumbnailUrl) || encode_url(this.image.url)}`;
},
ariaLabel() {
return `Image thumbnail from ${this.image.formattedTime}${this.showAnnotationIndicator ? ', has annotations' : ''}`;
},

View File

@ -222,6 +222,7 @@ import { TIME_CONTEXT_EVENTS } from '@/api/time/constants.js';
import imageryData from '@/plugins/imagery/mixins/imageryData.js';
import { VIEW_LARGE_ACTION_KEY } from '@/plugins/viewLargeAction/viewLargeAction.js';
import { encode_url } from '../../../utils/encoding';
import eventHelpers from '../lib/eventHelpers.js';
import AnnotationsCanvas from './AnnotationsCanvas.vue';
import Compass from './Compass/CompassComponent.vue';
@ -364,7 +365,7 @@ export default {
filter: `brightness(${this.filters.brightness}%) contrast(${this.filters.contrast}%)`,
backgroundImage: `${
this.imageUrl
? `url(${this.imageUrl}),
? `url(${encode_url(this.imageUrl)}),
repeating-linear-gradient(
45deg,
transparent,
@ -789,7 +790,7 @@ export default {
},
getVisibleLayerStyles(layer) {
return {
backgroundImage: `url(${layer.source})`,
backgroundImage: `url(${encode_url(layer.source)})`,
transform: `scale(${this.zoomFactor}) translate(${this.imageTranslateX / 2}px, ${
this.imageTranslateY / 2
}px)`,

View File

@ -32,6 +32,7 @@
<script>
import mount from 'utils/mount';
import { encode_url } from '../../utils/encoding';
import AboutDialog from './AboutDialog.vue';
export default {
@ -39,7 +40,7 @@ export default {
mounted() {
const branding = this.openmct.branding();
if (branding.smallLogoImage) {
this.$refs.aboutLogo.style.backgroundImage = `url('${branding.smallLogoImage}')`;
this.$refs.aboutLogo.style.backgroundImage = `url('${encode_url(branding.smallLogoImage)}')`;
}
},
methods: {

25
src/utils/encoding.js Normal file
View File

@ -0,0 +1,25 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2024, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
export function encode_url(url) {
return url ? encodeURI(url) : url;
}