changelog-server/public/js/app.js

196 lines
4.9 KiB
JavaScript

/* global initData, authorizationToken */
$(function(){
const actionToggle = function(e){
var el=e.target;
$(el).parent().siblings('.actions').show();
$(el).hide();
};
const deleteButton = function(e){
const el = $(e.target);
const url = el.attr('href');
$.ajax(url,{
method: "DELETE",
beforeSend: function(request) {
request.setRequestHeader("authorizationToken", authorizationToken);
}
})
.done(function(data) {
$(el).parents('.log').remove();
})
.fail(function() {
alert( "error" );
});
return false;
};
const editButton = function(e){
const el = $(e.target);
const id = el.attr("rel");
const pre = el.parents(".log").find("pre");
$.ajax(`/get/${id}`,{
beforeSend: function(request) {
request.setRequestHeader("authorizationToken", authorizationToken);
}
})
.done(function(data) {
pre
.text(data._source.content)
.attr('rel',id)
.css("background","#ccc")
.attr("contenteditable",true)
.focus();
$('body pre[contenteditable]').on('focusout', contentEdited );
})
.fail(function(data,err) {
console.log(data,err);
alert( "error" );
});
return false;
};
const contentEdited = function(e) {
const el = $(e.target);
const id = el.attr('rel');
const content = el.text();
$.ajax(`/patch/${id}`,{
method: "PATCH",
data: {content:content},
beforeSend: function(request) {
request.setRequestHeader("authorizationToken", authorizationToken);
}
})
.done(function(data) {
el
.css("background","")
.html( formatContent(content) );
})
.fail(function(data,err) {
console.log(data,err);
alert( "error" );
});
};
const search = function(e){
const el = $(e.target);
const val = el.val();
if( val.length < 3 ){ return; }
$.ajax("/search",{
beforeSend: function(request) {
request.setRequestHeader("authorizationToken", authorizationToken);
},
data: {
q:val
}
})
.done(function(data) {
updatePage(data);
})
.fail(function() {
alert( "error" );
});
};
// List of HTML entities for escaping.
var htmlEscapes = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#x27;',
'/': '&#x2F;'
};
// Regex containing the keys listed immediately above.
var htmlEscaper = /[&<>"'\/]/g;
// Escape a string for HTML interpolation.
const escape = function(string) {
return ('' + string).replace(htmlEscaper, function(match) {
return htmlEscapes[match];
});
};
const urlRegex = /(\S+): (https?:&#x2F;&#x2F;[^\s]+)/g;
const url = function(string){
return ''+string.replace(urlRegex, '<a target="_blank" href="$2">$1</a>');
};
var titleRegex = /^(.*\n)/;
const title = function(string){
return ''+string.replace(titleRegex, '<b>$1</b>');
};
var cmdRegex = /```([^`]*?)```/g;
const cmd = function(string) {
return ''+string.replace(cmdRegex, '<span class="cmd">$1</span>');
};
const date = function(string){
var D = new Date(string);
return D.toLocaleDateString()+" "+D.toLocaleTimeString();
};
const mailRegexp = /(.*) &lt;(.+@.+)&gt;/;
const mail = function( string ){
return ''+string.replace(mailRegexp, `<a href="mailto:${string}">$1</a>`);
};
const formatContent = function(string){
return cmd(title(url(escape(string))));
};
function updatePage(data){
var content = "";
var item = {};
var id = '';
// If the log entry is unique, simulate a search result
if( ! data['hits'] ){
data = {hits:{hits:[data]}};
}
$.each(data.hits.hits, (k,v)=>{
item = v._source;
id = v._id;
content += `
<div class="log row">
<div class="meta col-lg-2 ">
<p class="server"> ${escape(item.server)} </p>
<a href="/log/${id}">
${date(escape(item.created_at))} <br/>
</a>
<div class="d-none d-lg-block">
<p class="author"> ${mail(escape(item.author))} </p>
<p>
<a class="actions-toggle btn-link btn-sm">Actions</a>
</p>
<div class="actions btn-group btn-group-sm" role="group" aria-label="log actions">
<a class="delete btn btn btn-outline-secondary" rel="${id}" href="/delete/${id}">Remove</a>
<a class="edit btn btn btn-outline-secondary" rel="${id}" href="/edit/${id}">Edit</a>
</div>
</div>
</div>
<div class="col-lg data">
<pre> ${formatContent(item.content)}</pre>
</div>
</div>
`;
});
$("#content").html(content);
// attache events
$(".actions-toggle").on("click",actionToggle );
$('.delete').on('click', deleteButton);
$('.edit').on('click', editButton );
}
$("input").on("keyup",search );
updatePage( initData );
});