Merge pull request #40 from GitbookIO/feature/searchclient

Feature/searchclient
This commit is contained in:
Samy Pessé
2014-04-06 17:13:32 -07:00
15 changed files with 21633 additions and 35 deletions
+6 -2
View File
@@ -28,14 +28,15 @@ module.exports = function (grunt) {
baseUrl: "theme/javascript/",
out: "theme/assets/app.js",
preserveLicenseComments: false,
optimize: "uglify",
optimize: "none", //"uglify",
include: ["requireLib"],
paths: {
"jQuery": 'vendors/jquery',
"lodash": 'vendors/lodash',
"requireLib": 'vendors/require',
"Mousetrap": 'vendors/mousetrap',
"mixpanel": 'vendors/mixpanel'
"mixpanel": 'vendors/mixpanel',
"lunr": path.join(__dirname, "node_modules/lunr/lunr")
},
shim: {
'jQuery': {
@@ -49,6 +50,9 @@ module.exports = function (grunt) {
},
'mixpanel': {
exports: 'mixpanel'
},
'lunr': {
exports: 'lunr'
}
}
}
+3
View File
@@ -26,6 +26,7 @@ var Generator = function() {
// Attach methods to instance
_.bindAll(this);
this.revision = Date.now();
this.indexer = indexer();
// Load base template
@@ -41,6 +42,8 @@ Generator.prototype._writeTemplate = function(tpl, options, output) {
return Q()
.then(function(sections) {
return tpl(_.extend({
revision: that.revision,
title: that.options.title,
description: that.options.description,
+21415 -1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+6 -3
View File
@@ -8,10 +8,10 @@ require([
"core/keyboard",
"core/exercise",
"core/progress",
"core/sidebar"
], function($, storage, analytic, sharing, _state, keyboard, exercise, progress, sidebar){
"core/sidebar",
"core/search"
], function($, storage, analytic, sharing, state, keyboard, exercise, progress, sidebar, search){
$(document).ready(function() {
var state = _state();
var $book = state.$book;
// Initialize storage
@@ -20,6 +20,9 @@ require([
// Init sidebar
sidebar.init();
// Load search
search.init();
// Init keyboard
keyboard.init();
+1 -1
View File
@@ -38,7 +38,7 @@ define([
// Prepare all exercise
var init = function() {
state().$book.find("section.exercise").each(function() {
state.$book.find("section.exercise").each(function() {
prepareExercise($(this));
});
};
+11 -3
View File
@@ -2,8 +2,9 @@ define([
"jQuery",
"Mousetrap",
"core/navigation",
"core/sidebar"
], function($, Mousetrap, navigation, sidebar){
"core/sidebar",
"core/search"
], function($, Mousetrap, navigation, sidebar, search){
// Bind keyboard shortcuts
var init = function() {
// Next
@@ -23,9 +24,16 @@ define([
sidebar.toggle();
return false;
});
// Toggle Search
Mousetrap.bind(['f'], function(e) {
search.toggle();
return false;
});
};
return {
init: init
init: init,
search: search
};
});
+1 -1
View File
@@ -6,7 +6,7 @@ define([
], function(_, $, storage, state) {
// Get current level
var getCurrentLevel = function() {
return state().level;
return state.level;
};
// Return all levels
+106
View File
@@ -0,0 +1,106 @@
define([
"jQuery",
"lodash",
"lunr",
"utils/storage",
"core/state",
"core/sidebar"
], function($, _, lunr, storage, state, sidebar) {
var index = null;
var $searchBar = state.$book.find(".book-search");
var $searchInput = $searchBar.find("input");
// Use a specific idnex
var useIndex = function(data) {
index = lunr.Index.load(data);
};
// Load complete index
var loadIndex = function() {
var cacheKey = state.revision+":"+"searchIndex";
var cache = storage.get(cacheKey);
if (cache) return useIndex(cache);
$.getJSON(state.basePath+"/search_index.json")
.then(function(index) {
storage.set(cacheKey, index);
return index;
})
.then(useIndex);
};
// Search for a term
var search = function(q) {
if (!index) return;
var results = _.chain(index.search(q))
.map(function(result) {
var parts = result.ref.split("#")
return {
path: parts[0],
hash: parts[1]
}
})
.value();
return results;
};
// Toggle search bar
var toggleSearch = function(_state) {
if (state != null && isSearchOpen() == _state) return;
state.$book.toggleClass("with-search", _state);
// If search bar is open: focus input
if (isSearchOpen()) {
sidebar.toggle(true);
$searchInput.focus();
} else {
$searchInput.blur();
$searchInput.val("");
sidebar.filter(null);
}
};
// Return true if search bar is open
var isSearchOpen = function() {
return state.$book.hasClass("with-search");
};
var init = function() {
loadIndex();
// Toggle search
state.$book.find(".book-header .toggle-search").click(function(e) {
e.preventDefault();
toggleSearch();
});
$searchInput.keyup(function(e) {
var key = (e.keyCode ? e.keyCode : e.which);
var q = $(this).val();
if (key == 27) {
e.preventDefault();
toggleSearch(false);
return;
}
if (q.length == 0) {
sidebar.filter(null);
} else {
var results = search(q);
sidebar.filter(
_.pluck(results, "path")
);
}
});
};
return {
init: init,
search: search,
toggle: toggleSearch
};
});
+22 -10
View File
@@ -1,32 +1,31 @@
define([
"lodash",
"utils/storage",
"utils/platform",
"core/state"
], function(storage, platform, state) {
], function(_, storage, platform, state) {
var $summary = state.$book.find(".book-summary");
// Toggle sidebar with or withour animation
var toggleSidebar = function(_state, animation) {
if (-state != null && isOpen() == _state) return;
if (state != null && isOpen() == _state) return;
if (animation == null) animation = true;
var $book = state().$book;
$book.toggleClass("without-animation", !animation);
$book.toggleClass("with-summary", _state);
state.$book.toggleClass("without-animation", !animation);
state.$book.toggleClass("with-summary", _state);
storage.set("sidebar", isOpen());
};
// Return true if sidebar is open
var isOpen = function() {
return state().$book.hasClass("with-summary");
return state.$book.hasClass("with-summary");
};
// Prepare sidebar: state and toggle button
var init = function() {
var $book = state().$book;
// Toggle summary
$book.find(".book-header .toggle-summary").click(function(e) {
state.$book.find(".book-header .toggle-summary").click(function(e) {
e.preventDefault();
toggleSidebar();
});
@@ -37,8 +36,21 @@ define([
}
};
// Filter summary with a list of path
var filterSummary = function(paths) {
$summary.find("li").each(function() {
var path = $(this).data("path");
var st = paths == null || _.contains(paths, path);
$(this).toggle(st);
if (st) $(this).parents("li").show();
});
};
return {
$el: $summary,
init: init,
toggle: toggleSidebar
toggle: toggleSidebar,
filter: filterSummary
}
});
+7 -7
View File
@@ -1,14 +1,14 @@
define([
"jQuery"
], function() {
return function() {
var $book = $(".book");
var $book = $(".book");
return {
'$book': $book,
return {
'$book': $book,
'githubId': $book.data("github"),
'level': $book.data("level")
};
'githubId': $book.data("github"),
'level': $book.data("level"),
'basePath': $book.data("basepath"),
'revision': $book.data("revision")
};
});
+46 -2
View File
@@ -1,4 +1,6 @@
.book {
@searchHeight: 41px;
.book-summary {
@width: 250px;
@@ -8,19 +10,49 @@
bottom: 0px;
z-index: 1;
overflow-y: auto;
width: @width;
background: #2e3133;
color: #e2edf2;
.transition(all 0.5s ease);
.book-search {
padding: 6px;
padding-top: 0px;
background: #242628;
border-bottom: 1px solid #333;
position: absolute;
top: -@searchHeight;
left: 0px;
right: 0px;
.transition(top 0.5s ease);
input, input:focus {
width: 100%;
border: none;
.box-shadow(none);
}
}
ul.summary {
position: absolute;
top: 0px;
left: 0px;
right: 0px;
bottom: 0px;
overflow-y: auto;
list-style: none;
margin: 0px;
padding: 0px;
.transition(top 0.5s ease);
li {
list-style: none;
@@ -96,4 +128,16 @@
.transition(none) !important;
}
}
&.with-search {
.book-summary {
.book-search {
top: 0px;
}
ul.summary {
top: @searchHeight;
}
}
}
}
@@ -2,6 +2,7 @@
<!-- Actions Left -->
<a href="{{ githubHost }}{{ githubId }}" target="_blank" class="btn pull-left"><i class="fa fa-github-alt"></i></a>
<a href="#" class="btn pull-left toggle-summary"><i class="fa fa-align-justify"></i></a>
<a href="#" class="btn pull-left toggle-search"><i class="fa fa-search"></i></a>
<!-- Actions Right -->
<a href="#" target="_blank" class="btn pull-right" data-sharing="google-plus"><i class="fa fa-google-plus"></i></a>
+6 -3
View File
@@ -1,4 +1,7 @@
<div class="book-summary">
<div class="book-search">
<input type="text" placeholder="Search" class="form-control" />
</div>
<ul class="summary">
<li>
<a href="{{ githubHost }}{{ githubAuthor }}" target="blank">About the author</a>
@@ -10,11 +13,11 @@
<a href="{{ githubHost }}{{ githubId }}/edit/master/{{ _input }}" target="blank">Edit and Contribute</a>
</li>
<li class="divider"></li>
<li data-level="0">
<li data-level="0" data-path="index.html">
<a href="{{ basePath }}/"><i class="fa fa-check"></i> Introduction</a>
</li>
{% for item in summary.chapters %}
<li {% if item._path == _input %}class="active"{% endif %} data-level="{{ item.level }}">
<li {% if item._path == _input %}class="active"{% endif %} data-level="{{ item.level }}" {% if item.path %}data-path="{{ item.path|mdLink }}"{% endif %}>
{% if item.path %}
<a href="{{ basePath }}/{{ item.path|mdLink }}">
<i class="fa fa-check"></i> <b>{{ item.level }})</b> {{ item.title }}
@@ -25,7 +28,7 @@
{% if item.articles.length > 0 %}
<ul class="articles">
{% for article in item.articles %}
<li {% if article._path == _input %}class="active"{% endif %} data-level="{{ article.level }}">
<li {% if article._path == _input %}class="active"{% endif %} data-level="{{ article.level }}" {% if article.path %}data-path="{{ article.path|mdLink }}"{% endif %}>
{% if article.path %}
<a href="{{ basePath }}/{{ article.path|mdLink }}">
<i class="fa fa-check"></i> <b>{{ article.level }})</b> {{ article.title }}
+1 -1
View File
@@ -2,7 +2,7 @@
{% block title %}{{ progress.current.title }}{% parent %}{% endblock %}
{% block content %}
<div class="book" data-github="{{ githubId }}" data-level="{{ progress.current.level }}">
<div class="book" data-github="{{ githubId }}" data-level="{{ progress.current.level }}" data-basepath="{{ basePath }}" data-revision="{{ revision }}">
{% include "includes/book/header.html" %}
{% include "includes/book/summary.html" %}
<div class="book-body" tabindex="-1">