chg: rewrote most client-side code with alpine.js

This commit is contained in:
Tobi Schäfer 2020-05-02 17:36:47 +02:00
parent 21191ded75
commit eaa3ba2357
17 changed files with 157 additions and 316 deletions

View file

@ -78,14 +78,14 @@
</div>
</div>
</fieldset>
<fieldset class='uk-margin-top'>
<fieldset class='uk-margin-top' x-data='{ creationScope: "<% root.creationScope %>" }'>
<legend><% gettext 'Site Creation' %></legend>
<div class='uk-form-row'>
<label class='uk-form-label' for='creationScope'>
<% gettext 'Required Account Status' %>
</label>
<div class='uk-form-controls'>
<% root.select creationScope %>
<% root.select creationScope x-model='creationScope' %>
</div>
</div>
<div class='uk-form-row'>
@ -93,7 +93,7 @@
<% gettext 'Probation Period' %>
</label>
<div class='uk-form-controls'>
<% root.input probationPeriod class=uk-width-1-6 type=number min=0 %> <% gettext days %>
<% root.input probationPeriod class=uk-width-1-6 type=number min=0 :disabled="creationScope !== 'regular'" %> <% gettext days %>
</div>
</div>
<div class='uk-form-row'>
@ -101,18 +101,18 @@
<% gettext Interval %>
</label>
<div class='uk-form-controls'>
<% root.input creationDelay class=uk-width-1-6 type=number min=0 %> <% gettext days %>
<% root.input creationDelay class=uk-width-1-6 type=number min=0 :disabled="creationScope !== 'regular'" %> <% gettext days %>
</div>
</div>
</fieldset>
<fieldset class='uk-margin-top'>
<fieldset class='uk-margin-top' x-data='{ phaseOutMode: "<% root.phaseOutMode %>" }'>
<legend><% gettext 'Site Phase-Out' %></legend>
<div class='uk-form-row'>
<label class='uk-form-label' for='phaseOutMode'>
<% gettext Mode %>
</label>
<div class='uk-form-controls'>
<% root.select phaseOutMode %>
<% root.select phaseOutMode x-model='phaseOutMode' %>
</div>
</div>
<div class='uk-form-row'>
@ -120,7 +120,7 @@
<% gettext 'Notification Period' %>
</label>
<div class='uk-form-controls'>
<% root.input phaseOutNotificationPeriod class=uk-width-1-6 type=number min=1 %> <% gettext days %>
<% root.input phaseOutNotificationPeriod class=uk-width-1-6 type=number min=1 :disabled="phaseOutMode === 'disabled'" %> <% gettext days %>
</div>
</div>
<div class='uk-form-row'>
@ -128,7 +128,7 @@
<% gettext 'Grace Period' %>
</label>
<div class='uk-form-controls'>
<% root.input phaseOutGracePeriod class=uk-width-1-6 type=number min=1 %> <% gettext days %>
<% root.input phaseOutGracePeriod class=uk-width-1-6 type=number min=1 :disabled="phaseOutMode === 'disabled'" %> <% gettext days %>
</div>
</div>
</fieldset>
@ -140,21 +140,6 @@
</div>
</form>
<script>
creationScope.addEventListener('change', event => {
const disabled = event.currentTarget.value !== 'regular';
probationPeriod.disabled = creationDelay.disabled = disabled;
});
phaseOutMode.addEventListener('change', event => {
const disabled = event.currentTarget.value === "disabled";
phaseOutNotificationPeriod.disabled = phaseOutGracePeriod.disabled = disabled;
})
Antville.trigger(creationScope, 'change');
Antville.trigger(phaseOutMode, 'change');
</script>
<% #activities %>
<h1><% response.title %></h1>
<form class='uk-form uk-form-stacked' method="post" action="<% response.action %>">

View file

@ -15,35 +15,11 @@
</tr>
<% #delete %>
<div class='uk-alert uk-alert-warning uk-hidden av-alert-confirm'>
<input type="checkbox" id="mode" name="mode" value="user" />
<label for="mode"><% gettext "Erase all comments of user {0}" <% comment.creator %> %></label>
<div id="confirmation">
<input type="checkbox" id="confirm" name="confirm" value="1" />
<label for="confirm"><% ngettext "Yes, really erase {0} comment" "Yes, really erase {0} comments" <% comment.related.size %> %></label>
</div>
<div class='uk-alert uk-alert-warning av-alert-confirm' x-data='{ confirm: false, confirmed: false }' hidden :hidden='false'>
<input type="checkbox" id="mode" name="mode" value="user" @click='confirm = document.querySelector("button").disabled = !confirm'/>
<label for="mode"><% gettext "Erase all comments of user {0}" <% comment.creator %> %></label>
<div id="confirmation" x-show='confirm'>
<input type="checkbox" id="confirm" name="confirm" value="1" x-model='confirmed' @click='confirmed = !confirmed; document.querySelector("button").disabled = !confirmed'/>
<label for="confirm"><% ngettext "Yes, really erase {0} comment" "Yes, really erase {0} comments" <% comment.related.size %> %></label>
</div>
</div>
<script>
confirmation.hidden = true;
mode.addEventListener('click', event => {
const button = document.querySelector('button');
const input = document.querySelector('#confirm');
if (event.currentTarget.checked) {
input.checked = false;
confirmation.hidden = false;
button.disabled = true;
} else {
confirmation.hidden = true;
button.disabled = false;
}
input.addEventListener('click', event => {
document.querySelector('button').disabled = !event.currentTarget.checked;
});
});
document.querySelector('.av-alert-confirm').classList.remove('uk-hidden');
</script>

View file

@ -24,7 +24,7 @@
</h1>
<div class='uk-article-meta'><% file.skin $HopObject#meta %></div>
<% site.skin $Site#noscript %>
<form class='uk-margin-top uk-form uk-form-stacked' method="post" action="<% response.action %>" enctype="multipart/form-data">
<form class='uk-margin-top uk-form uk-form-stacked' method="post" action="<% response.action %>" enctype="multipart/form-data" x-data='{ name: "<% file.name %>" }'>
<div class='uk-form-row'>
<label class='uk-form-label' for='file'>
<% gettext File %>
@ -33,13 +33,13 @@
<% file.upload file class='uk-width-1-2' %>
</div>
</div>
<div class='uk-form-row uk-hidden av-name-row'>
<div class='uk-form-row av-name-row' hidden :hidden='false'>
<label class='uk-form-label' for='name'>
<% gettext Name %>
<i class='uk-icon-info-circle uk-text-muted' title='<% gettext "If you do not specify a name Antville will create one based on the filename." %>' data-uk-tooltip='{pos: "right"}'></i>
</label>
<div class='uk-form-controls'>
<% file.input name class='uk-width-1-2' %>
<% file.input name class='uk-width-1-2' :disabled='name' %>
</div>
</div>
<div class='uk-form-row'>
@ -64,8 +64,3 @@
<a href='<% site.files.href %>' class="uk-button uk-button-link"><% gettext Cancel %></a>
</div>
</form>
<script>
if ('<% file.name %>') document.querySelector('#name').disabled = true;
document.querySelector('.av-name-row').classList.remove('uk-hidden');
</script>

View file

@ -32,38 +32,16 @@
<input type="file" id="<% param.name %>" name="<% param.name %>">
</noscript>
<div class="av-upload uk-hidden">
<input type="file">
<div class="av-upload" hidden :hidden='false'>
<input type="file" x-ref='file' :name='"<% param.name %>"' @change='$refs.text.value = $event.currentTarget.value'>
<div class="uk-width-1-1 av-upload-controls">
<input class='uk-width-1-2' type="text" value="<% param.value %>">
<button class='uk-button' id="<% param.name %>_control" name="<% param.name %>_control" type="button">
<input class='uk-width-1-2' type="text" value="<% param.value %>" x-ref='text' :name='"<% param.name %>_origin"' @blur='$refs.file.value = ""'>
<button class='uk-button' id="<% param.name %>_control" name="<% param.name %>_control" type="button" @click='$refs.file.click()'>
<% gettext "Select" suffix=… %>
</button>
</div>
</div>
<script>
document.querySelector('noscript').remove();
document.querySelector('.av-upload').classList.remove('uk-hidden');
const textInput = document.querySelector('.av-upload input[type="text"]');
const fileInput = document.querySelector('.av-upload input[type="file"]');
textInput.id = textInput.name = '<% param.name %>_origin';
fileInput.id = fileInput.name = '<% param.name %>';
textInput.addEventListener('blur', () => {
fileInput.value = '';
});
fileInput.addEventListener('change', event => {
textInput.value = event.currentTarget.value;
});
document.querySelector('.av-upload button')
.addEventListener('click', () => fileInput.click());
</script>
<% #listItemFlag %>
<td rowspan="2" width="10" align="center" valign="top" nowrap="nowrap"
class="listItemFlag"><% param.text %></td>

View file

@ -41,7 +41,7 @@
<% image.link . ' ' class='uk-icon-button uk-icon-link uk-text-middle' %>
</h1>
<div class='uk-article-meta'><% image.skin $HopObject#meta %></div>
<form class='uk-margin-top uk-form uk-form-stacked' method="post" action="<% response.action %>" enctype="multipart/form-data">
<form class='uk-margin-top uk-form uk-form-stacked' method="post" action="<% response.action %>" enctype="multipart/form-data" x-data="{ name: '<% image.name %>', layout: location.href.indexOf('/layout/') > -1 }">
<div class='uk-form-row'>
<label class='uk-form-label' for='file'>
<% gettext File %>
@ -50,13 +50,13 @@
<% image.upload file %>
</div>
</div>
<div class='uk-form-row uk-hidden av-name-row'>
<div class='uk-form-row av-name-row' hidden :hidden='false'>
<label class='uk-form-label' for='name'>
<% gettext Name %>
<i class='uk-icon-info-circle uk-text-muted' title='<% gettext "If you do not specify a name Antville will create one based on the filename." %>' data-uk-tooltip='{pos: "right"}'></i>
</label>
<div class='uk-form-controls'>
<% image.input name class='uk-width-1-2' %>
<% image.input name class='uk-width-1-2' :disabled='name' %>
</div>
</div>
<div class='uk-form-row'>
@ -67,7 +67,7 @@
<% image.input description class='uk-width-1-1' %>
</div>
</div>
<div class='uk-form-row uk-hidden av-tags-row'>
<div class='uk-form-row av-tags-row' x-show='!layout'>
<label class='uk-form-label' for='tags'>
<% gettext Tags %>
<i class='uk-icon-info-circle uk-text-muted' title='<% gettext 'Separated by commas' %>' data-uk-tooltip='{pos: "right"}'></i>
@ -90,12 +90,3 @@
<a href='.' class="uk-button uk-button-link"><% gettext Cancel %></a>
</div>
</form>
<script>
if ('<% image.name %>') document.querySelector('#name').disabled = true;
document.querySelector('.av-name-row').classList.remove('uk-hidden');
if (location.href.indexOf('/layout/') < 0) {
document.querySelector('.av-tags-row').classList.remove('uk-hidden');
}
</script>

View file

@ -35,53 +35,54 @@
</div>
<script>
(function() {
const dropElement = document.querySelector('.av-upload-drop');
const parent = location.href.lastIndexOf('/layout/images/') > -1 ? 'layout' : 'site';
const uploadUrl = '<% site.images.href upload %>?parent=' + parent;
// Setup drag&drop for image uploads
(function() {
const dropElement = document.querySelector('.av-upload-drop');
const parent = location.href.lastIndexOf('/layout/images/') > -1 ? 'layout' : 'site';
const uploadUrl = '<% site.images.href upload %>?parent=' + parent;
let dropTimer;
let dropHasHilite;
let dropTimer;
let dropHasHilite;
['dragstart', 'dragenter', 'dragover'].forEach(function(type) {
document.addEventListener(type, function() {
if (!dropHasHilite) {
dropElement.classList.remove('uk-hidden');
dropHasHilite = true;
}
['dragstart', 'dragenter', 'dragover'].forEach(function(type) {
document.addEventListener(type, function() {
if (!dropHasHilite) {
dropElement.classList.remove('uk-hidden');
dropHasHilite = true;
}
});
});
});
['dragleave', 'dragend'].forEach(function(type) {
dropHasHilite = false;
clearTimeout(dropTimer);
dropTimer = setTimeout(function() {
dropHasHilite || dropElement.classList.add('uk-hidden');
}, 100);
});
['dragleave', 'dragend'].forEach(function(type) {
dropHasHilite = false;
clearTimeout(dropTimer);
dropTimer = setTimeout(function() {
dropHasHilite || dropElement.classList.add('uk-hidden');
}, 100);
});
const restoreDrop = function() {
dropElement.classList.add('uk-hidden');
dropElement.querySelector('i').classList.remove('av-upload-glow');
};
const restoreDrop = function() {
dropElement.classList.add('uk-hidden');
dropElement.querySelector('i').classList.remove('av-upload-glow');
};
UIkit.uploadDrop(document, {
action: uploadUrl,
allow: '*.(jpg|jpeg|gif|png)',
UIkit.uploadDrop(document, {
action: uploadUrl,
allow: '*.(jpg|jpeg|gif|png)',
loadstart: function() {
dropElement.querySelector('i').classList.add('av-upload-glow');
},
loadstart: function() {
dropElement.querySelector('i').classList.add('av-upload-glow');
},
//progress: function(percent) {},
//progress: function(percent) {},
allcomplete: function(response) {
location.href = response;
},
allcomplete: function(response) {
location.href = response;
},
notallowed: restoreDrop,
error: restoreDrop,
abort: restoreDrop
});
})();
notallowed: restoreDrop,
error: restoreDrop,
abort: restoreDrop
});
})();
</script>

View file

@ -42,23 +42,24 @@
const valueRow = document.querySelector(".av-value-row:last-child");
const clone = valueRow.cloneNode(true);
clone.classList.remove("uk-hidden");
clone.querySelector(".av-value-title").innerHTML = name;
clone.querySelector(".av-clipboard-copy").remove();
const clipboard = clone.querySelector(".av-clipboard-copy");
if (clipboard) clipboard.remove();
const input = clone.querySelector(".uk-form-controls input");
input.setAttribute("id", key.replace(/\s/g, "-"));
input.setAttribute("name", key);
input.setAttribute("value", "");
input.setAttribute("type", this.getType(key));
input.id = key.replace(/\s/g, "-");
input.name = key;
input.value = "";
input.type = this.getType(key);
valueRow.insertAdjacentElement("afterend", clone);
clone.querySelector("input").focus();
},
removeSetting: function(event) {
event.currentTarget.remove();
event.currentTarget.closest(".av-value-row").remove();
},
getType: function(name) {
@ -90,11 +91,11 @@
</form>
<% #value %>
<div class='uk-width-1-2 uk-margin-bottom av-value-row <% param.class %>' @mouseover='showControls($event)' @mouseout='hideControls($event)' @click='removeSetting($event)'>
<div class='uk-width-1-2 uk-margin-bottom av-value-row <% param.class %>' @mouseover='showControls($event)' @mouseout='hideControls($event)'>
<div class='uk-form-label'>
<span class='av-value-title'><% param.title %></span>
<span class='av-value-controls' hidden>
<a href='javascript:' class='av-value-remove'><i class='uk-icon-trash-o'></i></a>
<a href='javascript:' class='av-value-remove' @click='removeSetting($event)'><i class='uk-icon-trash-o'></i></a>
<a href='javascript:' class='av-clipboard-copy' data-text='<% gettext 'Press CTRL & C to copy to clipboard.' %>' data-value="<% param.macro %>"><i class='uk-icon-clipboard'></i></a>
</span>
</div>

View file

@ -26,14 +26,29 @@
<% #login %>
<h1><% response.title %></h1>
<form class='uk-form uk-form-stacked' id="login" method="post" action="<% response.action %>">
<input type="hidden" name="digest" id="digest" />
<form class='uk-form uk-form-stacked' id="login" method="post" action="<% response.action %>" @submit='submit($refs)' x-data='{
submit: function($refs) {
const options = {
data: { user: $refs.username.value },
callback: function(salt, error) {
if (error) return;
$refs.digest.value = Antville.hash(Antville.hash($refs.password.value + salt) + "<% session.token %>");
$refs.password.value = "";
}
};
Antville.http("get", "<% members.href salt.txt %>", options);
}
}'>
<input type="hidden" name="digest" id="digest" x-ref='digest'/>
<div class='uk-form-row'>
<label class='uk-form-label' for='name'>
<% gettext Account %>
</label>
<div class='uk-form-controls'>
<input name="name" id="name" tabindex=1 value="<% request.name encoding="form" %>" class='uk-width-1-2' required>
<input name="name" id="name" tabindex=1 value="<% request.name encoding="form" %>" class='uk-width-1-2' required x-ref='username'>
<% members.link register <% gettext "Not registered yet\?" %> class='uk-button uk-button-link' tabindex=6 %>
</div>
</div>
@ -42,7 +57,7 @@
<% gettext Password %>
</label>
<div class='uk-form-controls uk-form-password uk-width-1-2'>
<input type="password" name="password" id="password" class='uk-width-1-1' tabindex=2 required>
<input type="password" name="password" id="password" class='uk-width-1-1' tabindex=2 required x-ref='password'>
<a href='javascript:' class='uk-form-password-toggle' data-uk-form-password="{
lblHide: '<% gettext Hide %>',
lblShow: '<% gettext Show %>'
@ -68,36 +83,10 @@
<% story <% root.termsStory %> link text=<% gettext "Terms and Conditions" %> prefix='<div class="uk-margin-top"><i class="uk-icon-legal"></i> ' suffix=</div> %>
<% story <% root.privacyStory %> link text=<% gettext "Data Privacy Statement" %> prefix='<div><i class="uk-icon-cloud-upload"></i> ' suffix=</div> %>
<script>
document.querySelector('#login').addEventListener('submit', function(event) {
event.preventDefault();
if (document.querySelector('#digest').value) return true;
const form = event.currentTarget;
const name = document.querySelector('#name').value;
const options = {
data: {user: name},
callback: function(salt, error) {
if (error) return;
const password = document.querySelector('#password').value;
const token = '<% session.token %>';
document.querySelector('input[type=password]').value = '';
document.querySelector('#digest').value = window.md5(window.md5(password + salt) + token);
form.submit();
}
};
Antville.http('get', '<% members.href salt.txt %>', options);
});
</script>
<% #register %>
<h1><% response.title %></h1>
<form class='uk-form uk-form-stacked' id="register" method="post" action="<% response.action %>">
<input type="hidden" name="hash" id="hash" />
<form class='uk-form uk-form-stacked' method="post" action="<% response.action %>" x-data='{ hash: "" }' @submit='$refs.hash.value = Antville.hash($refs.password.value, "<% session.token %>"); $refs.password.value = "";'>
<input type="hidden" name="hash" id="hash" x-ref='hash' />
<div class='uk-form-row'>
<label class='uk-form-label' for='name'>
<% gettext Account %>
@ -119,7 +108,7 @@
<% gettext Password %>
</label>
<div class='uk-form-controls uk-form-password uk-width-1-2'>
<input type="password" name="password" id="password" class='uk-width-1-1' required tabindex=3>
<input type="password" name="password" id="password" class='uk-width-1-1' required tabindex=3 x-ref='password'>
<a href='javascript:' class='uk-form-password-toggle' data-uk-form-password="{
lblHide: '<% gettext Hide %>',
lblShow: '<% gettext Show %>'
@ -137,17 +126,6 @@
</div>
</form>
<script>
document.querySelector('#register').addEventListener('submit', function() {
debugger;
const token = '<% session.token %>';
const password = document.querySelector('#password');
const hash = window.md5(password.value + token);
password.value = '';
document.querySelector('#hash').value = hash;
});
</script>
<% #terms %>
<div class='uk-form-row'>
<label>

View file

@ -84,7 +84,7 @@
<% poll.link . ' ' class='uk-icon-button uk-icon-link uk-text-middle' %>
</h1>
<div class='uk-article-meta'><% poll.skin $HopObject#meta %></div>
<form class='uk-margin-top uk-form uk-form-stacked' method="post" action="<% response.action %>">
<form class='uk-margin-top uk-form uk-form-stacked' method="post" action="<% response.action %>" x-data='{ counter: 2 }'>
<div class='uk-form-row'>
<div class='uk-form-label'><% gettext Question %></div>
<div class='uk-form-controls'>
@ -94,8 +94,8 @@
<fieldset class='uk-margin-top'>
<legend><% gettext Choices %></legend>
<% poll.input choices %>
<div class='uk-text-small uk-form-row uk-hidden' id='av-add-choice'>
<a href='javascript:'>
<div class='uk-text-small uk-form-row' id='av-add-choice' hidden :hidden='false'>
<a href='javascript:' @click='const choice = document.querySelectorAll(".av-choice")[counter - 1]; const clone = choice.cloneNode(true); counter += 1; clone.querySelector(".uk-form-label").innerText = "#" + counter; const input = clone.querySelector("input"); input.value = ""; choice.insertAdjacentElement("afterEnd", clone); input.focus();'>
<i class='uk-icon-plus'></i>
<% gettext "Add Choice" %>
</a>
@ -120,27 +120,3 @@
<a href='.' class='uk-button uk-button-link'><% gettext Cancel %></a>
</div>
</form>
<script>
const addButton = document.querySelector('#av-add-choice');
addButton.classList.remove('uk-hidden');
addButton.querySelector('a').addEventListener('click', event => {
event.preventDefault();
const choices = document.querySelectorAll('.av-choice');
const choice = choices[choices.length - 1];
const clone = choice.cloneNode(true);
const input = clone.querySelector('input');
let index = choices.length + 1;
clone.querySelector('.uk-form-label').innerText = '#' + index;
choice.insertAdjacentElement('afterEnd', clone);
input.value = '';
input.focus();
index += 1;
});
</script>

View file

@ -5,8 +5,8 @@
<label class='uk-form-label' for='name'>
<% gettext Name %> <i class='uk-icon uk-icon-info-circle uk-text-muted' data-uk-tooltip title="<% gettext "Please note that you cannot change the name after the site was created." %>"></i>
</label>
<div class='uk-form-controls'>
<% newSite.input name class=uk-form-width-medium maxlength=25 tabindex=1 %>
<div class='uk-form-controls' x-data="{ name: '' }">
<% newSite.input name class=uk-form-width-medium maxlength=25 tabindex=1 x-model="name" %>
<div class='uk-form-help-inline'>
<% gettext 'The name will be part of the URL of your site.' %>
</div>

View file

@ -2,18 +2,7 @@
<% gettext 'System is up and running.' %>
<% #urlPreview %>
<a id='av-site-url-preview'></a>
<script>
document.querySelector('#name').addEventListener('keyup', event => {
const name = event.target.value;
const preview = document.querySelector('#av-site-url-preview');
if (name) {;
preview.innerHTML = `<% root.href %><strong>${name}</strong>`;
preview.setAttribute('href', '<% root.href %>' + name);
} else {
preview.innerHTML = '<% root.href %>';
}
});
</script>
<% // This snippet contains additional markup to be rendered client-side by Alpine %>
<a :href='"<% root.href %>" + name'>
<strong x-show='name' x-text='"<% root.href %>" + name'></strong>
</a>

View file

@ -171,10 +171,10 @@
<% gettext 'Callback URL' %>
</label>
<div class='uk-form-controls'>
<% site.input callbackUrl type=url class='uk-width-1-1' %>
<div class='uk-form-controls' x-data='{ callbackMode: false }'>
<% site.input callbackUrl type=url class='uk-width-1-1' :disabled='!callbackMode' %>
<label>
<% site.checkbox callbackMode %>
<% site.checkbox callbackMode x-model='callbackMode' %>
<% gettext enabled %>
</label>
</div>
@ -186,7 +186,7 @@
</label>
<div class='uk-form-controls'>
<a class='uk-button' data-uk-tooltip='{pos: "right"}' href="javascript: void (() => {const F = {'🍪': '', '🐜': '<% root.static %>../../formica.html', '🎯': '<% site.href %>', '🌐': '<% root.href %>', '📝': window.getSelection ? window.getSelection() : document.selection.createRange()}; F['📝'] = '' + (F['📝'].text || F['📝']); F['🐜'] += '?s=' + encodeURIComponent(F['🎯']) + '&amp;l=' + encodeURIComponent(location.href) + '&amp;r=' + encodeURIComponent(document.referrer) + '&amp;k=' + encodeURIComponent(F['🍪']) + '&c=' + encodeURIComponent(F['📝']) + '&b=' + encodeURIComponent(F['🌐']); window.open(F['🐜'], '🐜', 'width=650, height=350');})()" title="<% gettext 'Drag to Bookmarks Bar' %>"><% gettext "Post to {0}" <% site.title %> %></a>
<a class='uk-button' data-uk-tooltip='{ pos: "right" }' href="javascript: void (() => { const F = { '🍪': '', '🐜': '<% root.static %>../../formica.html', '🎯': '<% site.href %>', '🌐': '<% root.href %>', '📝': window.getSelection ? window.getSelection() : document.selection.createRange() }; F['📝'] = '' + (F['📝'].text || F['📝']); F['🐜'] += '?s=' + encodeURIComponent(F['🎯']) + '&amp;l=' + encodeURIComponent(location.href) + '&amp;r=' + encodeURIComponent(document.referrer) + '&amp;k=' + encodeURIComponent(F['🍪']) + '&c=' + encodeURIComponent(F['📝']) + '&b=' + encodeURIComponent(F['🌐']); window.open(F['🐜'], '🐜', 'width=650, height=350'); })()" title="<% gettext 'Drag to Bookmarks Bar' %>"><% gettext "Post to {0}" <% site.title %> %></a>
</div>
</div>

View file

@ -6,13 +6,13 @@
</td>
<td class='uk-text-right uk-text-nowrap'>
<% tag.link rss.xml "<i class='uk-icon-rss'></i>" %>
<% tag.link delete "<i class='uk-icon-trash-o'></i>" class='av-delete-tag uk-hidden' data-av-tag-url=<% tag.href delete %> %>
<% tag.link rename "<i class='uk-icon-pencil'></i>" class='av-rename-tag uk-hidden' data-av-tag-url=<% tag.href rename %> %>
<% tag.link delete "<i class='uk-icon-trash-o'></i>" @click.prevent=<% tag.name prefix='remove(\'' suffix='\', $event)' %> hidden=hidden :hidden='false' %>
<% tag.link rename "<i class='uk-icon-pencil'></i>" @click.prevent=<% tag.name prefix='rename(\'' suffix='\', $event)' %> hidden=hidden :hidden='false' %>
</td>
</tr>
<% #main %>
<div class='av-tag'>
<div class='av-tag' :class='"<% tag.type parent %>" === "Image" ? "av-collage" : ""' x-data='{}'>
<% list.render skin="$TagHub#main" %>
</div>
@ -22,16 +22,13 @@
</ul>
<script>
// Load additional script for Collage jQuery plugin
if ('<% tag.type parent %>' === 'Image') {
const script = document.createElement('script');
// Load an extra script for the gallery
script.src = '<% root.static ../../scripts/gallery.min.js %>';
script.onload = function() {
// Collage is a jQuery plugin
$(function() {
const resizeTimer = null;
let resizeTimer = null;
const collage = () => {
$('.av-collage').removeWhitespace().collagePlus({
@ -52,8 +49,8 @@
});
};
script.src = '<% root.static ../../scripts/gallery.min.js %>';
document.head.appendChild(script);
document.querySelector('.av-tag').classList.add('av-collage');
}
</script>

View file

@ -5,49 +5,32 @@
<% response.pager %>
<table class='uk-table uk-table-striped uk-table-hover uk-table-condensed'>
<thead>
<tr>
<th class='uk-text-right'>
<% if <% tags.self __name__ %> is tags then
"<i class='uk-icon-newspaper-o'></i>"
<thead>
<tr>
<th class='uk-text-right'>
<% if <% tags.self __name__ %> is tags then
"<i class='uk-icon-newspaper-o'></i>"
else
"<i class='uk-icon-image'></i>"
%>
</th>
<th class='uk-width-5-6'><% gettext Name %></th>
<th></th>
</tr>
</thead>
<tbody>
<% response.list %>
</tbody>
"<i class='uk-icon-image'></i>"
%>
</th>
<th class='uk-width-5-6'><% gettext Name %></th>
<th></th>
</tr>
</thead>
<tbody x-data='{
rename: function(tag, event) {
const name = prompt("<% gettext 'Please enter a new name for this tag' suffix=: %>", tag);
if (name) location.href = event.currentTarget.href + "?name=" + name;
},
remove: function(url) {
if (!confirm("<% gettext 'Are you sure you want to remove this tag?' %>")) return;
location.href= url;
}
}'>
<% response.list %>
</tbody>
</table>
<% response.pager %>
<script>
document.querySelectorAll('.av-rename-tag').forEach(renameButton => {
renameButton.classList.remove('uk-hidden');
renameButton.addEventListener('click', event => {
event.preventDefault();
const url = event.currentTarget.dataset.avTagUrl;
const name = prompt("<% gettext 'Please enter a new name for this tag' suffix=: %>")
if (name) location.href = url + '?name=' + name;
});
});
document.querySelectorAll('.av-delete-tag').forEach(deleteButton => {
deleteButton.classList.remove('uk-hidden');
deleteButton.addEventListener('click', event => {
event.preventDefault();
if (confirm("<% gettext 'Are you sure you want to remove this tag?' %>")) {
location.href = event.currentTarget.dataset.avTagUrl;
}
});
});
</script>

View file

@ -51,9 +51,9 @@
<% context.link timeline <% gettext Timeline %> %>
<% context.link export <% gettext Export %> prefix='| ' %>
</div>
<form id='edit' class='uk-form uk-form-stacked uk-margin-top' method="post">
<form id='edit' class='uk-form uk-form-stacked uk-margin-top' method="post" x-data='{ token: "<% session.token %>", salt: "<% session.salt %>" }' @submit='if ($refs.password.value) { $refs.hash.value = Antville.hash($refs.password.value + token); $refs.password.value = ""; }'>
<input type="hidden" name="digest" id="digest">
<input type="hidden" name="hash" id="hash">
<input type="hidden" name="hash" id="hash" x-ref='hash'>
<figure class='uk-float-right' style='height: 0'>
<a href='https://gravatar.com'>
<img alt='' src='<% user.gravatar suffix="?s=160&amp;d=mm" %> 'style='border: 1px solid #ddd; border-radius: 4px;'>
@ -83,11 +83,11 @@
</div>
</div>
<div class='uk-form-row'>
<label class='uk-form-label' for='password'>
<label class='uk-form-label' for='password''>
<% gettext "Password" %>
</label>
<div class='uk-form-controls uk-form-password uk-width-2-3'>
<input type="password" name="password" id="password" class='uk-width-1-1'>
<input type="password" name="password" id="password" class='uk-width-1-1' x-ref='password'>
<a href='javascript:' class='uk-form-password-toggle' data-uk-form-password="{
lblHide: '<% gettext Hide %>',
lblShow: '<% gettext Show %>'
@ -105,21 +105,6 @@
</div>
</form>
<script>
document.querySelector('#submit').addEventListener('click', function(event) {
const password = document.querySelector('#password');
if (!password.value) return;
const token = '<% session.token %>';
const salt = '<% session.salt %>';
const hash = window.md5(password.value + token);
document.querySelector('#hash').value = hash;
password.value = '';
});
</script>
<% #admin %>
<fieldset class='uk-margin-top uk-margin-bottom'>
<legend><% gettext Administration %></legend>

View file

@ -1,5 +1,6 @@
<% #googleSearch %>
<h1><% response.title %></h1>
<form class='uk-form' method='get' action='<% site.href search %>'>
<div class='uk-form-controls'>
<input type='text' class='uk-width-1-2' name='q' value='<% request.q encoding="form" %>' required>
@ -9,7 +10,11 @@
<a href='<% site.href %>' class='uk-button uk-button-link'><% gettext Cancel %></a>
</div>
</form>
<gcse:searchresults-only></gcse:searchresults-only>
<script>
// Load additional script for Googles custom search
(function() {
var cx = '008141500676255803966:bw4l-wnuz44';
var gcse = document.createElement('script');
@ -21,4 +26,3 @@
s.parentNode.insertBefore(gcse, s);
})();
</script>
<gcse:searchresults-only></gcse:searchresults-only>

View file

@ -1,14 +1,16 @@
window.Antville = {};
window.md5 = require('js-md5/src/md5');
window.$ = window.jQuery = require('jquery');
require('alpinejs');
require('uikit/dist/js/uikit');
require('uikit/dist/js/components/form-password');
require('uikit/dist/js/components/tooltip');
require('uikit/dist/js/components/upload');
require('alpinejs');
const Antville = window.Antville = {};
Antville.hash = require('js-md5/src/md5');
const init = function() {
// Highlight the current navigation menu item
const navItem = document.querySelector('.uk-nav a[href="' + location + '"]');