client/general: add empty href for link buttons

In e464e69 I removed href='#' but I noticed that it broke some things.
Readding href serves two purposes:

- it makes links reachable with Tab key
- it makes links clickable with Enter key

The alternative to this approach was to introduce [tabindex] and [role]
attributes. But not only using tabindex=0 with <a/> is questionable,
it'd require adding a keyboard handler that'd intercept space and return
key presses and simulated link clicks. Since it's best to leave this
kind of thing to the native UI, I went with readding hrefs instead. I
believe that hash hrefs, even though being a common practice, are silly,
so I decided to settle down with empty hrefs.

As a bonus, I added a snippet that prevents middle mouse clicks from
opening such links/buttons in new tabs, which was the motivation for
e464e69.
This commit is contained in:
rr- 2016-08-22 01:25:10 +02:00
parent 44b2d9b830
commit d5e197e6ea
18 changed files with 47 additions and 28 deletions

View file

@ -32,13 +32,13 @@
--><span class='score-container'></span><!--
--><% if (ctx.canEditComment) { %><!--
--><a class='edit'><!--
--><a href class='edit'><!--
--><i class='fa fa-pencil'></i> edit<!--
--></a><!--
--><% } %><!--
--><% if (ctx.canDeleteComment) { %><!--
--><a class='delete'><!--
--><a href class='delete'><!--
--><i class='fa fa-remove'></i> delete<!--
--></a><!--
--><% } %><!--

View file

@ -16,8 +16,8 @@
<nav class='buttons'>
<ul>
<li class='preview'><a>Preview</a></li>
<li class='edit'><a>Edit</a></li>
<li class='preview'><a href>Preview</a></li>
<li class='edit'><a href>Edit</a></li>
</ul>
</nav>

View file

@ -1,6 +1,6 @@
<section class='expander'>
<header>
<a>
<a href>
<%- ctx.title %>
<i class='fa fa-chevron-down'></i>
</a>

View file

@ -1,9 +1,9 @@
<% if (ctx.canFavorite) { %>
<% if (ctx.ownFavorite) { %>
<a class='remove-favorite'>
<a href class='remove-favorite'>
<i class='fa fa-heart'></i>
<% } else { %>
<a class='add-favorite'>
<a href class='add-favorite'>
<i class='fa fa-heart-o'></i>
<% } %>
<% } else { %>

View file

@ -57,9 +57,9 @@
<% if (ctx.canEditPostNotes) { %>
<section class='notes'>
<a class='add'>Add a note</a>
<a href class='add'>Add a note</a>
<%= ctx.makeTextarea({disabled: true, text: 'Content (supports Markdown)', rows: '8'}) %>
<a class='delete inactive'>Delete selected note</a>
<a href class='delete inactive'>Delete selected note</a>
</section>
<% } %>
@ -74,7 +74,7 @@
<section class='post-thumbnail'>
<label>Thumbnail</label>
<div class='dropper-container'></div>
<a>Discard custom thumbnail</a>
<a href>Discard custom thumbnail</a>
</section>
<% } %>
@ -82,10 +82,10 @@
<section class='management'>
<ul>
<% if (ctx.canFeaturePosts) { %>
<li><a class='feature'>Feature this post on main page</a></li>
<li><a href class='feature'>Feature this post on main page</a></li>
<% } %>
<% if (ctx.canDeletePosts) { %>
<li><a class='delete'>Delete this post</a></li>
<li><a href class='delete'>Delete this post</a></li>
<% } %>
</ul>
</section>

View file

@ -26,10 +26,10 @@
</section>
<section class='zoom'>
<a class='fit-original'>Original zoom</a> &middot;
<a class='fit-width'>fit width</a> &middot;
<a class='fit-height'>height</a> &middot;
<a class='fit-both'>both</a>
<a href class='fit-original'>Original zoom</a> &middot;
<a href class='fit-width'>fit width</a> &middot;
<a href class='fit-height'>height</a> &middot;
<a href class='fit-both'>both</a>
</section>
<section class='search'>

View file

@ -1,5 +1,5 @@
<li class='uploadable'>
<a class='remove'>
<a href class='remove'>
<i class='fa fa-remove'></i>
</a>

View file

@ -12,11 +12,11 @@
<% if (ctx.parameters.tag) { %>
<span class='append'>Tagging with:</span>
<% } else { %>
<a class='mousetrap button append open-masstag'>Mass tag</a>
<a href class='mousetrap button append open-masstag'>Mass tag</a>
<% } %>
<%= ctx.makeTextInput({name: 'masstag', value: ctx.parameters.tag}) %>
<input class='mousetrap start-tagging' type='submit' value='Start tagging'/>
<a class='mousetrap button append stop-tagging'>Stop tagging</a>
<a href class='mousetrap button append stop-tagging'>Stop tagging</a>
</form>
<% } %>
</div>

View file

@ -36,7 +36,7 @@
<% } %>
</a>
<% if (ctx.parameters && ctx.parameters.tag) { %>
<a data-post-id='<%= post.id %>' class='masstag'>
<a href data-post-id='<%= post.id %>' class='masstag'>
</a>
<% } %>
</li>

View file

@ -1,5 +1,5 @@
<% if (ctx.canScore) { %>
<a class='upvote'>
<a href class='upvote'>
<% if (ctx.ownScore == 1) { %>
<i class='fa fa-thumbs-up'></i>
<% } else { %>
@ -9,13 +9,13 @@
<span class='vim-nav-hint'>like</span>
</a>
<% } else { %>
<a class='upvote inactive'>
<a href class='upvote inactive'>
<i class='fa fa-thumbs-o-up'></i>
</a>
<% } %>
<span class='value'><%- ctx.score %></span>
<% if (ctx.canScore) { %>
<a class='downvote'>
<a href class='downvote'>
<% if (ctx.ownScore == -1) { %>
<i class='fa fa-thumbs-down'></i>
<% } else { %>

View file

@ -14,7 +14,7 @@
</table>
<% if (ctx.canCreate) { %>
<p><a class='add'>Add new category</a></p>
<p><a href class='add'>Add new category</a></p>
<% } %>
<div class='messages'></div>

View file

@ -31,13 +31,13 @@
<% if (ctx.tagCategory.tagCount) { %>
<a class='inactive' title="Can't delete category in use">Remove</a>
<% } else { %>
<a>Remove</a>
<a href>Remove</a>
<% } %>
</td>
<% } %>
<% if (ctx.canSetDefault) { %>
<td class='set-default'>
<a>Make default</a>
<a href>Make default</a>
</td>
<% } %>
</tr>

View file

@ -8,8 +8,8 @@
<div class='wrapper'>
<p>
<span class='buttons'>
<a class='opacity'><i class='fa fa-eye'></i></a>
<a class='close'>×</a>
<a href class='opacity'><i class='fa fa-eye'></i></a>
<a href class='close'>×</a>
</span>
Suggested tags
</p>

View file

@ -215,6 +215,7 @@ class AutoCompleteControl {
const listItem = document.createElement('li');
const link = document.createElement('a');
link.innerHTML = resultItem.caption;
link.setAtribute('href', '');
link.setAttribute('data-key', resultItem.value);
link.addEventListener(
'mouseenter',

View file

@ -146,12 +146,14 @@ class PostEditSidebarControl extends events.EventTarget {
}
_evtRemoveThumbnailClick(e) {
e.preventDefault();
this._thumbnailFileDropper.reset();
this._newPostThumbnail = null;
this._thumbnailRemovalLinkNode.style.display = 'none';
}
_evtFeatureClick(e) {
e.preventDefault();
if (confirm('Are you sure you want to feature this post?')) {
this.dispatchEvent(new CustomEvent('feature', {
detail: {
@ -162,6 +164,7 @@ class PostEditSidebarControl extends events.EventTarget {
}
_evtDeleteClick(e) {
e.preventDefault();
if (confirm('Are you sure you want to delete this post?')) {
this.dispatchEvent(new CustomEvent('delete', {
detail: {
@ -195,6 +198,7 @@ class PostEditSidebarControl extends events.EventTarget {
}
_evtAddNoteClick(e) {
e.preventDefault();
if (e.target.classList.contains('inactive')) {
return;
}
@ -203,6 +207,7 @@ class PostEditSidebarControl extends events.EventTarget {
}
_evtDeleteNoteClick(e) {
e.preventDefault();
if (e.target.classList.contains('inactive')) {
return;
}

View file

@ -251,6 +251,7 @@ class TagInputControl extends events.EventTarget {
}
_evtAddTagButtonClick(e) {
e.preventDefault();
this.addTag(this._tagInputNode.value, SOURCE_USER_INPUT);
this._tagInputNode.value = '';
}
@ -324,6 +325,7 @@ class TagInputControl extends events.EventTarget {
const removalLinkNode = document.createElement('a');
removalLinkNode.classList.add('append');
removalLinkNode.setAttribute('href', '')
removalLinkNode.setAttribute('data-pseudo-content', '×');
removalLinkNode.addEventListener('click', e => {
e.preventDefault();
@ -387,6 +389,7 @@ class TagInputControl extends events.EventTarget {
const addLinkNode = document.createElement('a');
addLinkNode.textContent = tagName;
addLinkNode.classList.add('add-tag');
addLinkNode.setAttribute('href', '');
if (actualTag) {
addLinkNode.classList.add(
misc.makeCssName(actualTag.category, 'tag'));
@ -405,6 +408,7 @@ class TagInputControl extends events.EventTarget {
const removeLinkNode = document.createElement('a');
removeLinkNode.classList.add('remove-tag');
removeLinkNode.classList.add('append');
removeLinkNode.setAttribute('href', '');
removeLinkNode.setAttribute('data-pseudo-content', '×');
removeLinkNode.addEventListener('click', e => {
e.preventDefault();

View file

@ -476,6 +476,14 @@ document.addEventListener('input', e => {
}
});
// prevent opening buttons in new tabs
document.addEventListener('click', e => {
if (e.target.getAttribute('href') === '' && e.which === 2) {
console.log('prevented');
e.preventDefault();
}
});
module.exports = misc.arrayToObject([
htmlToDom,
getTemplate,

View file

@ -206,6 +206,7 @@ class PostUploadView extends events.EventTarget {
}
_evtRemoveClick(e, uploadable) {
e.preventDefault();
this.removeUploadable(uploadable);
}