glib-web 4.44.4 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/lint.yml +2 -2
- package/.nycrc.json +3 -1
- package/README.md +1 -0
- package/components/charts/series.js +23 -11
- package/components/component.vue +0 -5
- package/components/fields/checkGroup.vue +14 -7
- package/components/fields/richText2.vue +33 -3
- package/components/fields/upload.vue +5 -3
- package/components/mixins/styles.js +0 -1
- package/components/popover.vue +107 -78
- package/cypress/e2e/glib-web/auth.cy.ts +21 -0
- package/cypress/e2e/glib-web/dialog.cy.ts +39 -1
- package/cypress/e2e/glib-web/dirtyState.cy.ts +8 -23
- package/cypress/e2e/glib-web/fieldsCaptcha.cy.ts +4 -4
- package/cypress/e2e/glib-web/fieldsCreditCard.cy.ts +22 -0
- package/cypress/e2e/glib-web/fieldsDateTime.cy.ts +48 -0
- package/cypress/e2e/glib-web/fieldsLocation.cy.ts +40 -0
- package/cypress/e2e/glib-web/fieldsOtp.cy.ts +68 -0
- package/cypress/e2e/glib-web/fieldsPhone.cy.ts +87 -0
- package/cypress/e2e/glib-web/fieldsRating.cy.ts +91 -0
- package/cypress/e2e/glib-web/fieldsRichText.cy.ts +137 -0
- package/cypress/e2e/glib-web/fieldsStripeToken.cy.ts +47 -0
- package/cypress/e2e/glib-web/fieldsUpload.cy.ts +111 -0
- package/cypress/e2e/glib-web/panelsBulkEdit2.cy.ts +13 -2
- package/cypress/e2e/glib-web/window.cy.ts +13 -6
- package/cypress/e2e/glib-web/windows.cy.ts +33 -1
- package/cypress/helper.ts +14 -2
- package/cypress/support/component.ts +15 -0
- package/cypress/support/e2e.ts +15 -0
- package/cypress.yml.example +5 -5
- package/index.js +2 -0
- package/package.json +1 -1
- package/utils/dom.js +19 -1
- package/components/composable/dropable.js +0 -52
- package/components/fields/googlePlace.vue +0 -162
- package/components/mixins/tooltip.js +0 -57
- package/cypress/e2e/glib-web/multiupload.cy.ts +0 -25
|
@@ -2,7 +2,11 @@ import { testPageUrl } from "../../helper"
|
|
|
2
2
|
|
|
3
3
|
const url = testPageUrl('panels_bulkEdit2')
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const csvFixtureContents = [
|
|
6
|
+
'month,electricity_usage,gas_usage,sources,compliant',
|
|
7
|
+
'January,120,10,Generators,yes',
|
|
8
|
+
'February,150,12,Solar Panels,no'
|
|
9
|
+
].join('\n')
|
|
6
10
|
|
|
7
11
|
describe('panels_bulkEdit2', () => {
|
|
8
12
|
it('loads csv rows and toggles column variants', () => {
|
|
@@ -10,7 +14,14 @@ describe('panels_bulkEdit2', () => {
|
|
|
10
14
|
|
|
11
15
|
cy.contains('Drag your CSV file here').should('exist')
|
|
12
16
|
|
|
13
|
-
cy.get('input[type="file"]').selectFile(
|
|
17
|
+
cy.get('input[type="file"]').selectFile(
|
|
18
|
+
{
|
|
19
|
+
contents: Cypress.Buffer.from(csvFixtureContents),
|
|
20
|
+
fileName: 'bulk_edit.csv',
|
|
21
|
+
mimeType: 'text/csv'
|
|
22
|
+
},
|
|
23
|
+
{ force: true }
|
|
24
|
+
)
|
|
14
25
|
|
|
15
26
|
cy.get('tbody tr').should('have.length', 2)
|
|
16
27
|
cy.contains('Submit (top)').should('be.visible')
|
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
import { testPageUrl } from "../../helper"
|
|
2
|
+
|
|
2
3
|
const url = testPageUrl('window')
|
|
3
4
|
|
|
4
|
-
describe(
|
|
5
|
-
it('
|
|
5
|
+
describe('window', () => {
|
|
6
|
+
it('opens a new window with updateExisting', () => {
|
|
6
7
|
cy.visit(url)
|
|
7
8
|
|
|
8
9
|
cy.contains('windows/open updateExisting: true').click()
|
|
10
|
+
cy.location('href').should('contain', 'fields_upload')
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
it('closes the current window', () => {
|
|
14
|
+
const previousUrl = testPageUrl('fields_upload')
|
|
15
|
+
|
|
16
|
+
cy.visit(previousUrl)
|
|
17
|
+
cy.visit(url)
|
|
9
18
|
|
|
10
|
-
cy.
|
|
11
|
-
expect(loc.href).to.eq(testPageUrl('multiupload'))
|
|
12
|
-
})
|
|
19
|
+
cy.contains('windows/close').click()
|
|
13
20
|
})
|
|
14
|
-
})
|
|
21
|
+
})
|
|
@@ -36,8 +36,26 @@ describe('windows', () => {
|
|
|
36
36
|
cy.get('@windowOpen').should('have.been.calledWith', 'http://www.google.com')
|
|
37
37
|
})
|
|
38
38
|
|
|
39
|
+
it('reloads the current window', () => {
|
|
40
|
+
cy.visit(url)
|
|
41
|
+
|
|
42
|
+
cy.contains('windows/reload').click()
|
|
43
|
+
cy.location('href').should('contain', 'path=test_page%2Fwindows')
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
it('prints the current window', () => {
|
|
47
|
+
cy.visit(url)
|
|
48
|
+
|
|
49
|
+
cy.window().then((win) => {
|
|
50
|
+
cy.stub(win, 'print').as('windowPrint')
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
cy.contains('windows/print').click()
|
|
54
|
+
cy.get('@windowPrint').should('have.been.called')
|
|
55
|
+
})
|
|
56
|
+
|
|
39
57
|
it('closes the current window and returns to the previous view', () => {
|
|
40
|
-
const previousUrl = testPageUrl('
|
|
58
|
+
const previousUrl = testPageUrl('fields_upload')
|
|
41
59
|
|
|
42
60
|
cy.visit(previousUrl)
|
|
43
61
|
cy.visit(url)
|
|
@@ -52,6 +70,13 @@ describe('windows', () => {
|
|
|
52
70
|
cy.location('href').should('contain', 'path=home%2Fprint')
|
|
53
71
|
})
|
|
54
72
|
|
|
73
|
+
it('closes the current window and reloads with fallback', () => {
|
|
74
|
+
cy.visit(url)
|
|
75
|
+
|
|
76
|
+
cy.contains('windows/closeWithReload').click()
|
|
77
|
+
cy.location('href').should('contain', 'path=home%2Findex')
|
|
78
|
+
})
|
|
79
|
+
|
|
55
80
|
it('closes all windows and opens the home view', () => {
|
|
56
81
|
cy.visit(url)
|
|
57
82
|
|
|
@@ -60,6 +85,13 @@ describe('windows', () => {
|
|
|
60
85
|
cy.location('href').should('contain', 'path=home%2Findex')
|
|
61
86
|
})
|
|
62
87
|
|
|
88
|
+
it('closes all windows and opens home view from onClose', () => {
|
|
89
|
+
cy.visit(url)
|
|
90
|
+
|
|
91
|
+
cy.contains('windows/closeAll').click()
|
|
92
|
+
cy.location('href').should('contain', 'path=home%2Findex')
|
|
93
|
+
})
|
|
94
|
+
|
|
63
95
|
it('opens a window with a loader view', () => {
|
|
64
96
|
cy.visit(url)
|
|
65
97
|
|
package/cypress/helper.ts
CHANGED
|
@@ -1,7 +1,19 @@
|
|
|
1
|
-
|
|
1
|
+
import { realComponent } from "../components/helper.js"
|
|
2
|
+
|
|
3
|
+
// const DEV_TEST_PAGE = 'http://localhost:3000/glib/json_ui_garage?path=test_page%2F{{testPage}}'
|
|
4
|
+
|
|
5
|
+
function testPageUrl(testPage) {
|
|
2
6
|
const port = Cypress.env('BACKEND_PORT') || '3000';
|
|
3
7
|
const baseUrl = `http://localhost:${port}/glib/json_ui_garage?path=test_page%2F${testPage}`;
|
|
4
8
|
return baseUrl;
|
|
5
9
|
}
|
|
6
10
|
|
|
7
|
-
|
|
11
|
+
function withComponent(id, callback) {
|
|
12
|
+
return cy.window().should((win) => {
|
|
13
|
+
const comp = realComponent(win.GLib.component.findById(id))
|
|
14
|
+
expect(comp).to.exist
|
|
15
|
+
callback(comp)
|
|
16
|
+
})
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export { testPageUrl, withComponent }
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import "./commands";
|
|
2
2
|
import "@cypress/code-coverage/support";
|
|
3
|
+
import { isFunction, isObject } from "../../utils/type.js";
|
|
3
4
|
|
|
4
5
|
const win = window as Window & { __settings?: { theme?: object }; __page?: object };
|
|
5
6
|
|
|
@@ -10,3 +11,17 @@ if (!win.__settings) {
|
|
|
10
11
|
if (!win.__page) {
|
|
11
12
|
win.__page = {};
|
|
12
13
|
}
|
|
14
|
+
|
|
15
|
+
Cypress.on("window:before:load", (win) => {
|
|
16
|
+
if (!isObject(win) || !isObject(win.console)) return;
|
|
17
|
+
|
|
18
|
+
if (isFunction(win.console.log)) {
|
|
19
|
+
win.console.log = () => {};
|
|
20
|
+
}
|
|
21
|
+
if (isFunction(win.console.warn)) {
|
|
22
|
+
win.console.warn = () => {};
|
|
23
|
+
}
|
|
24
|
+
if (isFunction(win.console.info)) {
|
|
25
|
+
win.console.info = () => {};
|
|
26
|
+
}
|
|
27
|
+
});
|
package/cypress/support/e2e.ts
CHANGED
|
@@ -16,6 +16,21 @@
|
|
|
16
16
|
// Import commands.js using ES2015 syntax:
|
|
17
17
|
import './commands'
|
|
18
18
|
import '@cypress/code-coverage/support'
|
|
19
|
+
import { isFunction, isObject } from "../../utils/type.js";
|
|
20
|
+
|
|
21
|
+
Cypress.on("window:before:load", (win) => {
|
|
22
|
+
if (!isObject(win) || !isObject(win.console)) return;
|
|
23
|
+
|
|
24
|
+
if (isFunction(win.console.log)) {
|
|
25
|
+
win.console.log = () => {};
|
|
26
|
+
}
|
|
27
|
+
if (isFunction(win.console.warn)) {
|
|
28
|
+
win.console.warn = () => {};
|
|
29
|
+
}
|
|
30
|
+
if (isFunction(win.console.info)) {
|
|
31
|
+
win.console.info = () => {};
|
|
32
|
+
}
|
|
33
|
+
});
|
|
19
34
|
|
|
20
35
|
// Ignore retry failures from backend error pages so specs can assert UI state.
|
|
21
36
|
Cypress.on('uncaught:exception', (err) => {
|
package/cypress.yml.example
CHANGED
|
@@ -43,13 +43,13 @@ jobs:
|
|
|
43
43
|
- run: cp config/database.yml.github-actions config/database.yml
|
|
44
44
|
- run: bundle exec rake db:test:prepare
|
|
45
45
|
- run: bundle exec rails server -d
|
|
46
|
-
- name: Cypress run
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
- name: Cypress run (e2e)
|
|
47
|
+
run: env -u ELECTRON_RUN_AS_NODE yarn cypress run --browser chrome
|
|
48
|
+
- name: Cypress run (component)
|
|
49
|
+
run: env -u ELECTRON_RUN_AS_NODE yarn cypress run --component
|
|
50
50
|
- name: Upload screenshots
|
|
51
51
|
uses: actions/upload-artifact@v4
|
|
52
52
|
if: failure()
|
|
53
53
|
with:
|
|
54
54
|
name: cypress-screenshots
|
|
55
|
-
path: cypress/screenshots
|
|
55
|
+
path: cypress/screenshots
|
package/index.js
CHANGED
|
@@ -61,6 +61,7 @@ import CommonResponsive from "./components/responsive.vue";
|
|
|
61
61
|
import CommonTemplateMenu from "./templates/_menu.vue";
|
|
62
62
|
import BigProgressCircle from "./templates/bigProgressCircle.vue";
|
|
63
63
|
import RichButton from "./components/button.vue";
|
|
64
|
+
import Dom from "./utils/dom";
|
|
64
65
|
Vue.component("panels-vertical", VerticalPanel);
|
|
65
66
|
Vue.component("panels-responsive", ResponsivePanel);
|
|
66
67
|
Vue.component("common-avatar", CommonAvatar);
|
|
@@ -123,6 +124,7 @@ const vPhoneInput = createVPhoneInput({
|
|
|
123
124
|
|
|
124
125
|
Vue.use(vPhoneInput);
|
|
125
126
|
|
|
127
|
+
Dom.ensureCsrfElement();
|
|
126
128
|
|
|
127
129
|
document.addEventListener("DOMContentLoaded", () => {
|
|
128
130
|
Vue.mount(`#${APP_ID}`);
|
package/package.json
CHANGED
package/utils/dom.js
CHANGED
|
@@ -1,6 +1,24 @@
|
|
|
1
|
+
import * as TypeUtils from "./type";
|
|
2
|
+
|
|
1
3
|
export default class {
|
|
4
|
+
static ensureCsrfElement() {
|
|
5
|
+
let element = document.querySelector('meta[name="csrf-token"]');
|
|
6
|
+
if (!TypeUtils.isObject(element)) {
|
|
7
|
+
const meta = document.createElement("meta");
|
|
8
|
+
meta.setAttribute("name", "csrf-token");
|
|
9
|
+
meta.setAttribute("content", "");
|
|
10
|
+
if (TypeUtils.isObject(document.head)) {
|
|
11
|
+
document.head.appendChild(meta);
|
|
12
|
+
} else {
|
|
13
|
+
document.documentElement.appendChild(meta);
|
|
14
|
+
}
|
|
15
|
+
element = meta;
|
|
16
|
+
}
|
|
17
|
+
return element;
|
|
18
|
+
}
|
|
19
|
+
|
|
2
20
|
static get csrfElement() {
|
|
3
|
-
return
|
|
21
|
+
return this.ensureCsrfElement();
|
|
4
22
|
}
|
|
5
23
|
|
|
6
24
|
static getCsrf() {
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { onMounted } from "vue";
|
|
2
|
-
|
|
3
|
-
function useDropUpload({ container, fileSelect, files, spec, uploader }) {
|
|
4
|
-
const { onDragStyle } = spec;
|
|
5
|
-
onMounted(() => {
|
|
6
|
-
uploader.setBusyWhenUploading({ files });
|
|
7
|
-
|
|
8
|
-
// handle style changes
|
|
9
|
-
let dragEl = null;
|
|
10
|
-
container.value.ondragenter = (event) => {
|
|
11
|
-
dragEl = event.target;
|
|
12
|
-
container.value.classList.add(...onDragStyle);
|
|
13
|
-
};
|
|
14
|
-
container.value.ondragleave = (event) => {
|
|
15
|
-
if (dragEl == event.target) {
|
|
16
|
-
container.value.classList.remove(...onDragStyle);
|
|
17
|
-
}
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
// handle upload
|
|
21
|
-
container.value.ondragover = (event) => event.preventDefault();
|
|
22
|
-
container.value.ondrop = (event) => {
|
|
23
|
-
event.preventDefault();
|
|
24
|
-
uploader.uploadFiles({
|
|
25
|
-
droppedFiles: event.dataTransfer.files,
|
|
26
|
-
container,
|
|
27
|
-
files,
|
|
28
|
-
spec
|
|
29
|
-
});
|
|
30
|
-
container.value.classList.remove(...onDragStyle);
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
container.value.onclick = (event) => {
|
|
34
|
-
const onchange = () => {
|
|
35
|
-
uploader.uploadFiles(
|
|
36
|
-
{
|
|
37
|
-
droppedFiles: event.target.files,
|
|
38
|
-
files,
|
|
39
|
-
spec,
|
|
40
|
-
container
|
|
41
|
-
}
|
|
42
|
-
);
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
fileSelect.value.onchange = onchange;
|
|
46
|
-
fileSelect.value.click();
|
|
47
|
-
};
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export { useDropUpload };
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
<!-- TODO: This probably can be merged with latLong-v1 or map-v1, i.e. add infoWindow support to latLong or map -->
|
|
2
|
-
|
|
3
|
-
<template>
|
|
4
|
-
<v-container v-if="loadIf" fluid class="pa-0">
|
|
5
|
-
<div class="v-input v-text-field theme--light">
|
|
6
|
-
<div class="v-input__control">
|
|
7
|
-
<div class="v-input__slot">
|
|
8
|
-
<div class="v-text-field__slot">
|
|
9
|
-
<label class="v-label theme--light v-label--active"
|
|
10
|
-
style="left: 0px; right: auto; position: absolute;">Address</label>
|
|
11
|
-
<!-- <gmap-place-input :default-place="placeName" :placeholder="Address" @place_changed="setPlace" /> -->
|
|
12
|
-
<gmap-autocomplete :name="spec.name" placeholder="Address" @place_changed="setPlace" />
|
|
13
|
-
</div>
|
|
14
|
-
</div>
|
|
15
|
-
</div>
|
|
16
|
-
</div>
|
|
17
|
-
|
|
18
|
-
<gmap-map ref="map" :center="{ lat: 25.105497, lng: 121.597366 }" :zoom="13" map-type-id="roadmap"
|
|
19
|
-
style="width: 100%; height: 300px" @click="onMapClick">
|
|
20
|
-
<gmap-info-window :options="infoOptions" :position="markerPos" :opened="infoWinOpen"
|
|
21
|
-
@closeclick="closeInfoWindow">
|
|
22
|
-
<div v-if="place !== null">
|
|
23
|
-
<strong>{{ place.name }}</strong>
|
|
24
|
-
<div>Place ID: {{ place.place_id }}</div>
|
|
25
|
-
<div>Address: {{ place.formatted_address }}</div>
|
|
26
|
-
<div>
|
|
27
|
-
Longitude: {{ place.geometry.location.lng() }}, Latitude:
|
|
28
|
-
{{ place.geometry.location.lat() }}
|
|
29
|
-
</div>
|
|
30
|
-
</div>
|
|
31
|
-
<div v-if="
|
|
32
|
-
spec.hasOwnProperty('infoWindow') &&
|
|
33
|
-
spec.infoWindow['actionButtons'].length > 0
|
|
34
|
-
">
|
|
35
|
-
<v-btn v-for="(buttonSpec, i) in spec.infoWindow.actionButtons" :key="i"
|
|
36
|
-
@click="onActionButtonClick($event, buttonSpec)">
|
|
37
|
-
{{ buttonSpec.text }}
|
|
38
|
-
</v-btn>
|
|
39
|
-
</div>
|
|
40
|
-
</gmap-info-window>
|
|
41
|
-
|
|
42
|
-
<gmap-marker :position="markerPos" :clickable="true" @click="openInfoWindow" />
|
|
43
|
-
<template #visible>
|
|
44
|
-
<div id="loading-container" ref="loading" class="d-none">
|
|
45
|
-
<v-progress-circular indeterminate color="primary" />
|
|
46
|
-
</div>
|
|
47
|
-
</template>
|
|
48
|
-
</gmap-map>
|
|
49
|
-
</v-container>
|
|
50
|
-
</template>
|
|
51
|
-
|
|
52
|
-
<script>
|
|
53
|
-
import GlibBase from "../base/glibBase.js";
|
|
54
|
-
import Action from "../../action";
|
|
55
|
-
|
|
56
|
-
export default {
|
|
57
|
-
extends: GlibBase,
|
|
58
|
-
props: ["spec"],
|
|
59
|
-
data() {
|
|
60
|
-
return {
|
|
61
|
-
infoOptions: {
|
|
62
|
-
pixelOffset: {
|
|
63
|
-
width: 0,
|
|
64
|
-
height: -35
|
|
65
|
-
}
|
|
66
|
-
},
|
|
67
|
-
markerPos: { lat: 0, lng: 0 },
|
|
68
|
-
infoWinOpen: false,
|
|
69
|
-
place: null
|
|
70
|
-
};
|
|
71
|
-
},
|
|
72
|
-
computed: {
|
|
73
|
-
placeName() {
|
|
74
|
-
return this.place == null ? "" : this.place.name;
|
|
75
|
-
}
|
|
76
|
-
},
|
|
77
|
-
methods: {
|
|
78
|
-
closeInfoWindow() {
|
|
79
|
-
this.infoWinOpen = false;
|
|
80
|
-
},
|
|
81
|
-
openInfoWindow() {
|
|
82
|
-
this.infoWinOpen = true;
|
|
83
|
-
},
|
|
84
|
-
toggleLoadingIndicator() {
|
|
85
|
-
this.$refs.loading.classList.toggle("d-none");
|
|
86
|
-
this.$refs.loading.classList.toggle("d-flex");
|
|
87
|
-
},
|
|
88
|
-
onActionButtonClick(event, properties) {
|
|
89
|
-
properties.onClick["formData"] = {
|
|
90
|
-
"place[google_place_id]": this.place.place_id,
|
|
91
|
-
"place[name]": this.place.name,
|
|
92
|
-
"place[address]": this.place.formatted_address,
|
|
93
|
-
"place[longitude]": this.place.geometry.location.lng(),
|
|
94
|
-
"place[latitude]": this.place.geometry.location.lat()
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
Action.execute(properties.onClick, this);
|
|
98
|
-
},
|
|
99
|
-
onMapClick(e) {
|
|
100
|
-
this.closeInfoWindow();
|
|
101
|
-
|
|
102
|
-
if (e.placeId === undefined) {
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
e.stop();
|
|
107
|
-
this.toggleLoadingIndicator();
|
|
108
|
-
|
|
109
|
-
const request = {
|
|
110
|
-
placeId: e.placeId,
|
|
111
|
-
fields: ["place_id", "geometry", "name", "formatted_address"]
|
|
112
|
-
};
|
|
113
|
-
var service = new google.maps.places.PlacesService(
|
|
114
|
-
this.$refs.map.$mapObject
|
|
115
|
-
);
|
|
116
|
-
service.getDetails(request, place => {
|
|
117
|
-
this.toggleLoadingIndicator();
|
|
118
|
-
this.markerPos = place.geometry.location;
|
|
119
|
-
this.place = place;
|
|
120
|
-
this.openInfoWindow();
|
|
121
|
-
});
|
|
122
|
-
},
|
|
123
|
-
setLocationField(name, value) {
|
|
124
|
-
let field = document.querySelector(`input[name="${name}"]`);
|
|
125
|
-
field.closest("div.v-input").classList.add("v-input--is-label-active");
|
|
126
|
-
field.closest("div.v-input").classList.add("v-input--is-dirty");
|
|
127
|
-
field.previousSibling.classList.add("v-label--active");
|
|
128
|
-
field.value = value;
|
|
129
|
-
},
|
|
130
|
-
setPlace(place) {
|
|
131
|
-
const { location } = place.geometry;
|
|
132
|
-
this.place = place;
|
|
133
|
-
this.markerPos = location;
|
|
134
|
-
this.$refs.map.$mapObject.setCenter(location);
|
|
135
|
-
|
|
136
|
-
if (Object.hasOwn(this.spec, "locationFields")) {
|
|
137
|
-
this.setLocationField(
|
|
138
|
-
this.spec.locationFields.latitudeName,
|
|
139
|
-
location.lat()
|
|
140
|
-
);
|
|
141
|
-
this.setLocationField(
|
|
142
|
-
this.spec.locationFields.longitudeName,
|
|
143
|
-
location.lng()
|
|
144
|
-
);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
};
|
|
149
|
-
</script>
|
|
150
|
-
|
|
151
|
-
<style scoped>
|
|
152
|
-
#loading-container {
|
|
153
|
-
position: absolute;
|
|
154
|
-
width: 100%;
|
|
155
|
-
height: 300px;
|
|
156
|
-
top: 0;
|
|
157
|
-
z-index: 100;
|
|
158
|
-
background: rgba(196, 154, 154, 0.1);
|
|
159
|
-
align-items: center;
|
|
160
|
-
justify-content: center;
|
|
161
|
-
}
|
|
162
|
-
</style>
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { defineComponent } from "vue";
|
|
2
|
-
import launch from "../../utils/launch";
|
|
3
|
-
import { htmlElement } from "../helper";
|
|
4
|
-
|
|
5
|
-
export default defineComponent({
|
|
6
|
-
data() {
|
|
7
|
-
return {
|
|
8
|
-
key: Math.random().toString(36).slice(2, 7)
|
|
9
|
-
};
|
|
10
|
-
},
|
|
11
|
-
computed: {
|
|
12
|
-
properties() {
|
|
13
|
-
return {
|
|
14
|
-
view: 'p',
|
|
15
|
-
text: this.spec.tooltip.text,
|
|
16
|
-
styleClasses: ['tooltip']
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
},
|
|
20
|
-
methods: {
|
|
21
|
-
handleMouseEnter() {
|
|
22
|
-
const properties = {
|
|
23
|
-
body: { childViews: [this.properties] },
|
|
24
|
-
key: this.key,
|
|
25
|
-
placement: this.spec.tooltip.placement || 'top',
|
|
26
|
-
styleClass: 'views-tooltip'
|
|
27
|
-
};
|
|
28
|
-
launch.popover.open(properties, this);
|
|
29
|
-
},
|
|
30
|
-
handleMouseLeave() {
|
|
31
|
-
launch.popover.close({ key: this.key });
|
|
32
|
-
},
|
|
33
|
-
$mounted() {
|
|
34
|
-
const tooltip = this.spec.tooltip;
|
|
35
|
-
|
|
36
|
-
if (!tooltip) return;
|
|
37
|
-
|
|
38
|
-
this.initTooltip();
|
|
39
|
-
},
|
|
40
|
-
$tearDown() {
|
|
41
|
-
const el = htmlElement(this);
|
|
42
|
-
|
|
43
|
-
if (el) {
|
|
44
|
-
el.removeEventListener('mouseenter', this.handleMouseEnter);
|
|
45
|
-
el.removeEventListener('mouseleave', this.handleMouseLeave);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
this.handleMouseLeave();
|
|
49
|
-
},
|
|
50
|
-
initTooltip() {
|
|
51
|
-
const el = htmlElement(this);
|
|
52
|
-
|
|
53
|
-
el.addEventListener('mouseenter', this.handleMouseEnter.bind(this));
|
|
54
|
-
el.addEventListener('mouseleave', this.handleMouseLeave.bind(this));
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
});
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { testPageUrl } from "../../helper"
|
|
2
|
-
const url = testPageUrl('multiupload')
|
|
3
|
-
|
|
4
|
-
describe('multiUpload', () => {
|
|
5
|
-
it('can change files', () => {
|
|
6
|
-
cy.visit(url)
|
|
7
|
-
|
|
8
|
-
cy.contains('clear files').click()
|
|
9
|
-
cy.contains('File (Example)').should('not.exist')
|
|
10
|
-
cy.contains('populate files').click()
|
|
11
|
-
cy.contains('File (Example)').should('exist')
|
|
12
|
-
|
|
13
|
-
cy.contains('submit').click()
|
|
14
|
-
|
|
15
|
-
// const result = `Method: POST
|
|
16
|
-
// Form Data:
|
|
17
|
-
// {
|
|
18
|
-
// "multi2": [
|
|
19
|
-
// "eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBSUT09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--e773c3169f0bac71fa589bddb1f77a04bc3771c9"
|
|
20
|
-
// ]
|
|
21
|
-
// }`
|
|
22
|
-
|
|
23
|
-
// cy.get('.unformatted').should('contain.text', result)
|
|
24
|
-
})
|
|
25
|
-
})
|