client/general: add empty href for link buttons
Ine464e69
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 fore464e69
.
This commit is contained in:
parent
44b2d9b830
commit
d5e197e6ea
18 changed files with 47 additions and 28 deletions
|
@ -32,13 +32,13 @@
|
||||||
--><span class='score-container'></span><!--
|
--><span class='score-container'></span><!--
|
||||||
|
|
||||||
--><% if (ctx.canEditComment) { %><!--
|
--><% if (ctx.canEditComment) { %><!--
|
||||||
--><a class='edit'><!--
|
--><a href class='edit'><!--
|
||||||
--><i class='fa fa-pencil'></i> edit<!--
|
--><i class='fa fa-pencil'></i> edit<!--
|
||||||
--></a><!--
|
--></a><!--
|
||||||
--><% } %><!--
|
--><% } %><!--
|
||||||
|
|
||||||
--><% if (ctx.canDeleteComment) { %><!--
|
--><% if (ctx.canDeleteComment) { %><!--
|
||||||
--><a class='delete'><!--
|
--><a href class='delete'><!--
|
||||||
--><i class='fa fa-remove'></i> delete<!--
|
--><i class='fa fa-remove'></i> delete<!--
|
||||||
--></a><!--
|
--></a><!--
|
||||||
--><% } %><!--
|
--><% } %><!--
|
||||||
|
|
|
@ -16,8 +16,8 @@
|
||||||
|
|
||||||
<nav class='buttons'>
|
<nav class='buttons'>
|
||||||
<ul>
|
<ul>
|
||||||
<li class='preview'><a>Preview</a></li>
|
<li class='preview'><a href>Preview</a></li>
|
||||||
<li class='edit'><a>Edit</a></li>
|
<li class='edit'><a href>Edit</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<section class='expander'>
|
<section class='expander'>
|
||||||
<header>
|
<header>
|
||||||
<a>
|
<a href>
|
||||||
<%- ctx.title %>
|
<%- ctx.title %>
|
||||||
<i class='fa fa-chevron-down'></i>
|
<i class='fa fa-chevron-down'></i>
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<% if (ctx.canFavorite) { %>
|
<% if (ctx.canFavorite) { %>
|
||||||
<% if (ctx.ownFavorite) { %>
|
<% if (ctx.ownFavorite) { %>
|
||||||
<a class='remove-favorite'>
|
<a href class='remove-favorite'>
|
||||||
<i class='fa fa-heart'></i>
|
<i class='fa fa-heart'></i>
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
<a class='add-favorite'>
|
<a href class='add-favorite'>
|
||||||
<i class='fa fa-heart-o'></i>
|
<i class='fa fa-heart-o'></i>
|
||||||
<% } %>
|
<% } %>
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
|
|
|
@ -57,9 +57,9 @@
|
||||||
|
|
||||||
<% if (ctx.canEditPostNotes) { %>
|
<% if (ctx.canEditPostNotes) { %>
|
||||||
<section class='notes'>
|
<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'}) %>
|
<%= 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>
|
</section>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@
|
||||||
<section class='post-thumbnail'>
|
<section class='post-thumbnail'>
|
||||||
<label>Thumbnail</label>
|
<label>Thumbnail</label>
|
||||||
<div class='dropper-container'></div>
|
<div class='dropper-container'></div>
|
||||||
<a>Discard custom thumbnail</a>
|
<a href>Discard custom thumbnail</a>
|
||||||
</section>
|
</section>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
|
@ -82,10 +82,10 @@
|
||||||
<section class='management'>
|
<section class='management'>
|
||||||
<ul>
|
<ul>
|
||||||
<% if (ctx.canFeaturePosts) { %>
|
<% 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) { %>
|
<% if (ctx.canDeletePosts) { %>
|
||||||
<li><a class='delete'>Delete this post</a></li>
|
<li><a href class='delete'>Delete this post</a></li>
|
||||||
<% } %>
|
<% } %>
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -26,10 +26,10 @@
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class='zoom'>
|
<section class='zoom'>
|
||||||
<a class='fit-original'>Original zoom</a> ·
|
<a href class='fit-original'>Original zoom</a> ·
|
||||||
<a class='fit-width'>fit width</a> ·
|
<a href class='fit-width'>fit width</a> ·
|
||||||
<a class='fit-height'>height</a> ·
|
<a href class='fit-height'>height</a> ·
|
||||||
<a class='fit-both'>both</a>
|
<a href class='fit-both'>both</a>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class='search'>
|
<section class='search'>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<li class='uploadable'>
|
<li class='uploadable'>
|
||||||
<a class='remove'>
|
<a href class='remove'>
|
||||||
<i class='fa fa-remove'></i>
|
<i class='fa fa-remove'></i>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
|
|
@ -12,11 +12,11 @@
|
||||||
<% if (ctx.parameters.tag) { %>
|
<% if (ctx.parameters.tag) { %>
|
||||||
<span class='append'>Tagging with:</span>
|
<span class='append'>Tagging with:</span>
|
||||||
<% } else { %>
|
<% } 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}) %>
|
<%= ctx.makeTextInput({name: 'masstag', value: ctx.parameters.tag}) %>
|
||||||
<input class='mousetrap start-tagging' type='submit' value='Start tagging'/>
|
<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>
|
</form>
|
||||||
<% } %>
|
<% } %>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
<% } %>
|
<% } %>
|
||||||
</a>
|
</a>
|
||||||
<% if (ctx.parameters && ctx.parameters.tag) { %>
|
<% if (ctx.parameters && ctx.parameters.tag) { %>
|
||||||
<a data-post-id='<%= post.id %>' class='masstag'>
|
<a href data-post-id='<%= post.id %>' class='masstag'>
|
||||||
</a>
|
</a>
|
||||||
<% } %>
|
<% } %>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<% if (ctx.canScore) { %>
|
<% if (ctx.canScore) { %>
|
||||||
<a class='upvote'>
|
<a href class='upvote'>
|
||||||
<% if (ctx.ownScore == 1) { %>
|
<% if (ctx.ownScore == 1) { %>
|
||||||
<i class='fa fa-thumbs-up'></i>
|
<i class='fa fa-thumbs-up'></i>
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
|
@ -9,13 +9,13 @@
|
||||||
<span class='vim-nav-hint'>like</span>
|
<span class='vim-nav-hint'>like</span>
|
||||||
</a>
|
</a>
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
<a class='upvote inactive'>
|
<a href class='upvote inactive'>
|
||||||
<i class='fa fa-thumbs-o-up'></i>
|
<i class='fa fa-thumbs-o-up'></i>
|
||||||
</a>
|
</a>
|
||||||
<% } %>
|
<% } %>
|
||||||
<span class='value'><%- ctx.score %></span>
|
<span class='value'><%- ctx.score %></span>
|
||||||
<% if (ctx.canScore) { %>
|
<% if (ctx.canScore) { %>
|
||||||
<a class='downvote'>
|
<a href class='downvote'>
|
||||||
<% if (ctx.ownScore == -1) { %>
|
<% if (ctx.ownScore == -1) { %>
|
||||||
<i class='fa fa-thumbs-down'></i>
|
<i class='fa fa-thumbs-down'></i>
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<% if (ctx.canCreate) { %>
|
<% 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>
|
<div class='messages'></div>
|
||||||
|
|
|
@ -31,13 +31,13 @@
|
||||||
<% if (ctx.tagCategory.tagCount) { %>
|
<% if (ctx.tagCategory.tagCount) { %>
|
||||||
<a class='inactive' title="Can't delete category in use">Remove</a>
|
<a class='inactive' title="Can't delete category in use">Remove</a>
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
<a>Remove</a>
|
<a href>Remove</a>
|
||||||
<% } %>
|
<% } %>
|
||||||
</td>
|
</td>
|
||||||
<% } %>
|
<% } %>
|
||||||
<% if (ctx.canSetDefault) { %>
|
<% if (ctx.canSetDefault) { %>
|
||||||
<td class='set-default'>
|
<td class='set-default'>
|
||||||
<a>Make default</a>
|
<a href>Make default</a>
|
||||||
</td>
|
</td>
|
||||||
<% } %>
|
<% } %>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
<div class='wrapper'>
|
<div class='wrapper'>
|
||||||
<p>
|
<p>
|
||||||
<span class='buttons'>
|
<span class='buttons'>
|
||||||
<a class='opacity'><i class='fa fa-eye'></i></a>
|
<a href class='opacity'><i class='fa fa-eye'></i></a>
|
||||||
<a class='close'>×</a>
|
<a href class='close'>×</a>
|
||||||
</span>
|
</span>
|
||||||
Suggested tags
|
Suggested tags
|
||||||
</p>
|
</p>
|
||||||
|
|
|
@ -215,6 +215,7 @@ class AutoCompleteControl {
|
||||||
const listItem = document.createElement('li');
|
const listItem = document.createElement('li');
|
||||||
const link = document.createElement('a');
|
const link = document.createElement('a');
|
||||||
link.innerHTML = resultItem.caption;
|
link.innerHTML = resultItem.caption;
|
||||||
|
link.setAtribute('href', '');
|
||||||
link.setAttribute('data-key', resultItem.value);
|
link.setAttribute('data-key', resultItem.value);
|
||||||
link.addEventListener(
|
link.addEventListener(
|
||||||
'mouseenter',
|
'mouseenter',
|
||||||
|
|
|
@ -146,12 +146,14 @@ class PostEditSidebarControl extends events.EventTarget {
|
||||||
}
|
}
|
||||||
|
|
||||||
_evtRemoveThumbnailClick(e) {
|
_evtRemoveThumbnailClick(e) {
|
||||||
|
e.preventDefault();
|
||||||
this._thumbnailFileDropper.reset();
|
this._thumbnailFileDropper.reset();
|
||||||
this._newPostThumbnail = null;
|
this._newPostThumbnail = null;
|
||||||
this._thumbnailRemovalLinkNode.style.display = 'none';
|
this._thumbnailRemovalLinkNode.style.display = 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
_evtFeatureClick(e) {
|
_evtFeatureClick(e) {
|
||||||
|
e.preventDefault();
|
||||||
if (confirm('Are you sure you want to feature this post?')) {
|
if (confirm('Are you sure you want to feature this post?')) {
|
||||||
this.dispatchEvent(new CustomEvent('feature', {
|
this.dispatchEvent(new CustomEvent('feature', {
|
||||||
detail: {
|
detail: {
|
||||||
|
@ -162,6 +164,7 @@ class PostEditSidebarControl extends events.EventTarget {
|
||||||
}
|
}
|
||||||
|
|
||||||
_evtDeleteClick(e) {
|
_evtDeleteClick(e) {
|
||||||
|
e.preventDefault();
|
||||||
if (confirm('Are you sure you want to delete this post?')) {
|
if (confirm('Are you sure you want to delete this post?')) {
|
||||||
this.dispatchEvent(new CustomEvent('delete', {
|
this.dispatchEvent(new CustomEvent('delete', {
|
||||||
detail: {
|
detail: {
|
||||||
|
@ -195,6 +198,7 @@ class PostEditSidebarControl extends events.EventTarget {
|
||||||
}
|
}
|
||||||
|
|
||||||
_evtAddNoteClick(e) {
|
_evtAddNoteClick(e) {
|
||||||
|
e.preventDefault();
|
||||||
if (e.target.classList.contains('inactive')) {
|
if (e.target.classList.contains('inactive')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -203,6 +207,7 @@ class PostEditSidebarControl extends events.EventTarget {
|
||||||
}
|
}
|
||||||
|
|
||||||
_evtDeleteNoteClick(e) {
|
_evtDeleteNoteClick(e) {
|
||||||
|
e.preventDefault();
|
||||||
if (e.target.classList.contains('inactive')) {
|
if (e.target.classList.contains('inactive')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -251,6 +251,7 @@ class TagInputControl extends events.EventTarget {
|
||||||
}
|
}
|
||||||
|
|
||||||
_evtAddTagButtonClick(e) {
|
_evtAddTagButtonClick(e) {
|
||||||
|
e.preventDefault();
|
||||||
this.addTag(this._tagInputNode.value, SOURCE_USER_INPUT);
|
this.addTag(this._tagInputNode.value, SOURCE_USER_INPUT);
|
||||||
this._tagInputNode.value = '';
|
this._tagInputNode.value = '';
|
||||||
}
|
}
|
||||||
|
@ -324,6 +325,7 @@ class TagInputControl extends events.EventTarget {
|
||||||
|
|
||||||
const removalLinkNode = document.createElement('a');
|
const removalLinkNode = document.createElement('a');
|
||||||
removalLinkNode.classList.add('append');
|
removalLinkNode.classList.add('append');
|
||||||
|
removalLinkNode.setAttribute('href', '')
|
||||||
removalLinkNode.setAttribute('data-pseudo-content', '×');
|
removalLinkNode.setAttribute('data-pseudo-content', '×');
|
||||||
removalLinkNode.addEventListener('click', e => {
|
removalLinkNode.addEventListener('click', e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
@ -387,6 +389,7 @@ class TagInputControl extends events.EventTarget {
|
||||||
const addLinkNode = document.createElement('a');
|
const addLinkNode = document.createElement('a');
|
||||||
addLinkNode.textContent = tagName;
|
addLinkNode.textContent = tagName;
|
||||||
addLinkNode.classList.add('add-tag');
|
addLinkNode.classList.add('add-tag');
|
||||||
|
addLinkNode.setAttribute('href', '');
|
||||||
if (actualTag) {
|
if (actualTag) {
|
||||||
addLinkNode.classList.add(
|
addLinkNode.classList.add(
|
||||||
misc.makeCssName(actualTag.category, 'tag'));
|
misc.makeCssName(actualTag.category, 'tag'));
|
||||||
|
@ -405,6 +408,7 @@ class TagInputControl extends events.EventTarget {
|
||||||
const removeLinkNode = document.createElement('a');
|
const removeLinkNode = document.createElement('a');
|
||||||
removeLinkNode.classList.add('remove-tag');
|
removeLinkNode.classList.add('remove-tag');
|
||||||
removeLinkNode.classList.add('append');
|
removeLinkNode.classList.add('append');
|
||||||
|
removeLinkNode.setAttribute('href', '');
|
||||||
removeLinkNode.setAttribute('data-pseudo-content', '×');
|
removeLinkNode.setAttribute('data-pseudo-content', '×');
|
||||||
removeLinkNode.addEventListener('click', e => {
|
removeLinkNode.addEventListener('click', e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
|
@ -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([
|
module.exports = misc.arrayToObject([
|
||||||
htmlToDom,
|
htmlToDom,
|
||||||
getTemplate,
|
getTemplate,
|
||||||
|
|
|
@ -206,6 +206,7 @@ class PostUploadView extends events.EventTarget {
|
||||||
}
|
}
|
||||||
|
|
||||||
_evtRemoveClick(e, uploadable) {
|
_evtRemoveClick(e, uploadable) {
|
||||||
|
e.preventDefault();
|
||||||
this.removeUploadable(uploadable);
|
this.removeUploadable(uploadable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue