Compare commits
16 commits
60918e6ca5
...
3b9a0c0951
Author | SHA1 | Date | |
---|---|---|---|
![]() |
3b9a0c0951 | ||
![]() |
cb5e13b218 | ||
![]() |
c42a2b7129 | ||
![]() |
2482111d24 | ||
![]() |
bcd21d3697 | ||
![]() |
b6b47cc0d0 | ||
![]() |
cb4ea1b1d2 | ||
![]() |
99fff916d5 | ||
![]() |
151beb6d4c | ||
![]() |
fe40effaaa | ||
![]() |
0e1fa6965d | ||
![]() |
49ea7ed4a5 | ||
![]() |
d20943a487 | ||
![]() |
250579eaa2 | ||
![]() |
8603774778 | ||
![]() |
48f9afdedd |
|
@ -1,5 +1,5 @@
|
|||
# Force rtfd to use a recent version of mkdocs
|
||||
mkdocs==1.6.1
|
||||
pymdown-extensions==10.14
|
||||
pymdown-extensions==10.14.1
|
||||
mkdocs-material==9.5.50
|
||||
mkdocs-static-i18n==1.2.3
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# Force rtfd to use a recent version of mkdocs
|
||||
mkdocs==1.6.1
|
||||
pymdown-extensions==10.14
|
||||
pymdown-extensions==10.14.1
|
||||
mkdocs-material==9.5.50
|
||||
mkdocs-static-i18n==1.2.3
|
||||
|
|
|
@ -30,10 +30,10 @@ classifiers = [
|
|||
dependencies = [
|
||||
"Django==5.1.5",
|
||||
"django-agnocomplete==2.2.0",
|
||||
"django-environ==0.11.2",
|
||||
"django-environ==0.12.0",
|
||||
"django-probes==1.7.0",
|
||||
"Pillow==11.1.0",
|
||||
"psycopg==3.2.3",
|
||||
"psycopg==3.2.4",
|
||||
"requests==2.32.3",
|
||||
"rcssmin==1.2.0",
|
||||
"rjsmin==1.2.3",
|
||||
|
@ -44,13 +44,13 @@ dependencies = [
|
|||
[project.optional-dependencies]
|
||||
dev = [
|
||||
"hatch==1.14.0",
|
||||
"ruff==0.9.2",
|
||||
"ruff==0.9.3",
|
||||
"djlint==1.36.4",
|
||||
"mkdocs==1.6.1",
|
||||
"mkdocs-material==9.5.50",
|
||||
"mkdocs-static-i18n==1.2.3",
|
||||
"vermin==1.6.0",
|
||||
"pymdown-extensions==10.14",
|
||||
"pymdown-extensions==10.14.1",
|
||||
"isort==5.13.2",
|
||||
]
|
||||
test = [
|
||||
|
@ -71,7 +71,7 @@ s3 = [
|
|||
"django-storages[s3]==1.14.4",
|
||||
]
|
||||
sync = [
|
||||
"pydantic==2.10.5",
|
||||
"pydantic==2.10.6",
|
||||
"redis==5.2.1",
|
||||
]
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ h3, h4, h5 {
|
|||
margin-bottom: 14px;
|
||||
}
|
||||
p {
|
||||
line-height: 21px;
|
||||
line-height: 1.4;
|
||||
margin-top: 14px;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
.umap-main-edit-toolbox [type=button] {
|
||||
color: #fff;
|
||||
font-size: 1em;
|
||||
border: none;
|
||||
background-color: var(--color-darkGray);
|
||||
width: auto;
|
||||
margin-bottom: 0;
|
||||
|
@ -11,7 +10,7 @@
|
|||
}
|
||||
|
||||
.leaflet-container [type=button].umap-help-link {
|
||||
padding-bottom: 3px;
|
||||
padding: 0 var(--text-margin);
|
||||
background-color: inherit;
|
||||
}
|
||||
.leaflet-container .edit-save,
|
||||
|
@ -20,8 +19,6 @@
|
|||
.leaflet-container .connected-peers
|
||||
{
|
||||
display: block;
|
||||
border: none;
|
||||
border-radius: 20px;
|
||||
height: 32px;
|
||||
line-height: 30px;
|
||||
padding: 0 20px;
|
||||
|
@ -37,11 +34,6 @@
|
|||
color: var(--color-darkGray);
|
||||
}
|
||||
|
||||
.leaflet-container .edit-cancel,
|
||||
.leaflet-container .edit-disable,
|
||||
.leaflet-container .connected-peers{
|
||||
border: 0.5px solid rgba(153, 153, 153, 0.40);
|
||||
}
|
||||
.leaflet-container .edit-cancel:hover,
|
||||
.leaflet-container .edit-disable:hover {
|
||||
border: 0.5px solid rgba(153, 153, 153, 0.80);
|
||||
|
@ -120,7 +112,7 @@
|
|||
column-gap: 10px;
|
||||
}
|
||||
.umap-right-edit-toolbox {
|
||||
align-items: baseline;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.umap-main-edit-toolbox .logo {
|
||||
|
|
|
@ -76,15 +76,14 @@ select[multiple="multiple"] {
|
|||
.button,
|
||||
[type="button"],
|
||||
input[type="submit"] {
|
||||
display: block;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 14px;
|
||||
text-align: center;
|
||||
border-radius: 2px;
|
||||
font-weight: normal;
|
||||
cursor: pointer;
|
||||
padding: 7px 14px;
|
||||
min-height: 32px;
|
||||
line-height: 32px;
|
||||
padding: 3px 12px;
|
||||
border: none;
|
||||
text-decoration: none;
|
||||
background-color: white;
|
||||
|
@ -132,6 +131,11 @@ button.flat:hover,
|
|||
.dark [type="button"].flat:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.dark button.round,
|
||||
button.round {
|
||||
border-radius: 20px;
|
||||
border: 0.5px solid rgba(153, 153, 153, 0.40);
|
||||
}
|
||||
.help-text, .helptext {
|
||||
display: block;
|
||||
padding: 7px 7px;
|
||||
|
@ -572,17 +576,11 @@ input.blur {
|
|||
border-start-end-radius: 0;
|
||||
border-end-end-radius: 0;
|
||||
}
|
||||
.blur + .button:before,
|
||||
.blur + [type="button"]:before {
|
||||
content: '✔';
|
||||
}
|
||||
.blur + .button,
|
||||
.blur + [type="button"] {
|
||||
width: 40px;
|
||||
height: 18px;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
line-height: 18px;
|
||||
border-start-start-radius: 0;
|
||||
border-end-start-radius: 0;
|
||||
box-sizing: border-box;
|
||||
|
@ -591,6 +589,10 @@ input[type=hidden].blur + .button,
|
|||
input[type=hidden].blur + [type="button"] {
|
||||
display: none;
|
||||
}
|
||||
.blur-container {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
}
|
||||
.copiable-input {
|
||||
display: flex;
|
||||
align-items: end;
|
||||
|
|
|
@ -17,11 +17,11 @@
|
|||
background-image: url('../img/24.svg');
|
||||
--tile: -36px;
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
width: 36px;
|
||||
}
|
||||
.icon + span {
|
||||
margin-inline-start: 10px;
|
||||
margin-inline-start: 5px;
|
||||
margin-inline-end: 5px;
|
||||
}
|
||||
html[dir="rtl"] .icon {
|
||||
transform: scaleX(-1);
|
||||
|
@ -153,6 +153,12 @@ html[dir="rtl"] .icon {
|
|||
.icon-share {
|
||||
background-position: 0px calc(var(--tile) * 5);
|
||||
}
|
||||
.icon-star {
|
||||
background-position: var(--tile) calc(var(--tile) * 7);
|
||||
}
|
||||
.icon-starred {
|
||||
background-position: 0 calc(var(--tile) * 7);
|
||||
}
|
||||
.icon-table {
|
||||
background-position: calc(var(--tile) * 2) 0px;
|
||||
}
|
||||
|
|
|
@ -42,7 +42,8 @@
|
|||
padding: var(--panel-gutter);
|
||||
}
|
||||
.panel h3 {
|
||||
line-height: 120%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.panel .counter::before {
|
||||
counter-increment: step;
|
||||
|
|
|
@ -208,5 +208,7 @@
|
|||
<g id="g2-67" transform="translate(170.12 814.31)" clip-path="url(#clip0_2695_1939)">
|
||||
<path id="path1-5" d="m8.8453 14.83c-0.28116 0.6439-1.1722 0.6439-1.4533 0l-0.73138-1.6751c-0.65086-1.4907-1.8224-2.6774-3.2837-3.326l-2.0131-0.89358c-0.64004-0.28408-0.64004-1.2152 0-1.4993l1.9502-0.86569c1.4989-0.66535 2.6914-1.8959 3.3312-3.4375l0.74086-1.7852c0.27491-0.66247 1.1902-0.66247 1.4652 0l0.74083 1.7852c0.63972 1.5416 1.8322 2.7722 3.3311 3.4375l1.9503 0.86569c0.64 0.2841 0.64 1.2152 0 1.4993l-2.0131 0.89358c-1.4613 0.64864-2.6328 1.8353-3.2837 3.326zm-5.0624-6.6444c1.9049 0.84555 3.4537 2.2354 4.3357 4.1478 0.88202-1.9124 2.4308-3.3022 4.3356-4.1478-1.9276-0.85565-3.4813-2.3132-4.3356-4.2596-0.85434 1.9463-2.4081 3.4039-4.3357 4.2596zm12.385 10.723 0.2057-0.4714c0.3667-0.8405 1.0271-1.5098 1.8511-1.8758l0.6336-0.2816c0.3428-0.1523 0.3428-0.6504 0-0.8026l-0.5981-0.2658c-0.8453-0.3755-1.5175-1.0695-1.8779-1.9386l-0.2112-0.5094c-0.1473-0.355-0.6381-0.355-0.7853 0l-0.2112 0.5094c-0.3603 0.8691-1.0326 1.5631-1.8778 1.9386l-0.5983 0.2658c-0.3427 0.1522-0.3427 0.6503 0 0.8026l0.6337 0.2816c0.8241 0.366 1.4844 1.0353 1.8511 1.8758l0.2057 0.4714c0.1505 0.3451 0.6283 0.3451 0.7789 0zm-0.8557-3.0358 0.4687-0.4655 0.459 0.4655-0.459 0.4524z" fill="#efefef"/>
|
||||
</g>
|
||||
<path id="star" class="sprite" d="m7.6698 998.86 1.3886-5.255-4.0585-3.2468h5.1831l1.8193-5.4949 1.8147 5.4939h5.1829l-4.0615 3.2496 1.3838 5.2564-4.3249-3.0123z" fill="#efefef"/>
|
||||
<path id="starred" class="sprite" d="m31.67 998.86 1.3886-5.255-4.0585-3.2468h5.1831l1.8193-5.4949 1.8147 5.4939h5.1829l-4.0615 3.2496 1.3838 5.2565-4.3249-3.0123z" fill="none" stroke="#efefef" stroke-linecap="square" stroke-linejoin="round"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
|
@ -19,7 +19,7 @@
|
|||
<rect width="20" height="20" fill="#ffffff" id="rect1" x="0" y="0" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
<sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="14.041122" inkscape:cx="165.15774" inkscape:cy="24.998002" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="true" inkscape:window-width="1920" inkscape:window-height="1011" inkscape:window-x="0" inkscape:window-y="0" inkscape:window-maximized="1" showguides="true" inkscape:guide-bbox="true" inkscape:snap-grids="true" inkscape:snap-to-guides="true" inkscape:showpageshadow="2" inkscape:pagecheckerboard="0" inkscape:deskcolor="#d1d1d1">
|
||||
<sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="14.412751" inkscape:cx="41.352272" inkscape:cy="165.68662" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="true" inkscape:window-width="1920" inkscape:window-height="1011" inkscape:window-x="0" inkscape:window-y="0" inkscape:window-maximized="1" showguides="true" inkscape:guide-bbox="true" inkscape:snap-grids="true" inkscape:snap-to-guides="true" inkscape:showpageshadow="2" inkscape:pagecheckerboard="0" inkscape:deskcolor="#d1d1d1">
|
||||
<inkscape:grid type="xygrid" id="grid3004" empspacing="4" visible="true" enabled="true" snapvisiblegridlinesonly="true" originx="0" originy="0" spacingy="1" spacingx="1" units="px" />
|
||||
<inkscape:grid id="grid1" units="px" originx="0" originy="0" spacingx="24" spacingy="24" empcolor="#203fff" empopacity="0.85490196" color="#3f3fff" opacity="0.1254902" empspacing="1" enabled="true" visible="true" />
|
||||
</sodipodi:namedview>
|
||||
|
@ -219,5 +219,7 @@
|
|||
<g clip-path="url(#clip0_2695_1939)" id="g2-67" transform="translate(170.11621,814.31159)">
|
||||
<path d="m 8.84533,14.8298 c -0.28116,0.6439 -1.1722,0.6439 -1.45333,0 l -0.73138,-1.6751 c -0.65086,-1.4907 -1.82238,-2.6774 -3.2837,-3.32604 l -2.0131,-0.89358 c -0.64004,-0.28408 -0.64004,-1.21518 0,-1.49928 l 1.95022,-0.86569 c 1.4989,-0.66535 2.69143,-1.89594 3.33118,-3.43751 l 0.74086,-1.78516 c 0.27491,-0.662471 1.19025,-0.662472 1.46517,0 l 0.74083,1.78517 c 0.63972,1.54156 1.83222,2.77215 3.33112,3.4375 l 1.9503,0.86569 c 0.64,0.2841 0.64,1.2152 0,1.49928 l -2.0131,0.89358 c -1.4613,0.64864 -2.6328,1.83534 -3.28374,3.32604 z m -5.06236,-6.64435 c 1.90486,0.84555 3.45371,2.23535 4.33568,4.14775 0.88202,-1.9124 2.43085,-3.3022 4.33565,-4.14775 -1.9276,-0.85565 -3.4813,-2.31323 -4.33564,-4.25955 -0.85434,1.94633 -2.4081,3.4039 -4.33569,4.25955 z m 12.38483,10.72295 0.2057,-0.4714 c 0.3667,-0.8405 1.0271,-1.5098 1.8511,-1.8758 l 0.6336,-0.2816 c 0.3428,-0.1523 0.3428,-0.6504 0,-0.8026 l -0.5981,-0.2658 c -0.8453,-0.3755 -1.5175,-1.0695 -1.8779,-1.9386 l -0.2112,-0.5094 c -0.1473,-0.355 -0.6381,-0.355 -0.7853,0 l -0.2112,0.5094 c -0.3603,0.8691 -1.0326,1.5631 -1.8778,1.9386 l -0.5983,0.2658 c -0.3427,0.1522 -0.3427,0.6503 0,0.8026 l 0.6337,0.2816 c 0.8241,0.366 1.4844,1.0353 1.8511,1.8758 l 0.2057,0.4714 c 0.1505,0.3451 0.6283,0.3451 0.7789,0 z m -0.8557,-3.0358 0.4687,-0.4655 0.459,0.4655 -0.459,0.4524 z" fill="#efefef" id="path1-5" />
|
||||
</g>
|
||||
<path style="fill:#efefef;fill-opacity:1;stroke:none;stroke-width:6.97518;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" inkscape:transform-center-x="-0.0010932573" inkscape:transform-center-y="-0.7377641" d="m 7.6698317,998.8588 1.3886278,-5.25497 -4.0584591,-3.24679 h 5.1830926 l 1.819345,-5.49493 1.81469,5.49392 h 5.182872 l -4.06154,3.24965 1.383849,5.25642 -4.324867,-3.01228 z" id="star" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccc" class="sprite" />
|
||||
<path style="fill:none;fill-opacity:1;stroke:#efefef;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" inkscape:transform-center-x="-0.0010925804" inkscape:transform-center-y="-0.73776941" d="m 31.669832,998.8588 1.388628,-5.25501 -4.05846,-3.24679 h 5.183093 l 1.819345,-5.49493 1.814694,5.49392 h 5.182868 l -4.06154,3.24964 1.383849,5.25647 -4.324874,-3.01232 z" id="starred" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccc" class="sprite" />
|
||||
</g>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 75 KiB |
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 44 KiB |
|
@ -1,5 +1,6 @@
|
|||
import { translate } from './i18n.js'
|
||||
import * as Utils from './utils.js'
|
||||
import { uMapAlert as Alert } from '../components/alerts/alert.js'
|
||||
|
||||
const TEMPLATE = `
|
||||
<div class="umap-caption">
|
||||
|
@ -7,8 +8,9 @@ const TEMPLATE = `
|
|||
<i class="icon icon-16 icon-caption icon-block"></i>
|
||||
<hgroup>
|
||||
<h3><span class="map-name" data-ref="name"></span></h3>
|
||||
<h4 data-ref="author"></h4>
|
||||
<h5 class="dates" data-ref="dates"></h5>
|
||||
<p class="dates" data-ref="dates"></p>
|
||||
<p data-ref="author"></p>
|
||||
<p><button type="button" class="round" data-ref="star" title="${translate('Star this map')}"><i class="icon icon-16 icon-star map-star"></i><span class="map-stars"></span></button></p>
|
||||
</hgroup>
|
||||
</div>
|
||||
<div class="umap-map-description text" data-ref="description"></div>
|
||||
|
@ -35,6 +37,14 @@ export default class Caption extends Utils.WithTemplate {
|
|||
this._umap = umap
|
||||
this._leafletMap = leafletMap
|
||||
this.loadTemplate(TEMPLATE)
|
||||
this.elements.star.addEventListener('click', async () => {
|
||||
if (this._umap.properties.user?.id) {
|
||||
await this._umap.star()
|
||||
this.refresh()
|
||||
} else {
|
||||
Alert.error(translate('You must be logged in'))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
isOpen() {
|
||||
|
@ -62,10 +72,6 @@ export default class Caption extends Utils.WithTemplate {
|
|||
this.addDataLayer(datalayer, this.elements.datalayersContainer)
|
||||
)
|
||||
this.addCredits()
|
||||
this._umap.panel.open({ content: this.element }).then(() => {
|
||||
// Create the legend when the panel is actually on the DOM
|
||||
this._umap.eachDataLayerReverse((datalayer) => datalayer.renderLegend())
|
||||
})
|
||||
if (this._umap.properties.created_at) {
|
||||
const created_at = translate('Created at {date}', {
|
||||
date: new Date(this._umap.properties.created_at).toLocaleDateString(),
|
||||
|
@ -77,6 +83,11 @@ export default class Caption extends Utils.WithTemplate {
|
|||
} else {
|
||||
this.elements.dates.hidden = true
|
||||
}
|
||||
this._umap.panel.open({ content: this.element }).then(() => {
|
||||
// Create the legend when the panel is actually on the DOM
|
||||
this._umap.eachDataLayerReverse((datalayer) => datalayer.renderLegend())
|
||||
this._umap.propagate()
|
||||
})
|
||||
}
|
||||
|
||||
addDataLayer(datalayer, parent) {
|
||||
|
|
|
@ -132,7 +132,10 @@ Fields.Textarea = class extends BaseElement {
|
|||
super.build()
|
||||
this.textarea = this.elements.textarea
|
||||
this.fetch()
|
||||
this.textarea.addEventListener('input', () => this.sync())
|
||||
this.textarea.addEventListener(
|
||||
'input',
|
||||
Utils.debounce(() => this.sync(), 300)
|
||||
)
|
||||
this.textarea.addEventListener('keypress', (event) => this.onKeyPress(event))
|
||||
}
|
||||
|
||||
|
@ -179,7 +182,7 @@ Fields.Input = class extends BaseElement {
|
|||
this.input.step = this.properties.step
|
||||
}
|
||||
this.fetch()
|
||||
this.input.addEventListener(this.getSyncEvent(), () => this.sync())
|
||||
this.listenForSync()
|
||||
this.input.addEventListener('keydown', (event) => this.onKeyDown(event))
|
||||
}
|
||||
|
||||
|
@ -189,8 +192,11 @@ Fields.Input = class extends BaseElement {
|
|||
this.input.value = value
|
||||
}
|
||||
|
||||
getSyncEvent() {
|
||||
return 'input'
|
||||
listenForSync() {
|
||||
this.input.addEventListener(
|
||||
'input',
|
||||
Utils.debounce(() => this.sync(), 300)
|
||||
)
|
||||
}
|
||||
|
||||
type() {
|
||||
|
@ -212,12 +218,12 @@ Fields.Input = class extends BaseElement {
|
|||
}
|
||||
|
||||
Fields.BlurInput = class extends Fields.Input {
|
||||
getSyncEvent() {
|
||||
return 'blur'
|
||||
listenForSync() {
|
||||
this.input.addEventListener('blur', () => this.sync())
|
||||
}
|
||||
|
||||
getTemplate() {
|
||||
return `${super.getTemplate()}<span class="button blur-button"></span>`
|
||||
return `<div class="blur-container">${super.getTemplate()}<button type="button">✔</button></div>`
|
||||
}
|
||||
|
||||
build() {
|
||||
|
@ -856,10 +862,10 @@ Fields.IconUrl = class extends Fields.BlurInput {
|
|||
}
|
||||
|
||||
buildInput(parent, value) {
|
||||
const input = Utils.loadTemplate('<input class="blur" />')
|
||||
const button = Utils.loadTemplate('<span class="button blur-button"></span>')
|
||||
parent.appendChild(input)
|
||||
parent.appendChild(button)
|
||||
const [element, { input }] = Utils.loadTemplateWithRefs(
|
||||
'<div class="blur-container"><input class="blur" data-ref="input" /><button type="button">✔</button></div>'
|
||||
)
|
||||
parent.appendChild(element)
|
||||
if (value) input.value = value
|
||||
input.addEventListener('blur', () => {
|
||||
// Do not clear this.input when focus-blur
|
||||
|
|
|
@ -32,7 +32,6 @@ const ControlsMixin = {
|
|||
'locate',
|
||||
'measure',
|
||||
'editinosm',
|
||||
'star',
|
||||
'tilelayers',
|
||||
],
|
||||
|
||||
|
@ -84,7 +83,6 @@ const ControlsMixin = {
|
|||
this._controls.search = new U.SearchControl()
|
||||
this._controls.embed = new Control.Embed(this._umap)
|
||||
this._controls.tilelayersChooser = new U.TileLayerChooser(this)
|
||||
if (this.options.user?.id) this._controls.star = new U.StarControl(this._umap)
|
||||
this._controls.editinosm = new Control.EditInOSM({
|
||||
position: 'topleft',
|
||||
widgetOptions: {
|
||||
|
|
|
@ -478,12 +478,6 @@ export const SCHEMA = {
|
|||
label: translate('Sort key'),
|
||||
inheritable: true,
|
||||
},
|
||||
starControl: {
|
||||
type: Boolean,
|
||||
impacts: ['ui'],
|
||||
nullable: true,
|
||||
label: translate('Display the star map button'),
|
||||
},
|
||||
stroke: {
|
||||
type: Boolean,
|
||||
impacts: ['data'],
|
||||
|
|
|
@ -7,8 +7,8 @@ const TOP_BAR_TEMPLATE = `
|
|||
<div class="umap-main-edit-toolbox with-transition dark">
|
||||
<div class="umap-left-edit-toolbox" data-ref="left">
|
||||
<div class="logo"><a class="" href="/" title="${translate('Go to the homepage')}">uMap</a></div>
|
||||
<button class="map-name" type="button" data-ref="name"></button>
|
||||
<button class="share-status" type="button" data-ref="share"></button>
|
||||
<button class="map-name flat" type="button" data-ref="name"></button>
|
||||
<button class="share-status flat" type="button" data-ref="share"></button>
|
||||
</div>
|
||||
<div class="umap-right-edit-toolbox" data-ref="right">
|
||||
<button class="connected-peers round" type="button" data-ref="peers">
|
||||
|
@ -19,7 +19,7 @@ const TOP_BAR_TEMPLATE = `
|
|||
<i class="icon icon-16 icon-profile"></i>
|
||||
<span class="username" data-ref="username"></span>
|
||||
</button>
|
||||
<button class="umap-help-link" type="button" title="${translate('Help')}" data-ref="help">${translate('Help')}</button>
|
||||
<button class="umap-help-link flat" type="button" title="${translate('Help')}" data-ref="help">${translate('Help')}</button>
|
||||
<button class="edit-cancel round" type="button" data-ref="cancel">
|
||||
<i class="icon icon-16 icon-restore"></i>
|
||||
<span class="">${translate('Cancel edits')}</span>
|
||||
|
|
|
@ -1366,7 +1366,11 @@ export default class Umap extends ServerStored {
|
|||
},
|
||||
'properties.starred': () => {
|
||||
Utils.eachElement('.map-star', (el) => {
|
||||
el.classList.toggle('starred', this.properties.starred)
|
||||
el.classList.toggle('icon-starred', this.properties.starred)
|
||||
el.classList.toggle('icon-star', !this.properties.starred)
|
||||
})
|
||||
Utils.eachElement('.map-stars', (el) => {
|
||||
el.textContent = this.properties.stars || 0
|
||||
})
|
||||
},
|
||||
}
|
||||
|
@ -1549,6 +1553,7 @@ export default class Umap extends ServerStored {
|
|||
return
|
||||
}
|
||||
this.properties.starred = data.starred
|
||||
this.properties.stars = data.stars
|
||||
Alert.success(
|
||||
data.starred
|
||||
? translate('Map has been starred')
|
||||
|
|
|
@ -471,6 +471,19 @@ export function isWritable(element) {
|
|||
return false
|
||||
}
|
||||
|
||||
// From https://www.joshwcomeau.com/snippets/javascript/debounce/
|
||||
export const debounce = (callback, wait) => {
|
||||
let timeoutId = null
|
||||
|
||||
return (...args) => {
|
||||
window.clearTimeout(timeoutId)
|
||||
|
||||
timeoutId = window.setTimeout(() => {
|
||||
callback.apply(null, args)
|
||||
}, wait)
|
||||
}
|
||||
}
|
||||
|
||||
export const COLORS = [
|
||||
'Black',
|
||||
'Navy',
|
||||
|
|
|
@ -491,18 +491,6 @@ U.CaptionControl = L.Control.Button.extend({
|
|||
},
|
||||
})
|
||||
|
||||
U.StarControl = L.Control.Button.extend({
|
||||
options: {
|
||||
position: 'topleft',
|
||||
title: L._('Star this map'),
|
||||
className: 'leaflet-control-star map-star umap-control',
|
||||
},
|
||||
|
||||
onClick: function () {
|
||||
this._umap.star()
|
||||
},
|
||||
})
|
||||
|
||||
L.Control.Embed = L.Control.Button.extend({
|
||||
options: {
|
||||
position: 'topleft',
|
||||
|
|
|
@ -134,12 +134,6 @@ html[dir="rtl"] .leaflet-tooltip-pane > * {
|
|||
background-position: -72px -144px;
|
||||
box-shadow: 0 0 4px 0 black inset;
|
||||
}
|
||||
.leaflet-control-star [type="button"] {
|
||||
background-position: -144px -144px;
|
||||
}
|
||||
.leaflet-control-star.starred [type="button"] {
|
||||
background-position: -108px -144px;
|
||||
}
|
||||
.leaflet-control-search [type="button"] {
|
||||
background-position: -36px -108px;
|
||||
display: block;
|
||||
|
@ -703,6 +697,10 @@ a.umap-control-caption,
|
|||
.umap-caption .header i.icon {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.umap-caption hgroup p,
|
||||
.umap-caption hgroup button {
|
||||
margin: 0;
|
||||
}
|
||||
.umap-browser .main-toolbox {
|
||||
padding-left: 4px; /* Align with toolbox below */
|
||||
border-top: 1px solid var(--color-mediumGray);
|
||||
|
|
|
@ -191,7 +191,7 @@ def test_sortkey_impacts_datalayerindex(map, live_server, page):
|
|||
page.locator('input[name="sortKey"]').fill("key")
|
||||
|
||||
# Click the checkmark to apply the changes
|
||||
page.locator(".panel .umap-field-sortKey .blur-button").click()
|
||||
page.locator(".panel .umap-field-sortKey .blur-container button").click()
|
||||
|
||||
# Features should be sorted by key (First, Second, Third)
|
||||
first_listed_feature = page.locator(".umap-browser .datalayer ul > li").nth(0)
|
||||
|
|
|
@ -24,6 +24,7 @@ def test_layers_list_is_updated(live_server, tilelayer, page):
|
|||
page.get_by_role("button", name="Add a layer").click()
|
||||
page.locator('input[name="name"]').click()
|
||||
page.locator('input[name="name"]').fill("foobar")
|
||||
page.wait_for_timeout(300) # Time for the input debounce.
|
||||
page.get_by_role("link", name=f"Import data ({modifier}+I)").click()
|
||||
# Should still work
|
||||
page.locator("[name=layer-id]").select_option(label="Import in a new layer")
|
||||
|
|
|
@ -285,6 +285,7 @@ def test_should_display_alert_on_conflict(context, live_server, datalayer, openm
|
|||
# Change name on page one and save
|
||||
page_one.locator(".leaflet-marker-icon").click(modifiers=["Shift"])
|
||||
page_one.locator('input[name="name"]').fill("name from page one")
|
||||
page_one.wait_for_timeout(300) # Time for the input debounce.
|
||||
with page_one.expect_response(re.compile(r".*/datalayer/update/.*")):
|
||||
page_one.get_by_role("button", name="Save").click()
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ def test_reseting_map_would_remove_from_save_queue(
|
|||
page.get_by_role("button", name="Edit", exact=True).click()
|
||||
page.locator('input[name="name"]').click()
|
||||
page.locator('input[name="name"]').fill("new datalayer name")
|
||||
page.wait_for_timeout(300) # Time of the Input debounce
|
||||
with page.expect_response(re.compile(".*/datalayer/update/.*")):
|
||||
page.get_by_role("button", name="Save").click()
|
||||
assert len(requests) == 1
|
||||
|
|
|
@ -8,20 +8,24 @@ from umap.models import Star
|
|||
pytestmark = pytest.mark.django_db
|
||||
|
||||
|
||||
def test_star_control_is_visible_if_logged_in(map, live_server, page, login, user):
|
||||
def test_star_button_is_active_if_logged_in(map, live_server, page, login, user):
|
||||
login(user)
|
||||
assert not Star.objects.count()
|
||||
page.goto(f"{live_server.url}{map.get_absolute_url()}")
|
||||
page.get_by_title("More controls").click()
|
||||
control = page.locator(".leaflet-control-star")
|
||||
expect(control).to_be_visible()
|
||||
page.get_by_title("About").click()
|
||||
button = page.locator(".icon-star")
|
||||
expect(button).to_be_visible()
|
||||
with page.expect_response(re.compile(".*/star/")):
|
||||
control.click()
|
||||
button.click()
|
||||
expect(button).to_be_hidden()
|
||||
# Button has changed
|
||||
expect(page.locator(".icon-starred")).to_be_visible()
|
||||
assert Star.objects.count() == 1
|
||||
|
||||
|
||||
def test_no_star_control_if_not_logged_in(map, live_server, page):
|
||||
def test_star_button_inctive_if_not_logged_in(map, live_server, page):
|
||||
page.goto(f"{live_server.url}{map.get_absolute_url()}")
|
||||
page.get_by_title("More controls").click()
|
||||
control = page.locator(".leaflet-control-star")
|
||||
expect(control).to_be_hidden()
|
||||
page.get_by_title("About").click()
|
||||
button = page.locator(".icon-star")
|
||||
button.click()
|
||||
expect(page.get_by_text("You must be logged in")).to_be_visible()
|
||||
|
|
|
@ -74,6 +74,7 @@ def test_table_editor(live_server, openmap, datalayer, page):
|
|||
page.locator("dialog").get_by_role("button", name="OK").click()
|
||||
page.locator("td").nth(2).dblclick()
|
||||
page.locator('input[name="newprop"]').fill("newvalue")
|
||||
page.wait_for_timeout(300) # Time for the input debounce.
|
||||
page.keyboard.press("Enter")
|
||||
page.locator("thead button[data-property=name]").click()
|
||||
page.get_by_role("button", name="Delete this column").click()
|
||||
|
|
|
@ -56,6 +56,7 @@ def test_websocket_connection_can_sync_markers(new_page, asgi_live_server, tilel
|
|||
expect(peerB.get_by_role("button", name="Cancel edits")).to_be_hidden()
|
||||
peerA.locator("body").type("Synced name")
|
||||
peerA.locator("body").press("Escape")
|
||||
peerA.wait_for_timeout(300)
|
||||
|
||||
peerB.locator(".leaflet-marker-icon").first.click()
|
||||
peerB.get_by_role("link", name="Toggle edit mode (⇧+Click)").click()
|
||||
|
@ -320,6 +321,7 @@ def test_websocket_connection_can_sync_late_joining_peer(
|
|||
a_map_el.click(position={"x": 220, "y": 220})
|
||||
peerA.locator("body").type("First marker")
|
||||
peerA.locator("body").press("Escape")
|
||||
peerA.wait_for_timeout(300)
|
||||
|
||||
# Add a polygon from peer A
|
||||
create_polygon = peerA.locator(".leaflet-control-toolbar ").get_by_title(
|
||||
|
|
|
@ -605,6 +605,7 @@ class MapDetailMixin(SessionMixin):
|
|||
"schema": Map.extra_schema,
|
||||
"id": self.get_id(),
|
||||
"starred": self.is_starred(),
|
||||
"stars": self.stars(),
|
||||
"licences": dict((l.name, l.json) for l in Licence.objects.all()),
|
||||
"umap_version": VERSION,
|
||||
"featuresHaveOwner": settings.UMAP_DEFAULT_FEATURES_HAVE_OWNERS,
|
||||
|
@ -677,6 +678,9 @@ class MapDetailMixin(SessionMixin):
|
|||
def is_starred(self):
|
||||
return False
|
||||
|
||||
def stars(self):
|
||||
return 0
|
||||
|
||||
def get_geojson(self):
|
||||
return {
|
||||
"geometry": {
|
||||
|
@ -779,6 +783,9 @@ class MapView(MapDetailMixin, PermissionsMixin, DetailView):
|
|||
return False
|
||||
return Star.objects.filter(by=user, map=self.object).exists()
|
||||
|
||||
def stars(self):
|
||||
return Star.objects.filter(map=self.object).count()
|
||||
|
||||
|
||||
class MapDownload(DetailView):
|
||||
model = Map
|
||||
|
@ -1080,7 +1087,9 @@ class ToggleMapStarStatus(View):
|
|||
else:
|
||||
Star.objects.create(map=map_inst, by=self.request.user)
|
||||
status = True
|
||||
return simple_json_response(starred=status)
|
||||
return simple_json_response(
|
||||
starred=status, stars=Star.objects.filter(map=map_inst).count()
|
||||
)
|
||||
|
||||
|
||||
class MapShortUrl(RedirectView):
|
||||
|
|