Newer
Older
<div class="margin-bottom">
<img
class="ui small centered image"
alt="Thumbnail du projet"
:src="
project.thumbnail.includes('default')
? require('@/assets/img/default.png')
: DJANGO_BASE_URL + project.thumbnail + refreshId()
"
>
<div class="centered">
<div
class="ui basic teal label tiny-margin"
data-tooltip="Membres"
>
<i
class="user icon"
aria-hidden="true"
/>{{ project.nb_contributors }}
</div>
<div
class="ui basic teal label tiny-margin"
data-tooltip="Signalements publiés"
>
<i
class="map marker icon"
aria-hidden="true"
/>{{ project.nb_published_features }}
</div>
<div
class="ui basic teal label tiny-margin"
data-tooltip="Commentaires"
>
<i
class="comment icon"
aria-hidden="true"
/>{{
project.nb_published_features_comments
}}
</div>
<h1 class="ui header margin-bottom">
<!-- {{ project.description }} -->
<div id="preview" />
<textarea
id="editor"
v-model="project.description"
data-preview="#preview"
hidden
/>
</div>
</div>
<div class="four wide column right-column">
<div class="ui icon right compact buttons">
<a
v-if="
user &&
permissions &&
permissions.can_view_project &&
class="ui button button-hover-green tiny-margin"
data-tooltip="Gérer mon abonnement au projet"

Timothee P
committed
data-position="bottom center"
data-variation="mini"
@click="OPEN_PROJECT_MODAL('subscribe')"
>
<i
class="inverted grey envelope icon"
aria-hidden="true"
/>
</a>
<router-link
v-if="
permissions &&
permissions.can_update_project &&
class="ui button button-hover-orange tiny-margin"

Timothee P
committed
data-position="bottom center"
<i
class="inverted grey pencil alternate icon"
aria-hidden="true"
/>
v-if="isProjectAdmin && isOnline"
class="ui button button-hover-red tiny-margin"

Timothee P
committed
data-position="bottom right"
data-variation="mini"
@click="OPEN_PROJECT_MODAL('deleteProject')"
>
<i
class="inverted grey trash icon"
aria-hidden="true"
/>
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
<div
v-if="isProjectAdmin && !isSharedProject"
id="share-button"
class="ui dropdown button compact tiny-margin"
data-tooltip="Partager le projet"
data-position="bottom right"
data-variation="mini"
@click="toggleShareOptions"
>
<i
class="inverted grey share icon"
aria-hidden="true"
/>
<div
:class="['menu left transition', {'visible': showShareOptions}]"
style="z-index: 9999"
>
<div
v-if="project.generate_share_link"
class="item"
@click="copyLink"
>
Copier le lien de partage
</div>
<div
class="item"
@click="copyCode"
>
Copier le code du Web Component
</div>
</div>
</div>
<Transition>
<div
v-if="confirmMsg"
class="ui positive tiny-margin message"
>
<span>
Le lien a été copié dans le presse-papier
</span>
@click="confirmMsg = false"
<div
v-if="arraysOffline.length > 0"
class="centered"
>
{{ arraysOffline.length }} modification<span v-if="arraysOffline.length > 1">s</span> en attente
:disabled="!isOnline"
Envoyer au serveur
</button>
</div>
</div>
</div>
</template>
<script>
import TextareaMarkdown from 'textarea-markdown';
import { mapState, mapGetters, mapMutations } from 'vuex';
name: 'ProjectHeader',
props: {
arraysOffline: {
type: Array,
default: () => {
return [];
}
}
},
data() {
return {
slug: this.$route.params.slug,
confirmMsg: false,
showShareOptions: false,
};
},
computed: {
...mapState('projects', [
'project'
]),
...mapState([
'configuration',
]),
...mapState([
'user',
'user_permissions',
'isOnline',
]),
...mapGetters([
'permissions'
]),
DJANGO_BASE_URL() {
return this.configuration.VUE_APP_DJANGO_BASE;
},
isProjectAdmin() {
return this.user_permissions && this.user_permissions[this.slug] &&
this.user_permissions[this.slug].is_project_administrator;
},
isSharedProject() {
return this.$route.path.includes('projet-partage');
},
},
mounted() {
let textarea = document.querySelector('textarea');
new TextareaMarkdown(textarea);
window.addEventListener('mousedown', this.clickOutsideDropdown);
},
destroyed() {
window.removeEventListener('mousedown', this.clickOutsideDropdown);
methods: {
...mapMutations('modals', [
'OPEN_PROJECT_MODAL'
]),
refreshId() {
const crypto = window.crypto || window.msCrypto;
var array = new Uint32Array(1);
return '?ver=' + crypto.getRandomValues(array); // Compliant for security-sensitive use cases
toggleShareOptions() {
this.confirmMsg = false;
this.showShareOptions = !this.showShareOptions;
},
clickOutsideDropdown(e) {
// If the user click outside of the dropdown, close it
if (!e.target.closest('#share-button')) {
this.showShareOptions = false;
}
},
copyLink() {
const sharedLink = window.location.href.replace('projet', 'projet-partage');
navigator.clipboard.writeText(sharedLink).then(()=> {
this.confirmMsg = true;
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
setTimeout(() => {
this.confirmMsg = false;
}, 15000);
}, (e) => console.error('Failed to copy link: ', e));
},
copyCode() {
// Including <script> directly within template literals cause the JavaScript parser to raise syntax errors.
// The only working workaround, but ugly, is to split and concatenate the <script> tag.
const webComponent = `
<!-- Pour modifier la police, ajoutez l'attribut "font" avec le nom de la police souhaitée (par exemple: font="'Roboto Condensed', Lato, 'Helvetica Neue'"). -->
<!-- Dans le cas où la police souhaitée ne serait pas déjà disponible dans la page affichant le web component, incluez également une balise <style> pour l'importer. -->
<style>@import url('https://fonts.googleapis.com/css?family=Roboto Condensed:400,700,400italic,700italic&subset=latin');</style>
<scr` + `ipt src="${this.configuration.VUE_APP_DJANGO_BASE}/geocontrib/static/wc/project-preview.js"></scr` + `ipt>
<project-preview
domain="${this.configuration.VUE_APP_DJANGO_BASE}"
project-slug="${this.project.slug}"
color="${this.configuration.VUE_APP_PRIMARY_COLOR}"
font="${this.configuration.VUE_APP_FONT_FAMILY}"
width=""
></project-preview>`;
navigator.clipboard.writeText(webComponent).then(()=> {
this.confirmMsg = true;
setTimeout(() => {
this.confirmMsg = false;
}, 15000);
}, (e) => console.error('Failed to copy link: ', e));
sendOfflineFeatures() {
this.arraysOfflineErrors = [];
const promises = this.arraysOffline.map((feature) => featureAPI.postOrPutFeature({
data: feature.geojson,
feature_id: feature.featureId,
project__slug: feature.project,
feature_type__slug: feature.geojson.properties.feature_type,
method: feature.type.toUpperCase(),
})
.then((response) => {
if (!response) {
this.arraysOfflineErrors.push(feature);
}
})
.catch((error) => {
console.error(error);
this.arraysOfflineErrors.push(feature);
})
);
this.$store.commit('DISPLAY_LOADER', 'Envoi des signalements en cours.');
this.$emit('updateLocalStorage');
this.$emit('retrieveInfo');
this.$store.commit('DISCARD_LOADER');
}
};
</script>
<style lang="less" scoped>
.project-header {
.row .right-column {
display: flex;
flex-direction: column;
.ui.buttons {
justify-content: flex-end;
flex-grow: 0; /* avoid stretching buttons */
}
.centered {
margin: auto;
text-align: center;
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
.ui.dropdown > .left.menu {
display: block;
overflow: hidden;
opacity: 0;
max-height: 0;
&.transition {
transition: all .5s ease;
}
&.visible {
opacity: 1;
max-height: 6em;
}
.menu {
margin-right: 0 !important;
.item {
white-space: nowrap;
}
}
}
.v-enter-active,
.v-leave-active {
transition: opacity .5s ease;
}
.v-enter-from,
.v-leave-to {
opacity: 0;
}

Florent Lavelle
committed
overflow-y: scroll;
@media screen and (max-width: 767px) {
.middle.aligned.column {
text-align: center;
}
}