Skip to content

Instantly share code, notes, and snippets.

@mattlevine
Last active October 9, 2020 10:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save mattlevine/300626e39e776f034575473a81596411 to your computer and use it in GitHub Desktop.
Save mattlevine/300626e39e776f034575473a81596411 to your computer and use it in GitHub Desktop.
Headless Comment
<!--
This would run on a page that has an inited Mura.js instance. You would need to do this in a normal layout manager.
//Init Mura so you can make an initial api call to get the current page
Mura.init({
siteid:'default',
rootpath: 'http://localhost:8888',
processMarkup:false
}};
Mura.renderFilename('path/to/content').then((content)=>{
//Re-init Mura with the specific config for this content node
Mura.init(content.get('config');
//Then call something like this script.
Mura.loader().loadjs('https://cdn.jsdelivr.net/npm/vue/dist/vue.js',
app
);
});
//Or in the renderClient method of a client Mura.UI object. For an example visit this urls
https://github.com/blueriver/MuraVueDecoupled/blob/master/
https://github.com/blueriver/MuraVueDecoupled/blob/master/vue/mura.config.js
https://docs.getmura.com/v7-1/mura-developers/mura-rendering/murajs/modules-with-mura-js/
-->
<script>
app=()=>{
var app = new Vue({
template: '#app-template',
el: '#app',
data: function(){
return{
entityName:'comment',
collection:false,
entity:false,
sort:'',
keywords:'',
itemsPerPage:10,
maxItems:100,
applyingKeywords:false,
itemsPerPageOptions:[1,5,10,25,50,100],
permissions:{
read:false,
save:false,
delete:false
}
}
},
watch: {
itemsPerPage() {
this.load();
},
maxItems() {
this.load();
},
sort() {
this.load(false);
},
entity() {
},
keywords() {
this.load(false);
}
},
mounted: function() {
Mura.getEntity(this.entityName).get('permissions').then(
(permissions)=>{
this.permissions=permissions.getAll();
if(this.permissions.read){
this.load();
}
}
)
},
methods: {
load(reset){
if(typeof reset == 'undefined'){
reset=true;
}
if(reset){
this.collection=false;
this.entity=false;
}
let feed=Mura
.getFeed(this.entityName)
.where().prop('contentid').isEQ(Mura.contentid);
if(this.sort){
feed.sort(this.sort);
}
if(this.keywords){
feed
.openGrouping()
.prop('email').contains(this.keywords)
.orProp('name').contains(this.keywords)
.orProp('comments').contains(this.keywords)
.closeGrouping()
}
feed
.maxItems(this.maxItems)
.itemsPerPage(this.itemsPerPage)
.getQuery().then((collection)=>{
this.collection=collection;
if(this.applyingKeywords){
setTimeout(()=>{
Mura('#keywordsinput').focus();
this.applyingKeywords=false
}
,100
);
}
})
},
setSort(sortby){
if(typeof sortby=='undefined'){
this.sort="";
} else if(this.sort == sortby){
this.sort="-" + this.sort;
} else{
this.sort=sortby;
}
},
setKeywords(e){
if(e.charCode==13){
this.applyingKeywords=true;
this.keywords=Mura('#keywordsinput').val();
}
},
saveEntity(){
this.entity.set({
contentid:Mura.contentid,
contenthistid:Mura.contenthistid
});
this.entity.save().then(()=>this.load());
},
deleteEntity(){
this.entity.delete().then(()=>this.load());
},
goToPage(link){
link=link || 'missing';
if(this.collection.has(link)){
this.collection.get(link).then((collection)=>{
this.collection=collection;
})
}
},
closeForm(){
this.entity='';
},
viewEntity(entityInstance){
if(typeof entityInstance != 'undefined'){
this.entity=Mura.getEntity(this.entityName).set(Object.assign({},entityInstance.getAll()));
} else {
Mura.getEntity(this.entityName).new().then((entityInstance)=>{
this.entity=entityInstance;
});
}
return false;
}
}
})
};
Mura(()=>{
Mura.loader().loadjs('https://cdn.jsdelivr.net/npm/vue/dist/vue.js',
app
)
})
</script>
<template id="app-template">
<div >
<h3>Decoupled Comments</h3>
<div v-if="entity">
<div>
<div>
<button class="btn btn-light" v-on:click="closeForm()">Back</button>
</div>
<div class="alert alert-danger" role="alert" v-for="error in entity.get('errors')">
{{error}}
</div>
<div class="form-group">
<label for="name">Name</label><br/>
<input class="form-control" name="name" v-model="entity.properties.name"/>
</div>
<div class="form-group" v-if="this.permissions.delete || entity.get('isnew')">
<label for="email">Email</label><br/>
<input class="form-control" name="email" v-model="entity.properties.email"/>
</div>
<div class="form-group">
<label for="comments">Comments</label><br/>
<textarea class="form-control" v-model="entity.properties.comments"></textarea>
</div>
<div class="form-group">
<label for="comments">Subscribe
<input
type="checkbox"
v-model="entity.properties.subscribe"
true-value="1"
false-value="0"
>
</label>
</div>
<div v-if="this.permissions.save">
<button class="btn btn-primary" v-on:click="saveEntity()">Save</button>
<button class="btn btn-danger" v-if="!entity.get('isnew') && this.permissions.delete" v-on:click="deleteEntity()">Delete</button>
</div>
</div>
</div>
<div v-else-if="collection">
<div class="form-group">
<label for="description">Keyword Search</label><br/>
<input class="form-control" id="keywordsinput" type=text" v-bind:value="keywords" v-on:keypress="setKeywords"/>
</div>
<table>
<h2 v-on:click="setSort('entered')">
Entered <span v-if="this.sort=='-entered'">&#9660</span><span v-else>&#9650;</span>
</th>
</h2>
<ul >
<li v-for="item in collection.get('items')">
<h3 v-on:click.prevent="viewEntity(item);">{{item.get('name')}} ({{item.get('entered')}})</h3>
<div>{{item.get('comments')}}</div>
</li>
<li v-if="permissions.save">
<button class="btn btn-primary" v-on:click="viewEntity()">Add</button>
</li>
</ul>
<div>
<div>
<strong>{{collection.get('startindex')}}</strong> to <strong>{{collection.get('endindex')}}</strong> of <strong>{{collection.get('totalitems')}}</strong>
<select v-model="itemsPerPage">
<option v-for="option in itemsPerPageOptions" v-bind:value="option">
{{option}}
</option>
</select>
<button class="btn btn-light" v-if="collection.has('first')" v-on:click="goToPage('first')">First</button>
<button class="btn btn-light" v-if="collection.has('previous')" v-on:click="goToPage('previous')">&lt; Previous</button>
<button class="btn btn-light" v-if="collection.has('next')" v-on:click="goToPage('next')">Next &gt;</button>
<button class="btn btn-light" v-if="collection.has('last')" v-on:click="goToPage('last')">Last</button>
</div>
</div>
<div v-if="!this.permissions.read">
<div class="alert alert-info">
You currently do not have access to view this data.
</div>
</div>
<div v-if="!collection">
..loading...
</div>
</div>
</template>
<div id="app"></div>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment