Skip to content

Commit

Permalink
* Add search input to fixed header.
Browse files Browse the repository at this point in the history
* Load json from src/metadata.json.
* Add keyboard shortcuts.
  • Loading branch information
pcj committed Apr 2, 2015
1 parent 5fd8c1a commit f0a23bb
Show file tree
Hide file tree
Showing 6 changed files with 304 additions and 6 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@
"docpad-plugin-partials": "x.x.x"
},
"devDependencies": {
"docpad-plugin-ghpages": "x.x.x"
"docpad-plugin-ghpages": "~2.4.4"
}
}
66 changes: 65 additions & 1 deletion server/files/javascript/docs.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ semantic.ready = function() {

// selector cache
var

$document = $(document),
$sortableTables = $('.sortable.table'),
$sticky = $('.ui.sticky'),

Expand All @@ -36,6 +36,7 @@ semantic.ready = function() {
$swap = $('.theme.menu .item'),
$menu = $('#toc'),
$hideMenu = $('#toc .hide.item'),
$search = $('#search'),
$sortTable = $('.sortable.table'),
$demo = $('.demo'),

Expand Down Expand Up @@ -1068,6 +1069,69 @@ semantic.ready = function() {
})
;

// Load search data the first time user focuses the search input.
$search.find('input').on('focus', function() {
// Unbind listener
$(this).off('focus');
$search.addClass('loading');
$.getJSON('/src/metadata.json').always(function() {
$search.removeClass('loading');
}).fail(function(err) {
console.log('Failed to load search metadata');
$search.remove();
}).done(function(data) {
$search.search({
source: data,
searchFields: [ 'title' ],
searchFullText: true,
onSelect: function(results, response) {
window.location = '/' + results.filename;
}
});
});
});

// setup keyboard shortcuts
var shortcuts = [
{ name: 'Search',
key: 's',
aka: 's',
d: 'Focus search bar',
fn: function() {
$('#search').find('input').focus();
}
},
{ name: 'Help',
key: 'shift+/',
aka: '?',
d: 'Show keyboard shortcuts',
fn: function() {
var $modal = $('#shortcuts');
if (!$modal.length) {
var s = '<div class="ui small modal" id="shortcuts">';
s += '<div class="header">Keyboard Shortcuts</div>';
s += '<div class="content">';
s += '<table class="ui small collapsing striped basic table">';
for (var i = 0; i < shortcuts.length; i++) {
var d = shortcuts[i];
s += '<tr><td><b>' + d.aka + '</b></td><td>' + d.d + '</td></tr>';
}
s += '</table>';
s += '<div class="actions"><div class="ui small teal button">OK</div></div>';
s += '</div></div>';

$('body').append(s);
$modal = $('#shortcuts');
}
$('#shortcuts').modal('show');
}
}
];

$.each(shortcuts, function(i, d) {
$document.bind('keyup', d.key, d.fn);
});

handler.createIcon();
$example
.each(function() {
Expand Down
204 changes: 204 additions & 0 deletions server/files/javascript/library/jquery.hotkeys.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
/*jslint browser: true*/
/*jslint jquery: true*/

/*
* jQuery Hotkeys Plugin
* Copyright 2010, John Resig
* Dual licensed under the MIT or GPL Version 2 licenses.
*
* Based upon the plugin by Tzury Bar Yochay:
* https://github.com/tzuryby/jquery.hotkeys
*
* Original idea by:
* Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/
*/

/*
* One small change is: now keys are passed by object { keys: '...' }
* Might be useful, when you want to pass some other data to your handler
*/

(function(jQuery) {

jQuery.hotkeys = {
version: "0.8",

specialKeys: {
8: "backspace",
9: "tab",
10: "return",
13: "return",
16: "shift",
17: "ctrl",
18: "alt",
19: "pause",
20: "capslock",
27: "esc",
32: "space",
33: "pageup",
34: "pagedown",
35: "end",
36: "home",
37: "left",
38: "up",
39: "right",
40: "down",
45: "insert",
46: "del",
59: ";",
61: "=",
96: "0",
97: "1",
98: "2",
99: "3",
100: "4",
101: "5",
102: "6",
103: "7",
104: "8",
105: "9",
106: "*",
107: "+",
109: "-",
110: ".",
111: "/",
112: "f1",
113: "f2",
114: "f3",
115: "f4",
116: "f5",
117: "f6",
118: "f7",
119: "f8",
120: "f9",
121: "f10",
122: "f11",
123: "f12",
144: "numlock",
145: "scroll",
173: "-",
186: ";",
187: "=",
188: ",",
189: "-",
190: ".",
191: "/",
192: "`",
219: "[",
220: "\\",
221: "]",
222: "'"
},

shiftNums: {
"`": "~",
"1": "!",
"2": "@",
"3": "#",
"4": "$",
"5": "%",
"6": "^",
"7": "&",
"8": "*",
"9": "(",
"0": ")",
"-": "_",
"=": "+",
";": ": ",
"'": "\"",
",": "<",
".": ">",
"/": "?",
"\\": "|"
},

// excludes: button, checkbox, file, hidden, image, password, radio, reset, search, submit, url
textAcceptingInputTypes: [
"text", "password", "number", "email", "url", "range", "date", "month", "week", "time", "datetime",
"datetime-local", "search", "color", "tel"],

// default input types not to bind to unless bound directly
textInputTypes: /textarea|input|select/i,

options: {
filterInputAcceptingElements: true,
filterTextInputs: true,
filterContentEditable: true
}
};

function keyHandler(handleObj) {
if (typeof handleObj.data === "string") {
handleObj.data = {
keys: handleObj.data
};
}

// Only care when a possible input has been specified
if (!handleObj.data || !handleObj.data.keys || typeof handleObj.data.keys !== "string") {
return;
}

var origHandler = handleObj.handler,
keys = handleObj.data.keys.toLowerCase().split(" ");

handleObj.handler = function(event) {
// Don't fire in text-accepting inputs that we didn't directly bind to
if (this !== event.target &&
(jQuery.hotkeys.options.filterInputAcceptingElements &&
jQuery.hotkeys.textInputTypes.test(event.target.nodeName) ||
(jQuery.hotkeys.options.filterContentEditable && jQuery(event.target).attr('contenteditable')) ||
(jQuery.hotkeys.options.filterTextInputs &&
jQuery.inArray(event.target.type, jQuery.hotkeys.textAcceptingInputTypes) > -1))) {
return;
}

var special = event.type !== "keypress" && jQuery.hotkeys.specialKeys[event.which],
character = String.fromCharCode(event.which).toLowerCase(),
modif = "",
possible = {};

jQuery.each(["alt", "ctrl", "shift"], function(index, specialKey) {

if (event[specialKey + 'Key'] && special !== specialKey) {
modif += specialKey + '+';
}
});

// metaKey is triggered off ctrlKey erronously
if (event.metaKey && !event.ctrlKey && special !== "meta") {
modif += "meta+";
}

if (event.metaKey && special !== "meta" && modif.indexOf("alt+ctrl+shift+") > -1) {
modif = modif.replace("alt+ctrl+shift+", "hyper+");
}

if (special) {
possible[modif + special] = true;
}
else {
possible[modif + character] = true;
possible[modif + jQuery.hotkeys.shiftNums[character]] = true;

// "$" can be triggered as "Shift+4" or "Shift+$" or just "$"
if (modif === "shift+") {
possible[jQuery.hotkeys.shiftNums[character]] = true;
}
}

for (var i = 0, l = keys.length; i < l; i++) {
if (possible[keys[i]]) {
return origHandler.apply(this, arguments);
}
}
};
}

jQuery.each(["keydown", "keyup", "keypress"], function() {
jQuery.event.special[this] = {
add: keyHandler
};
});

})(jQuery || this.jQuery || window.jQuery);
25 changes: 24 additions & 1 deletion server/files/stylesheets/docs.css
Original file line number Diff line number Diff line change
Expand Up @@ -1379,6 +1379,29 @@ body.progress.animated .ui.progress .bar {
}


/*--------------
Search
---------------*/

#search input {
max-width: 800px;
color: white;
}

#search.ui.input input::-webkit-input-placeholder {
color: rgba(255, 255, 255, 0.75);
}

#search.ui.input input::-moz-placeholder {
color: rgba(255, 255, 255, 0.75);
}

#shortcuts.ui.modal .actions {
padding: 0;
border: none;
background: none;
}

/*******************************
Code Samples
*******************************/
Expand Down Expand Up @@ -1929,4 +1952,4 @@ body.progress.animated .ui.progress .bar {
#example > .pusher > .full.height {
flex: none;
}
}
}
12 changes: 9 additions & 3 deletions server/partials/fixed-menu.html.eco
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,14 @@
Menu
</a>
<% if @document.title: %>
<div class="title item">
<b><%= @document.type %>:</b> <%= @document.title %>
<div class="search item">
<div class="ui search input" id="search">
<div class="ui transparent icon input">
<input class="prompt" type="text" placeholder="<%= @document.type %>: <%= @document.title %>">
<i class="inverted search icon"></i>
</div>
<div class="results"></div>
</div>
</div>
<% if pageNumber > 1 and currentCollection[pageNumber - 2]?: %>
<a class="icon item" href="<%= currentCollection[pageNumber - 2].url %>"><i class="left chevron icon"></i></a>
Expand Down Expand Up @@ -60,4 +66,4 @@
</div>
</div>
</div>
</div>
</div>
1 change: 1 addition & 0 deletions server/partials/library-javascript.html.eco
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
</script>
<% end %>

<script src="/javascript/library/jquery.hotkeys.js"></script>
<script src="/javascript/library/easing.min.js"></script>
<script src="/javascript/library/highlight.min.js"></script>
<script src="/javascript/library/highlight.languages.min.js"></script>
Expand Down

0 comments on commit f0a23bb

Please sign in to comment.