Commit 452876af authored by Tariq Islam's avatar Tariq Islam

Merge pull request #239 from tripit/update

Bugfixes merged.
parents 7452f6b1 16dca4d0
FROM ubuntu:trusty
RUN apt-get update
RUN apt-get install -yq ruby ruby-dev build-essential
RUN apt-get install -yq ruby ruby-dev build-essential git
RUN gem install --no-ri --no-rdoc bundler
ADD Gemfile /app/Gemfile
ADD Gemfile.lock /app/Gemfile.lock
......@@ -9,4 +9,4 @@ RUN cd /app; bundle install
ADD . /app
EXPOSE 4567
WORKDIR /app
CMD ["bundle", "exec", "middleman", "server"]
\ No newline at end of file
CMD ["bundle", "exec", "middleman", "server"]
# If you have OpenSSL installed, we recommend updating
# the following line to use "https"
source 'http://rubygems.org'
gem "rouge", "1.7.2"
# Middleman
gem 'middleman', '~>3.3.10'
gem 'middleman-gh-pages', '~> 0.0.3'
gem 'middleman-syntax', '~> 2.0.0'
gem 'rouge', '~> 1.8.0'
gem 'redcarpet', '~> 3.2.2'
gem "middleman", "~>3.3.0"
# For syntax highlighting
gem "middleman-syntax"
# Plugin for middleman to generate Github pages
gem 'middleman-gh-pages'
# Live-reloading plugin
gem "middleman-livereload", "~> 3.3.0"
gem 'redcarpet', '~> 3.2.1'
# For faster file watcher updates on Windows:
gem "wdm", "~> 0.1.0", :platforms => [:mswin, :mingw]
# Cross-templating language block fix for Ruby 1.8
platforms :mri_18 do
gem "ruby18_source_location"
end
gem "rake", "~> 10.4.0"
gem 'therubyracer', :platforms => :ruby
\ No newline at end of file
gem 'rake', '~> 10.4.2'
gem 'therubyracer', '~> 0.12.1', platforms: :ruby
GEM
remote: http://rubygems.org/
specs:
activesupport (4.1.9)
activesupport (4.1.10)
i18n (~> 0.6, >= 0.6.9)
json (~> 1.7, >= 1.7.7)
minitest (~> 5.1)
......@@ -9,62 +9,57 @@ GEM
tzinfo (~> 1.1)
celluloid (0.16.0)
timers (~> 4.0.0)
chunky_png (1.3.3)
coffee-script (2.3.0)
chunky_png (1.3.4)
coffee-script (2.4.1)
coffee-script-source
execjs
coffee-script-source (1.8.0)
compass (1.0.1)
coffee-script-source (1.9.1.1)
compass (1.0.3)
chunky_png (~> 1.2)
compass-core (~> 1.0.1)
compass-core (~> 1.0.2)
compass-import-once (~> 1.0.5)
rb-fsevent (>= 0.9.3)
rb-inotify (>= 0.9)
sass (>= 3.3.13, < 3.5)
compass-core (1.0.1)
compass-core (1.0.3)
multi_json (~> 1.0)
sass (>= 3.3.0, < 3.5)
compass-import-once (1.0.5)
sass (>= 3.2, < 3.5)
em-websocket (0.5.1)
eventmachine (>= 0.12.9)
http_parser.rb (~> 0.6.0)
erubis (2.7.0)
eventmachine (1.0.4)
execjs (2.2.2)
ffi (1.9.6)
execjs (2.5.2)
ffi (1.9.8)
haml (4.0.6)
tilt
hike (1.2.3)
hitimes (1.2.2)
hooks (0.4.0)
uber (~> 0.0.4)
http_parser.rb (0.6.0)
i18n (0.6.11)
i18n (0.7.0)
json (1.8.2)
kramdown (1.5.0)
kramdown (1.7.0)
libv8 (3.16.14.7)
listen (2.8.5)
celluloid (>= 0.15.2)
listen (2.10.0)
celluloid (~> 0.16.0)
rb-fsevent (>= 0.9.3)
rb-inotify (>= 0.9)
middleman (3.3.7)
middleman (3.3.11)
coffee-script (~> 2.2)
compass (>= 1.0.0, < 2.0.0)
compass-import-once (= 1.0.5)
execjs (~> 2.0)
haml (>= 4.0.5)
kramdown (~> 1.2)
middleman-core (= 3.3.7)
middleman-core (= 3.3.11)
middleman-sprockets (>= 3.1.2)
sass (>= 3.4.0, < 4.0)
uglifier (~> 2.5)
middleman-core (3.3.7)
middleman-core (3.3.11)
activesupport (~> 4.1.0)
bundler (~> 1.1)
erubis
hooks (~> 0.3)
i18n (~> 0.6.9)
i18n (~> 0.7.0)
listen (>= 2.7.9, < 3.0)
padrino-helpers (~> 0.12.3)
rack (>= 1.4.5, < 2.0)
......@@ -73,11 +68,7 @@ GEM
tilt (~> 1.4.1, < 2.0)
middleman-gh-pages (0.0.3)
rake (> 0.9.3)
middleman-livereload (3.3.4)
em-websocket (~> 0.5.1)
middleman-core (~> 3.2)
rack-livereload (~> 0.3.15)
middleman-sprockets (3.4.1)
middleman-sprockets (3.4.2)
middleman-core (>= 3.3)
sprockets (~> 2.12.1)
sprockets-helpers (~> 1.1.0)
......@@ -85,28 +76,25 @@ GEM
middleman-syntax (2.0.0)
middleman-core (~> 3.2)
rouge (~> 1.0)
minitest (5.5.1)
multi_json (1.10.1)
padrino-helpers (0.12.4)
minitest (5.6.1)
multi_json (1.11.0)
padrino-helpers (0.12.5)
i18n (~> 0.6, >= 0.6.7)
padrino-support (= 0.12.4)
padrino-support (= 0.12.5)
tilt (~> 1.4.1)
padrino-support (0.12.4)
padrino-support (0.12.5)
activesupport (>= 3.1)
rack (1.6.0)
rack-livereload (0.3.15)
rack
rack-test (0.6.3)
rack (>= 1.0)
rake (10.4.2)
rb-fsevent (0.9.4)
rb-inotify (0.9.5)
ffi (>= 0.5.0)
redcarpet (3.2.2)
redcarpet (3.2.3)
ref (1.0.5)
rouge (1.7.2)
ruby18_source_location (0.2)
sass (3.4.9)
rouge (1.8.0)
sass (3.4.13)
sprockets (2.12.3)
hike (~> 1.2)
multi_json (~> 1.0)
......@@ -117,18 +105,18 @@ GEM
sprockets-sass (1.3.1)
sprockets (~> 2.0)
tilt (~> 1.1)
therubyracer (0.12.1)
therubyracer (0.12.2)
libv8 (~> 3.16.14.0)
ref
thor (0.19.1)
thread_safe (0.3.4)
thread_safe (0.3.5)
tilt (1.4.1)
timers (4.0.1)
hitimes
tzinfo (1.2.2)
thread_safe (~> 0.1)
uber (0.0.13)
uglifier (2.7.0)
uglifier (2.7.1)
execjs (>= 0.3.0)
json (>= 1.8.0)
......@@ -136,13 +124,10 @@ PLATFORMS
ruby
DEPENDENCIES
middleman (~> 3.3.0)
middleman-gh-pages
middleman-livereload (~> 3.3.0)
middleman-syntax
rake (~> 10.4.0)
redcarpet (~> 3.2.1)
rouge (= 1.7.2)
ruby18_source_location
therubyracer
wdm (~> 0.1.0)
middleman (~> 3.3.10)
middleman-gh-pages (~> 0.0.3)
middleman-syntax (~> 2.0.0)
rake (~> 10.4.2)
redcarpet (~> 3.2.2)
rouge (~> 1.8.0)
therubyracer (~> 0.12.1)
......@@ -84,8 +84,10 @@ Examples of Slate in the Wild
* [Switch Payments Documentation](http://switchpayments.com/docs/) & [API](http://switchpayments.com/developers/)
* [Coinbase API Reference](https://developers.coinbase.com/api)
* [Whispir.io API](https://whispir.github.io/api)
* [Nasa API](https://data.nasa.gov/developer/external/planetary/)
* [NASA API](https://data.nasa.gov/developer/external/planetary/)
* [CardPay API](https://developers.cardpay.com/)
* [IBM Cloudant](https://docs-testb.cloudant.com/content-review/_design/couchapp/index.html)
* [Bitrix basis components](http://bbc.bitrix.expert/)
(Feel free to add your site to this list in a pull request!)
......
# Markdown
set :markdown_engine, :redcarpet
set :markdown,
fenced_code_blocks: true,
smartypants: true,
disable_indented_code_blocks: true,
prettify: true,
tables: true,
with_toc_data: true,
no_intra_emphasis: true
# Assets
set :css_dir, 'stylesheets'
set :js_dir, 'javascripts'
set :images_dir, 'images'
set :fonts_dir, 'fonts'
set :markdown_engine, :redcarpet
set :markdown, :fenced_code_blocks => true, :smartypants => true, :disable_indented_code_blocks => true, :prettify => true, :tables => true, :with_toc_data => true, :no_intra_emphasis => true
# Activate the syntax highlighter
activate :syntax
# This is needed for Github pages, since they're hosted on a subdomain
# Github pages require relative links
activate :relative_assets
set :relative_links, true
# Build-specific configuration
# Build Configuration
configure :build do
# For example, change the Compass output style for deployment
activate :minify_css
# Minify Javascript on build
activate :minify_javascript
# Enable cache buster
# activate :asset_hash
# Use relative URLs
# activate :relative_assets
# Or use a different image path
# set :http_prefix, "/Content/images/"
# activate :asset_hash
# activate :gzip
end
source/images/logo.png

4.68 KB | W: | H:

source/images/logo.png

3.42 KB | W: | H:

source/images/logo.png
source/images/logo.png
source/images/logo.png
source/images/logo.png
  • 2-up
  • Swipe
  • Onion skin
source/images/navbar.png

2.72 KB | W: | H:

source/images/navbar.png

96 Bytes | W: | H:

source/images/navbar.png
source/images/navbar.png
source/images/navbar.png
source/images/navbar.png
  • 2-up
  • Swipe
  • Onion skin
......@@ -55,7 +55,7 @@ Kittn expects for the API key to be included in all API requests to the server i
`Authorization: meowmeowmeow`
<aside class="notice">
You must replace `meowmeowmeow` with your personal API key.
You must replace <code>meowmeowmeow</code> with your personal API key.
</aside>
# Kittens
......
......@@ -14,6 +14,8 @@ License for the specific language governing permissions and limitations
under the License.
*/
(function (global) {
'use strict';
var languages = [];
global.setupLanguages = setupLanguages;
......@@ -26,9 +28,9 @@ under the License.
$(".lang-selector a").removeClass('active');
$(".lang-selector a[data-language-name='" + language + "']").addClass('active');
for (var i=0; i < languages.length; i++) {
$(".highlight." + languages[i]).parent().hide();
$(".highlight." + languages[i]).hide();
}
$(".highlight." + language).parent().show();
$(".highlight." + language).show();
global.toc.calculateHeights();
......
(function (global) {
'use strict';
var $global = $(global);
var content, darkBox, searchResults;
......@@ -49,7 +50,8 @@
if (results.length) {
searchResults.empty();
$.each(results, function (index, result) {
searchResults.append("<li><a href='#" + result.ref + "'>" + $('#'+result.ref).text() + "</a></li>");
var elem = document.getElementById(result.ref);
searchResults.append("<li><a href='#" + result.ref + "'>" + $(elem).text() + "</a></li>");
});
highlight.call(this);
} else {
......
(function (global) {
'use strict';
var closeToc = function() {
$(".tocify-wrapper").removeClass('open');
......
/*! jQuery UI - v1.10.3 - 2013-09-16
* http://jqueryui.com
* Includes: jquery.ui.widget.js
* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
/*! jQuery UI - v1.11.3 - 2015-02-12
* http://jqueryui.com
* Includes: widget.js
* Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */
(function(e,t){var i=0,s=Array.prototype.slice,a=e.cleanData;e.cleanData=function(t){for(var i,s=0;null!=(i=t[s]);s++)try{e(i).triggerHandler("remove")}catch(n){}a(t)},e.widget=function(i,s,a){var n,r,o,h,l={},u=i.split(".")[0];i=i.split(".")[1],n=u+"-"+i,a||(a=s,s=e.Widget),e.expr[":"][n.toLowerCase()]=function(t){return!!e.data(t,n)},e[u]=e[u]||{},r=e[u][i],o=e[u][i]=function(e,i){return this._createWidget?(arguments.length&&this._createWidget(e,i),t):new o(e,i)},e.extend(o,r,{version:a.version,_proto:e.extend({},a),_childConstructors:[]}),h=new s,h.options=e.widget.extend({},h.options),e.each(a,function(i,a){return e.isFunction(a)?(l[i]=function(){var e=function(){return s.prototype[i].apply(this,arguments)},t=function(e){return s.prototype[i].apply(this,e)};return function(){var i,s=this._super,n=this._superApply;return this._super=e,this._superApply=t,i=a.apply(this,arguments),this._super=s,this._superApply=n,i}}(),t):(l[i]=a,t)}),o.prototype=e.widget.extend(h,{widgetEventPrefix:r?h.widgetEventPrefix:i},l,{constructor:o,namespace:u,widgetName:i,widgetFullName:n}),r?(e.each(r._childConstructors,function(t,i){var s=i.prototype;e.widget(s.namespace+"."+s.widgetName,o,i._proto)}),delete r._childConstructors):s._childConstructors.push(o),e.widget.bridge(i,o)},e.widget.extend=function(i){for(var a,n,r=s.call(arguments,1),o=0,h=r.length;h>o;o++)for(a in r[o])n=r[o][a],r[o].hasOwnProperty(a)&&n!==t&&(i[a]=e.isPlainObject(n)?e.isPlainObject(i[a])?e.widget.extend({},i[a],n):e.widget.extend({},n):n);return i},e.widget.bridge=function(i,a){var n=a.prototype.widgetFullName||i;e.fn[i]=function(r){var o="string"==typeof r,h=s.call(arguments,1),l=this;return r=!o&&h.length?e.widget.extend.apply(null,[r].concat(h)):r,o?this.each(function(){var s,a=e.data(this,n);return a?e.isFunction(a[r])&&"_"!==r.charAt(0)?(s=a[r].apply(a,h),s!==a&&s!==t?(l=s&&s.jquery?l.pushStack(s.get()):s,!1):t):e.error("no such method '"+r+"' for "+i+" widget instance"):e.error("cannot call methods on "+i+" prior to initialization; "+"attempted to call method '"+r+"'")}):this.each(function(){var t=e.data(this,n);t?t.option(r||{})._init():e.data(this,n,new a(r,this))}),l}},e.Widget=function(){},e.Widget._childConstructors=[],e.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"<div>",options:{disabled:!1,create:null},_createWidget:function(t,s){s=e(s||this.defaultElement||this)[0],this.element=e(s),this.uuid=i++,this.eventNamespace="."+this.widgetName+this.uuid,this.options=e.widget.extend({},this.options,this._getCreateOptions(),t),this.bindings=e(),this.hoverable=e(),this.focusable=e(),s!==this&&(e.data(s,this.widgetFullName,this),this._on(!0,this.element,{remove:function(e){e.target===s&&this.destroy()}}),this.document=e(s.style?s.ownerDocument:s.document||s),this.window=e(this.document[0].defaultView||this.document[0].parentWindow)),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:e.noop,_getCreateEventData:e.noop,_create:e.noop,_init:e.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetName).removeData(this.widgetFullName).removeData(e.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled "+"ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:e.noop,widget:function(){return this.element},option:function(i,s){var a,n,r,o=i;if(0===arguments.length)return e.widget.extend({},this.options);if("string"==typeof i)if(o={},a=i.split("."),i=a.shift(),a.length){for(n=o[i]=e.widget.extend({},this.options[i]),r=0;a.length-1>r;r++)n[a[r]]=n[a[r]]||{},n=n[a[r]];if(i=a.pop(),s===t)return n[i]===t?null:n[i];n[i]=s}else{if(s===t)return this.options[i]===t?null:this.options[i];o[i]=s}return this._setOptions(o),this},_setOptions:function(e){var t;for(t in e)this._setOption(t,e[t]);return this},_setOption:function(e,t){return this.options[e]=t,"disabled"===e&&(this.widget().toggleClass(this.widgetFullName+"-disabled ui-state-disabled",!!t).attr("aria-disabled",t),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")),this},enable:function(){return this._setOption("disabled",!1)},disable:function(){return this._setOption("disabled",!0)},_on:function(i,s,a){var n,r=this;"boolean"!=typeof i&&(a=s,s=i,i=!1),a?(s=n=e(s),this.bindings=this.bindings.add(s)):(a=s,s=this.element,n=this.widget()),e.each(a,function(a,o){function h(){return i||r.options.disabled!==!0&&!e(this).hasClass("ui-state-disabled")?("string"==typeof o?r[o]:o).apply(r,arguments):t}"string"!=typeof o&&(h.guid=o.guid=o.guid||h.guid||e.guid++);var l=a.match(/^(\w+)\s*(.*)$/),u=l[1]+r.eventNamespace,c=l[2];c?n.delegate(c,u,h):s.bind(u,h)})},_off:function(e,t){t=(t||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,e.unbind(t).undelegate(t)},_delay:function(e,t){function i(){return("string"==typeof e?s[e]:e).apply(s,arguments)}var s=this;return setTimeout(i,t||0)},_hoverable:function(t){this.hoverable=this.hoverable.add(t),this._on(t,{mouseenter:function(t){e(t.currentTarget).addClass("ui-state-hover")},mouseleave:function(t){e(t.currentTarget).removeClass("ui-state-hover")}})},_focusable:function(t){this.focusable=this.focusable.add(t),this._on(t,{focusin:function(t){e(t.currentTarget).addClass("ui-state-focus")},focusout:function(t){e(t.currentTarget).removeClass("ui-state-focus")}})},_trigger:function(t,i,s){var a,n,r=this.options[t];if(s=s||{},i=e.Event(i),i.type=(t===this.widgetEventPrefix?t:this.widgetEventPrefix+t).toLowerCase(),i.target=this.element[0],n=i.originalEvent)for(a in n)a in i||(i[a]=n[a]);return this.element.trigger(i,s),!(e.isFunction(r)&&r.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},e.each({show:"fadeIn",hide:"fadeOut"},function(t,i){e.Widget.prototype["_"+t]=function(s,a,n){"string"==typeof a&&(a={effect:a});var r,o=a?a===!0||"number"==typeof a?i:a.effect||i:t;a=a||{},"number"==typeof a&&(a={duration:a}),r=!e.isEmptyObject(a),a.complete=n,a.delay&&s.delay(a.delay),r&&e.effects&&e.effects.effect[o]?s[t](a):o!==t&&s[o]?s[o](a.duration,a.easing,n):s.queue(function(i){e(this)[t](),n&&n.call(s[0]),i()})}})})(jQuery);
\ No newline at end of file
(function( factory ) {
if ( typeof define === "function" && define.amd ) {
// AMD. Register as an anonymous module.
define([ "jquery" ], factory );
} else {
// Browser globals
factory( jQuery );
}
}(function( $ ) {
/*!
* jQuery UI Widget 1.11.3
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*
* http://api.jqueryui.com/jQuery.widget/
*/
var widget_uuid = 0,
widget_slice = Array.prototype.slice;
$.cleanData = (function( orig ) {
return function( elems ) {
var events, elem, i;
for ( i = 0; (elem = elems[i]) != null; i++ ) {
try {
// Only trigger remove when necessary to save time
events = $._data( elem, "events" );
if ( events && events.remove ) {
$( elem ).triggerHandler( "remove" );
}
// http://bugs.jquery.com/ticket/8235
} catch ( e ) {}
}
orig( elems );
};
})( $.cleanData );
$.widget = function( name, base, prototype ) {
var fullName, existingConstructor, constructor, basePrototype,
// proxiedPrototype allows the provided prototype to remain unmodified
// so that it can be used as a mixin for multiple widgets (#8876)
proxiedPrototype = {},
namespace = name.split( "." )[ 0 ];
name = name.split( "." )[ 1 ];
fullName = namespace + "-" + name;
if ( !prototype ) {
prototype = base;
base = $.Widget;
}
// create selector for plugin
$.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
return !!$.data( elem, fullName );
};
$[ namespace ] = $[ namespace ] || {};
existingConstructor = $[ namespace ][ name ];
constructor = $[ namespace ][ name ] = function( options, element ) {
// allow instantiation without "new" keyword
if ( !this._createWidget ) {
return new constructor( options, element );
}
// allow instantiation without initializing for simple inheritance
// must use "new" keyword (the code above always passes args)
if ( arguments.length ) {
this._createWidget( options, element );
}
};
// extend with the existing constructor to carry over any static properties
$.extend( constructor, existingConstructor, {
version: prototype.version,
// copy the object used to create the prototype in case we need to
// redefine the widget later
_proto: $.extend( {}, prototype ),
// track widgets that inherit from this widget in case this widget is
// redefined after a widget inherits from it
_childConstructors: []
});
basePrototype = new base();
// we need to make the options hash a property directly on the new instance
// otherwise we'll modify the options hash on the prototype that we're
// inheriting from
basePrototype.options = $.widget.extend( {}, basePrototype.options );
$.each( prototype, function( prop, value ) {
if ( !$.isFunction( value ) ) {
proxiedPrototype[ prop ] = value;
return;
}
proxiedPrototype[ prop ] = (function() {
var _super = function() {
return base.prototype[ prop ].apply( this, arguments );
},
_superApply = function( args ) {
return base.prototype[ prop ].apply( this, args );
};
return function() {
var __super = this._super,
__superApply = this._superApply,
returnValue;
this._super = _super;
this._superApply = _superApply;
returnValue = value.apply( this, arguments );
this._super = __super;
this._superApply = __superApply;
return returnValue;
};
})();
});
constructor.prototype = $.widget.extend( basePrototype, {
// TODO: remove support for widgetEventPrefix
// always use the name + a colon as the prefix, e.g., draggable:start
// don't prefix for widgets that aren't DOM-based
widgetEventPrefix: existingConstructor ? (basePrototype.widgetEventPrefix || name) : name
}, proxiedPrototype, {
constructor: constructor,
namespace: namespace,
widgetName: name,
widgetFullName: fullName
});
// If this widget is being redefined then we need to find all widgets that
// are inheriting from it and redefine all of them so that they inherit from
// the new version of this widget. We're essentially trying to replace one
// level in the prototype chain.
if ( existingConstructor ) {
$.each( existingConstructor._childConstructors, function( i, child ) {
var childPrototype = child.prototype;
// redefine the child widget using the same prototype that was
// originally used, but inherit from the new version of the base
$.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
});
// remove the list of existing child constructors from the old constructor
// so the old child constructors can be garbage collected
delete existingConstructor._childConstructors;
} else {
base._childConstructors.push( constructor );
}
$.widget.bridge( name, constructor );
return constructor;
};
$.widget.extend = function( target ) {
var input = widget_slice.call( arguments, 1 ),
inputIndex = 0,
inputLength = input.length,
key,
value;
for ( ; inputIndex < inputLength; inputIndex++ ) {
for ( key in input[ inputIndex ] ) {
value = input[ inputIndex ][ key ];
if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
// Clone objects
if ( $.isPlainObject( value ) ) {
target[ key ] = $.isPlainObject( target[ key ] ) ?
$.widget.extend( {}, target[ key ], value ) :
// Don't extend strings, arrays, etc. with objects
$.widget.extend( {}, value );
// Copy everything else by reference
} else {
target[ key ] = value;
}
}
}
}
return target;
};
$.widget.bridge = function( name, object ) {
var fullName = object.prototype.widgetFullName || name;
$.fn[ name ] = function( options ) {
var isMethodCall = typeof options === "string",
args = widget_slice.call( arguments, 1 ),
returnValue = this;
if ( isMethodCall ) {
this.each(function() {
var methodValue,
instance = $.data( this, fullName );
if ( options === "instance" ) {
returnValue = instance;
return false;
}
if ( !instance ) {
return $.error( "cannot call methods on " + name + " prior to initialization; " +
"attempted to call method '" + options + "'" );
}
if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
return $.error( "no such method '" + options + "' for " + name + " widget instance" );
}
methodValue = instance[ options ].apply( instance, args );
if ( methodValue !== instance && methodValue !== undefined ) {
returnValue = methodValue && methodValue.jquery ?
returnValue.pushStack( methodValue.get() ) :
methodValue;
return false;
}
});
} else {
// Allow multiple hashes to be passed on init
if ( args.length ) {
options = $.widget.extend.apply( null, [ options ].concat(args) );
}
this.each(function() {
var instance = $.data( this, fullName );
if ( instance ) {
instance.option( options || {} );
if ( instance._init ) {
instance._init();
}
} else {
$.data( this, fullName, new object( options, this ) );
}
});
}
return returnValue;
};
};
$.Widget = function( /* options, element */ ) {};
$.Widget._childConstructors = [];
$.Widget.prototype = {
widgetName: "widget",
widgetEventPrefix: "",
defaultElement: "<div>",
options: {
disabled: false,
// callbacks
create: null
},
_createWidget: function( options, element ) {
element = $( element || this.defaultElement || this )[ 0 ];
this.element = $( element );
this.uuid = widget_uuid++;
this.eventNamespace = "." + this.widgetName + this.uuid;
this.bindings = $();
this.hoverable = $();
this.focusable = $();
if ( element !== this ) {
$.data( element, this.widgetFullName, this );
this._on( true, this.element, {
remove: function( event ) {
if ( event.target === element ) {
this.destroy();
}
}
});
this.document = $( element.style ?
// element within the document
element.ownerDocument :
// element is window or document
element.document || element );
this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
}
this.options = $.widget.extend( {},
this.options,
this._getCreateOptions(),
options );
this._create();
this._trigger( "create", null, this._getCreateEventData() );
this._init();
},
_getCreateOptions: $.noop,
_getCreateEventData: $.noop,
_create: $.noop,
_init: $.noop,
destroy: function() {
this._destroy();
// we can probably remove the unbind calls in 2.0
// all event bindings should go through this._on()
this.element
.unbind( this.eventNamespace )
.removeData( this.widgetFullName )
// support: jquery <1.6.3
// http://bugs.jquery.com/ticket/9413
.removeData( $.camelCase( this.widgetFullName ) );
this.widget()
.unbind( this.eventNamespace )
.removeAttr( "aria-disabled" )
.removeClass(
this.widgetFullName + "-disabled " +
"ui-state-disabled" );
// clean up events and states
this.bindings.unbind( this.eventNamespace );
this.hoverable.removeClass( "ui-state-hover" );
this.focusable.removeClass( "ui-state-focus" );
},
_destroy: $.noop,
widget: function() {
return this.element;
},
option: function( key, value ) {
var options = key,
parts,
curOption,
i;
if ( arguments.length === 0 ) {
// don't return a reference to the internal hash
return $.widget.extend( {}, this.options );
}
if ( typeof key === "string" ) {
// handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
options = {};
parts = key.split( "." );
key = parts.shift();
if ( parts.length ) {
curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
for ( i = 0; i < parts.length - 1; i++ ) {
curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
curOption = curOption[ parts[ i ] ];
}
key = parts.pop();
if ( arguments.length === 1 ) {
return curOption[ key ] === undefined ? null : curOption[ key ];
}
curOption[ key ] = value;
} else {
if ( arguments.length === 1 ) {
return this.options[ key ] === undefined ? null : this.options[ key ];
}
options[ key ] = value;
}
}
this._setOptions( options );
return this;
},
_setOptions: function( options ) {
var key;
for ( key in options ) {
this._setOption( key, options[ key ] );
}
return this;
},
_setOption: function( key, value ) {
this.options[ key ] = value;
if ( key === "disabled" ) {
this.widget()
.toggleClass( this.widgetFullName + "-disabled", !!value );
// If the widget is becoming disabled, then nothing is interactive
if ( value ) {
this.hoverable.removeClass( "ui-state-hover" );
this.focusable.removeClass( "ui-state-focus" );
}
}
return this;
},
enable: function() {
return this._setOptions({ disabled: false });
},
disable: function() {
return this._setOptions({ disabled: true });
},
_on: function( suppressDisabledCheck, element, handlers ) {
var delegateElement,
instance = this;
// no suppressDisabledCheck flag, shuffle arguments
if ( typeof suppressDisabledCheck !== "boolean" ) {
handlers = element;
element = suppressDisabledCheck;
suppressDisabledCheck = false;
}
// no element argument, shuffle and use this.element
if ( !handlers ) {
handlers = element;
element = this.element;
delegateElement = this.widget();
} else {
element = delegateElement = $( element );
this.bindings = this.bindings.add( element );
}
$.each( handlers, function( event, handler ) {
function handlerProxy() {
// allow widgets to customize the disabled handling
// - disabled as an array instead of boolean
// - disabled class as method for disabling individual parts
if ( !suppressDisabledCheck &&
( instance.options.disabled === true ||
$( this ).hasClass( "ui-state-disabled" ) ) ) {
return;
}
return ( typeof handler === "string" ? instance[ handler ] : handler )
.apply( instance, arguments );
}
// copy the guid so direct unbinding works
if ( typeof handler !== "string" ) {
handlerProxy.guid = handler.guid =
handler.guid || handlerProxy.guid || $.guid++;
}
var match = event.match( /^([\w:-]*)\s*(.*)$/ ),
eventName = match[1] + instance.eventNamespace,
selector = match[2];
if ( selector ) {
delegateElement.delegate( selector, eventName, handlerProxy );
} else {
element.bind( eventName, handlerProxy );
}
});
},
_off: function( element, eventName ) {
eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) +
this.eventNamespace;
element.unbind( eventName ).undelegate( eventName );
// Clear the stack to avoid memory leaks (#10056)
this.bindings = $( this.bindings.not( element ).get() );
this.focusable = $( this.focusable.not( element ).get() );
this.hoverable = $( this.hoverable.not( element ).get() );
},
_delay: function( handler, delay ) {
function handlerProxy() {
return ( typeof handler === "string" ? instance[ handler ] : handler )
.apply( instance, arguments );
}
var instance = this;
return setTimeout( handlerProxy, delay || 0 );
},
_hoverable: function( element ) {
this.hoverable = this.hoverable.add( element );
this._on( element, {
mouseenter: function( event ) {
$( event.currentTarget ).addClass( "ui-state-hover" );
},
mouseleave: function( event ) {
$( event.currentTarget ).removeClass( "ui-state-hover" );
}
});
},
_focusable: function( element ) {
this.focusable = this.focusable.add( element );
this._on( element, {
focusin: function( event ) {
$( event.currentTarget ).addClass( "ui-state-focus" );
},
focusout: function( event ) {
$( event.currentTarget ).removeClass( "ui-state-focus" );
}
});
},
_trigger: function( type, event, data ) {
var prop, orig,
callback = this.options[ type ];
data = data || {};
event = $.Event( event );
event.type = ( type === this.widgetEventPrefix ?
type :
this.widgetEventPrefix + type ).toLowerCase();
// the original event may come from any element
// so we need to reset the target on the new event
event.target = this.element[ 0 ];
// copy original event properties over to the new event
orig = event.originalEvent;
if ( orig ) {
for ( prop in orig ) {
if ( !( prop in event ) ) {
event[ prop ] = orig[ prop ];
}
}
}
this.element.trigger( event, data );
return !( $.isFunction( callback ) &&
callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
event.isDefaultPrevented() );
}
};
$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
$.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
if ( typeof options === "string" ) {
options = { effect: options };
}
var hasOptions,
effectName = !options ?
method :
options === true || typeof options === "number" ?
defaultEffect :
options.effect || defaultEffect;
options = options || {};
if ( typeof options === "number" ) {
options = { duration: options };
}
hasOptions = !$.isEmptyObject( options );
options.complete = callback;
if ( options.delay ) {
element.delay( options.delay );
}
if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
element[ method ]( options );
} else if ( effectName !== method && element[ effectName ] ) {
element[ effectName ]( options.duration, options.easing, callback );
} else {
element.queue(function( next ) {
$( this )[ method ]();
if ( callback ) {
callback.call( element[ 0 ] );
}
next();
});
}
};
});
var widget = $.widget;
}));
/**
* lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 0.5.2
* lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 0.5.7
* Copyright (C) 2014 Oliver Nightingale
* MIT Licensed
* @license
......@@ -7,1851 +7,1881 @@
(function(){
/**
* Convenience function for instantiating a new lunr index and configuring it
* with the default pipeline functions and the passed config function.
*
* When using this convenience function a new index will be created with the
* following functions already in the pipeline:
*
* lunr.StopWordFilter - filters out any stop words before they enter the
* index
*
* lunr.stemmer - stems the tokens before entering the index.
*
* Example:
*
* var idx = lunr(function () {
/**
* Convenience function for instantiating a new lunr index and configuring it
* with the default pipeline functions and the passed config function.
*
* When using this convenience function a new index will be created with the
* following functions already in the pipeline:
*
* lunr.StopWordFilter - filters out any stop words before they enter the
* index
*
* lunr.stemmer - stems the tokens before entering the index.
*
* Example:
*
* var idx = lunr(function () {
* this.field('title', 10)
* this.field('tags', 100)
* this.field('body')
*
*
* this.ref('cid')
*
*
* this.pipeline.add(function () {
* // some custom pipeline function
* })
*
* })
*
* @param {Function} config A function that will be called with the new instance
* of the lunr.Index as both its context and first parameter. It can be used to
* customize the instance of new lunr.Index.
* @namespace
* @module
* @returns {lunr.Index}
*
*/
var lunr = function (config) {
var idx = new lunr.Index
* })
*
* @param {Function} config A function that will be called with the new instance
* of the lunr.Index as both its context and first parameter. It can be used to
* customize the instance of new lunr.Index.
* @namespace
* @module
* @returns {lunr.Index}
*
*/
var lunr = function (config) {
var idx = new lunr.Index
idx.pipeline.add(
lunr.trimmer,
lunr.stopWordFilter,
lunr.stemmer
)
idx.pipeline.add(
lunr.trimmer,
lunr.stopWordFilter,
lunr.stemmer
)
if (config) config.call(idx, idx)
if (config) config.call(idx, idx)
return idx
}
return idx
}
lunr.version = "0.5.2"
/*!
* lunr.utils
* Copyright (C) 2014 Oliver Nightingale
*/
lunr.version = "0.5.7"
/*!
* lunr.utils
* Copyright (C) 2014 Oliver Nightingale
*/
/**
* A namespace containing utils for the rest of the lunr library
*/
lunr.utils = {}
/**
* A namespace containing utils for the rest of the lunr library
*/
lunr.utils = {}
/**
* Print a warning message to the console.
*
* @param {String} message The message to be printed.
* @memberOf Utils
*/
lunr.utils.warn = (function (global) {
return function (message) {
if (global.console && console.warn) {
console.warn(message)
/**
* Print a warning message to the console.
*
* @param {String} message The message to be printed.
* @memberOf Utils
*/
lunr.utils.warn = (function (global) {
return function (message) {
if (global.console && console.warn) {
console.warn(message)
}
}
}
})(this)
})(this)
/*!
* lunr.EventEmitter
* Copyright (C) 2014 Oliver Nightingale
*/
/*!
* lunr.EventEmitter
* Copyright (C) 2014 Oliver Nightingale
*/
/**
* lunr.EventEmitter is an event emitter for lunr. It manages adding and removing event handlers and triggering events and their handlers.
*
* @constructor
*/
lunr.EventEmitter = function () {
this.events = {}
}
/**
* lunr.EventEmitter is an event emitter for lunr. It manages adding and removing event handlers and triggering events and their handlers.
*
* @constructor
*/
lunr.EventEmitter = function () {
this.events = {}
}
/**
* Binds a handler function to a specific event(s).
*
* Can bind a single function to many different events in one call.
*
* @param {String} [eventName] The name(s) of events to bind this function to.
* @param {Function} handler The function to call when an event is fired.
* @memberOf EventEmitter
*/
lunr.EventEmitter.prototype.addListener = function () {
var args = Array.prototype.slice.call(arguments),
fn = args.pop(),
names = args
/**
* Binds a handler function to a specific event(s).
*
* Can bind a single function to many different events in one call.
*
* @param {String} [eventName] The name(s) of events to bind this function to.
* @param {Function} handler The function to call when an event is fired.
* @memberOf EventEmitter
*/
lunr.EventEmitter.prototype.addListener = function () {
var args = Array.prototype.slice.call(arguments),
fn = args.pop(),
names = args
if (typeof fn !== "function") throw new TypeError ("last argument must be a function")
if (typeof fn !== "function") throw new TypeError ("last argument must be a function")
names.forEach(function (name) {
if (!this.hasHandler(name)) this.events[name] = []
this.events[name].push(fn)
}, this)
}
names.forEach(function (name) {
if (!this.hasHandler(name)) this.events[name] = []
this.events[name].push(fn)
}, this)
}
/**
* Removes a handler function from a specific event.
*
* @param {String} eventName The name of the event to remove this function from.
* @param {Function} handler The function to remove from an event.
* @memberOf EventEmitter
*/
lunr.EventEmitter.prototype.removeListener = function (name, fn) {
if (!this.hasHandler(name)) return
/**
* Removes a handler function from a specific event.
*
* @param {String} eventName The name of the event to remove this function from.
* @param {Function} handler The function to remove from an event.
* @memberOf EventEmitter
*/
lunr.EventEmitter.prototype.removeListener = function (name, fn) {
if (!this.hasHandler(name)) return
var fnIndex = this.events[name].indexOf(fn)
this.events[name].splice(fnIndex, 1)
var fnIndex = this.events[name].indexOf(fn)
this.events[name].splice(fnIndex, 1)
if (!this.events[name].length) delete this.events[name]
}
if (!this.events[name].length) delete this.events[name]
}
/**
* Calls all functions bound to the given event.
*
* Additional data can be passed to the event handler as arguments to `emit`
* after the event name.
*
* @param {String} eventName The name of the event to emit.
* @memberOf EventEmitter
*/
lunr.EventEmitter.prototype.emit = function (name) {
if (!this.hasHandler(name)) return
/**
* Calls all functions bound to the given event.
*
* Additional data can be passed to the event handler as arguments to `emit`
* after the event name.
*
* @param {String} eventName The name of the event to emit.
* @memberOf EventEmitter
*/
lunr.EventEmitter.prototype.emit = function (name) {
if (!this.hasHandler(name)) return
var args = Array.prototype.slice.call(arguments, 1)
var args = Array.prototype.slice.call(arguments, 1)
this.events[name].forEach(function (fn) {
fn.apply(undefined, args)
})
}
this.events[name].forEach(function (fn) {
fn.apply(undefined, args)
})
}
/**
* Checks whether a handler has ever been stored against an event.
*
* @param {String} eventName The name of the event to check.
* @private
* @memberOf EventEmitter
*/
lunr.EventEmitter.prototype.hasHandler = function (name) {
return name in this.events
}
/**
* Checks whether a handler has ever been stored against an event.
*
* @param {String} eventName The name of the event to check.
* @private
* @memberOf EventEmitter
*/
lunr.EventEmitter.prototype.hasHandler = function (name) {
return name in this.events
}
/*!
* lunr.tokenizer
* Copyright (C) 2014 Oliver Nightingale
*/
/*!
* lunr.tokenizer
* Copyright (C) 2014 Oliver Nightingale
*/
/**
* A function for splitting a string into tokens ready to be inserted into
* the search index.
*
* @module
* @param {String} obj The string to convert into tokens
* @returns {Array}
*/
lunr.tokenizer = function (obj) {
if (!arguments.length || obj == null || obj == undefined) return []
if (Array.isArray(obj)) return obj.map(function (t) { return t.toLowerCase() })
/**
* A function for splitting a string into tokens ready to be inserted into
* the search index.
*
* @module
* @param {String} obj The string to convert into tokens
* @returns {Array}
*/
lunr.tokenizer = function (obj) {
if (!arguments.length || obj == null || obj == undefined) return []
if (Array.isArray(obj)) return obj.map(function (t) { return t.toLowerCase() })
var str = obj.toString().replace(/^\s+/, '')
var str = obj.toString().replace(/^\s+/, '')
for (var i = str.length - 1; i >= 0; i--) {
if (/\S/.test(str.charAt(i))) {
str = str.substring(0, i + 1)
break
for (var i = str.length - 1; i >= 0; i--) {
if (/\S/.test(str.charAt(i))) {
str = str.substring(0, i + 1)
break
}
}
return str
.split(/(?:\s+|\-)/)
.filter(function (token) {
return !!token
})
.map(function (token) {
return token.toLowerCase()
})
}
/*!
* lunr.Pipeline
* Copyright (C) 2014 Oliver Nightingale
*/
return str
.split(/\s+/)
.map(function (token) {
return token.toLowerCase()
})
}
/*!
* lunr.Pipeline
* Copyright (C) 2014 Oliver Nightingale
*/
/**
* lunr.Pipelines maintain an ordered list of functions to be applied to all
* tokens in documents entering the search index and queries being ran against
* the index.
*
* An instance of lunr.Index created with the lunr shortcut will contain a
* pipeline with a stop word filter and an English language stemmer. Extra
* functions can be added before or after either of these functions or these
* default functions can be removed.
*
* When run the pipeline will call each function in turn, passing a token, the
* index of that token in the original list of all tokens and finally a list of
* all the original tokens.
*
* The output of functions in the pipeline will be passed to the next function
* in the pipeline. To exclude a token from entering the index the function
* should return undefined, the rest of the pipeline will not be called with
* this token.
*
* For serialisation of pipelines to work, all functions used in an instance of
* a pipeline should be registered with lunr.Pipeline. Registered functions can
* then be loaded. If trying to load a serialised pipeline that uses functions
* that are not registered an error will be thrown.
*
* If not planning on serialising the pipeline then registering pipeline functions
* is not necessary.
*
* @constructor
*/
lunr.Pipeline = function () {
this._stack = []
}
/**
* lunr.Pipelines maintain an ordered list of functions to be applied to all
* tokens in documents entering the search index and queries being ran against
* the index.
*
* An instance of lunr.Index created with the lunr shortcut will contain a
* pipeline with a stop word filter and an English language stemmer. Extra
* functions can be added before or after either of these functions or these
* default functions can be removed.
*
* When run the pipeline will call each function in turn, passing a token, the
* index of that token in the original list of all tokens and finally a list of
* all the original tokens.
*
* The output of functions in the pipeline will be passed to the next function
* in the pipeline. To exclude a token from entering the index the function
* should return undefined, the rest of the pipeline will not be called with
* this token.
*
* For serialisation of pipelines to work, all functions used in an instance of
* a pipeline should be registered with lunr.Pipeline. Registered functions can
* then be loaded. If trying to load a serialised pipeline that uses functions
* that are not registered an error will be thrown.
*
* If not planning on serialising the pipeline then registering pipeline functions
* is not necessary.
*
* @constructor
*/
lunr.Pipeline = function () {
this._stack = []
}
lunr.Pipeline.registeredFunctions = {}
lunr.Pipeline.registeredFunctions = {}
/**
* Register a function with the pipeline.
*
* Functions that are used in the pipeline should be registered if the pipeline
* needs to be serialised, or a serialised pipeline needs to be loaded.
*
* Registering a function does not add it to a pipeline, functions must still be
* added to instances of the pipeline for them to be used when running a pipeline.
*
* @param {Function} fn The function to check for.
* @param {String} label The label to register this function with
* @memberOf Pipeline
*/
lunr.Pipeline.registerFunction = function (fn, label) {
if (label in this.registeredFunctions) {
lunr.utils.warn('Overwriting existing registered function: ' + label)
}
/**
* Register a function with the pipeline.
*
* Functions that are used in the pipeline should be registered if the pipeline
* needs to be serialised, or a serialised pipeline needs to be loaded.
*
* Registering a function does not add it to a pipeline, functions must still be
* added to instances of the pipeline for them to be used when running a pipeline.
*
* @param {Function} fn The function to check for.
* @param {String} label The label to register this function with
* @memberOf Pipeline
*/
lunr.Pipeline.registerFunction = function (fn, label) {
if (label in this.registeredFunctions) {
lunr.utils.warn('Overwriting existing registered function: ' + label)
fn.label = label
lunr.Pipeline.registeredFunctions[fn.label] = fn
}
fn.label = label
lunr.Pipeline.registeredFunctions[fn.label] = fn
}
/**
* Warns if the function is not registered as a Pipeline function.
*
* @param {Function} fn The function to check for.
* @private
* @memberOf Pipeline
*/
lunr.Pipeline.warnIfFunctionNotRegistered = function (fn) {
var isRegistered = fn.label && (fn.label in this.registeredFunctions)
/**
* Warns if the function is not registered as a Pipeline function.
*
* @param {Function} fn The function to check for.
* @private
* @memberOf Pipeline
*/
lunr.Pipeline.warnIfFunctionNotRegistered = function (fn) {
var isRegistered = fn.label && (fn.label in this.registeredFunctions)
if (!isRegistered) {
lunr.utils.warn('Function is not registered with pipeline. This may cause problems when serialising the index.\n', fn)
if (!isRegistered) {
lunr.utils.warn('Function is not registered with pipeline. This may cause problems when serialising the index.\n', fn)
}
}
}
/**
* Loads a previously serialised pipeline.
*
* All functions to be loaded must already be registered with lunr.Pipeline.
* If any function from the serialised data has not been registered then an
* error will be thrown.
*
* @param {Object} serialised The serialised pipeline to load.
* @returns {lunr.Pipeline}
* @memberOf Pipeline
*/
lunr.Pipeline.load = function (serialised) {
var pipeline = new lunr.Pipeline
/**
* Loads a previously serialised pipeline.
*
* All functions to be loaded must already be registered with lunr.Pipeline.
* If any function from the serialised data has not been registered then an
* error will be thrown.
*
* @param {Object} serialised The serialised pipeline to load.
* @returns {lunr.Pipeline}
* @memberOf Pipeline
*/
lunr.Pipeline.load = function (serialised) {
var pipeline = new lunr.Pipeline
serialised.forEach(function (fnName) {
var fn = lunr.Pipeline.registeredFunctions[fnName]
serialised.forEach(function (fnName) {
var fn = lunr.Pipeline.registeredFunctions[fnName]
if (fn) {
pipeline.add(fn)
} else {
throw new Error ('Cannot load un-registered function: ' + fnName)
}
})
return pipeline
}
if (fn) {
pipeline.add(fn)
} else {
throw new Error ('Cannot load un-registered function: ' + fnName)
}
})
/**
* Adds new functions to the end of the pipeline.
*
* Logs a warning if the function has not been registered.
*
* @param {Function} functions Any number of functions to add to the pipeline.
* @memberOf Pipeline
*/
lunr.Pipeline.prototype.add = function () {
var fns = Array.prototype.slice.call(arguments)
return pipeline
}
fns.forEach(function (fn) {
lunr.Pipeline.warnIfFunctionNotRegistered(fn)
this._stack.push(fn)
}, this)
}
/**
* Adds new functions to the end of the pipeline.
*
* Logs a warning if the function has not been registered.
*
* @param {Function} functions Any number of functions to add to the pipeline.
* @memberOf Pipeline
*/
lunr.Pipeline.prototype.add = function () {
var fns = Array.prototype.slice.call(arguments)
/**
* Adds a single function after a function that already exists in the
* pipeline.
*
* Logs a warning if the function has not been registered.
*
* @param {Function} existingFn A function that already exists in the pipeline.
* @param {Function} newFn The new function to add to the pipeline.
* @memberOf Pipeline
*/
lunr.Pipeline.prototype.after = function (existingFn, newFn) {
lunr.Pipeline.warnIfFunctionNotRegistered(newFn)
fns.forEach(function (fn) {
lunr.Pipeline.warnIfFunctionNotRegistered(fn)
this._stack.push(fn)
}, this)
}
var pos = this._stack.indexOf(existingFn) + 1
this._stack.splice(pos, 0, newFn)
}
/**
* Adds a single function after a function that already exists in the
* pipeline.
*
* Logs a warning if the function has not been registered.
*
* @param {Function} existingFn A function that already exists in the pipeline.
* @param {Function} newFn The new function to add to the pipeline.
* @memberOf Pipeline
*/
lunr.Pipeline.prototype.after = function (existingFn, newFn) {
lunr.Pipeline.warnIfFunctionNotRegistered(newFn)
/**
* Adds a single function before a function that already exists in the
* pipeline.
*
* Logs a warning if the function has not been registered.
*
* @param {Function} existingFn A function that already exists in the pipeline.
* @param {Function} newFn The new function to add to the pipeline.
* @memberOf Pipeline
*/
lunr.Pipeline.prototype.before = function (existingFn, newFn) {
lunr.Pipeline.warnIfFunctionNotRegistered(newFn)
var pos = this._stack.indexOf(existingFn) + 1
this._stack.splice(pos, 0, newFn)
}
var pos = this._stack.indexOf(existingFn)
this._stack.splice(pos, 0, newFn)
}
/**
* Adds a single function before a function that already exists in the
* pipeline.
*
* Logs a warning if the function has not been registered.
*
* @param {Function} existingFn A function that already exists in the pipeline.
* @param {Function} newFn The new function to add to the pipeline.
* @memberOf Pipeline
*/
lunr.Pipeline.prototype.before = function (existingFn, newFn) {
lunr.Pipeline.warnIfFunctionNotRegistered(newFn)
/**
* Removes a function from the pipeline.
*
* @param {Function} fn The function to remove from the pipeline.
* @memberOf Pipeline
*/
lunr.Pipeline.prototype.remove = function (fn) {
var pos = this._stack.indexOf(fn)
this._stack.splice(pos, 1)
}
var pos = this._stack.indexOf(existingFn)
this._stack.splice(pos, 0, newFn)
}
/**
* Runs the current list of functions that make up the pipeline against the
* passed tokens.
*
* @param {Array} tokens The tokens to run through the pipeline.
* @returns {Array}
* @memberOf Pipeline
*/
lunr.Pipeline.prototype.run = function (tokens) {
var out = [],
tokenLength = tokens.length,
stackLength = this._stack.length
/**
* Removes a function from the pipeline.
*
* @param {Function} fn The function to remove from the pipeline.
* @memberOf Pipeline
*/
lunr.Pipeline.prototype.remove = function (fn) {
var pos = this._stack.indexOf(fn)
this._stack.splice(pos, 1)
}
for (var i = 0; i < tokenLength; i++) {
var token = tokens[i]
/**
* Runs the current list of functions that make up the pipeline against the
* passed tokens.
*
* @param {Array} tokens The tokens to run through the pipeline.
* @returns {Array}
* @memberOf Pipeline
*/
lunr.Pipeline.prototype.run = function (tokens) {
var out = [],
tokenLength = tokens.length,
stackLength = this._stack.length
for (var j = 0; j < stackLength; j++) {
token = this._stack[j](token, i, tokens)
if (token === void 0) break
};
for (var i = 0; i < tokenLength; i++) {
var token = tokens[i]
if (token !== void 0) out.push(token)
};
for (var j = 0; j < stackLength; j++) {
token = this._stack[j](token, i, tokens)
if (token === void 0) break
};
return out
}
if (token !== void 0) out.push(token)
};
/**
* Resets the pipeline by removing any existing processors.
*
* @memberOf Pipeline
*/
lunr.Pipeline.prototype.reset = function () {
this._stack = []
}
return out
}
/**
* Returns a representation of the pipeline ready for serialisation.
*
* Logs a warning if the function has not been registered.
*
* @returns {Array}
* @memberOf Pipeline
*/
lunr.Pipeline.prototype.toJSON = function () {
return this._stack.map(function (fn) {
lunr.Pipeline.warnIfFunctionNotRegistered(fn)
return fn.label
})
}
/*!
* lunr.Vector
* Copyright (C) 2014 Oliver Nightingale
*/
/**
* Resets the pipeline by removing any existing processors.
*
* @memberOf Pipeline
*/
lunr.Pipeline.prototype.reset = function () {
this._stack = []
}
/**
* lunr.Vectors implement vector related operations for
* a series of elements.
*
* @constructor
*/
lunr.Vector = function () {
this._magnitude = null
this.list = undefined
this.length = 0
}
/**
* Returns a representation of the pipeline ready for serialisation.
*
* Logs a warning if the function has not been registered.
*
* @returns {Array}
* @memberOf Pipeline
*/
lunr.Pipeline.prototype.toJSON = function () {
return this._stack.map(function (fn) {
lunr.Pipeline.warnIfFunctionNotRegistered(fn)
/**
* lunr.Vector.Node is a simple struct for each node
* in a lunr.Vector.
*
* @private
* @param {Number} The index of the node in the vector.
* @param {Object} The data at this node in the vector.
* @param {lunr.Vector.Node} The node directly after this node in the vector.
* @constructor
* @memberOf Vector
*/
lunr.Vector.Node = function (idx, val, next) {
this.idx = idx
this.val = val
this.next = next
}
return fn.label
})
}
/*!
* lunr.Vector
* Copyright (C) 2014 Oliver Nightingale
*/
/**
* Inserts a new value at a position in a vector.
*
* @param {Number} The index at which to insert a value.
* @param {Object} The object to insert in the vector.
* @memberOf Vector.
*/
lunr.Vector.prototype.insert = function (idx, val) {
var list = this.list
/**
* lunr.Vectors implement vector related operations for
* a series of elements.
*
* @constructor
*/
lunr.Vector = function () {
this._magnitude = null
this.list = undefined
this.length = 0
}
if (!list) {
this.list = new lunr.Vector.Node (idx, val, list)
return this.length++
/**
* lunr.Vector.Node is a simple struct for each node
* in a lunr.Vector.
*
* @private
* @param {Number} The index of the node in the vector.
* @param {Object} The data at this node in the vector.
* @param {lunr.Vector.Node} The node directly after this node in the vector.
* @constructor
* @memberOf Vector
*/
lunr.Vector.Node = function (idx, val, next) {
this.idx = idx
this.val = val
this.next = next
}
var prev = list,
next = list.next
/**
* Inserts a new value at a position in a vector.
*
* @param {Number} The index at which to insert a value.
* @param {Object} The object to insert in the vector.
* @memberOf Vector.
*/
lunr.Vector.prototype.insert = function (idx, val) {
var list = this.list
while (next != undefined) {
if (idx < next.idx) {
prev.next = new lunr.Vector.Node (idx, val, next)
if (!list) {
this.list = new lunr.Vector.Node (idx, val, list)
return this.length++
}
prev = next, next = next.next
}
var prev = list,
next = list.next
prev.next = new lunr.Vector.Node (idx, val, next)
return this.length++
}
while (next != undefined) {
if (idx < next.idx) {
prev.next = new lunr.Vector.Node (idx, val, next)
return this.length++
}
/**
* Calculates the magnitude of this vector.
*
* @returns {Number}
* @memberOf Vector
*/
lunr.Vector.prototype.magnitude = function () {
if (this._magniture) return this._magnitude
var node = this.list,
sumOfSquares = 0,
val
prev = next, next = next.next
}
while (node) {
val = node.val
sumOfSquares += val * val
node = node.next
prev.next = new lunr.Vector.Node (idx, val, next)
return this.length++
}
return this._magnitude = Math.sqrt(sumOfSquares)
}
/**
* Calculates the magnitude of this vector.
*
* @returns {Number}
* @memberOf Vector
*/
lunr.Vector.prototype.magnitude = function () {
if (this._magniture) return this._magnitude
var node = this.list,
sumOfSquares = 0,
val
while (node) {
val = node.val
sumOfSquares += val * val
node = node.next
}
/**
* Calculates the dot product of this vector and another vector.
*
* @param {lunr.Vector} otherVector The vector to compute the dot product with.
* @returns {Number}
* @memberOf Vector
*/
lunr.Vector.prototype.dot = function (otherVector) {
var node = this.list,
otherNode = otherVector.list,
dotProduct = 0
return this._magnitude = Math.sqrt(sumOfSquares)
}
while (node && otherNode) {
if (node.idx < otherNode.idx) {
node = node.next
} else if (node.idx > otherNode.idx) {
otherNode = otherNode.next
} else {
dotProduct += node.val * otherNode.val
node = node.next
otherNode = otherNode.next
/**
* Calculates the dot product of this vector and another vector.
*
* @param {lunr.Vector} otherVector The vector to compute the dot product with.
* @returns {Number}
* @memberOf Vector
*/
lunr.Vector.prototype.dot = function (otherVector) {
var node = this.list,
otherNode = otherVector.list,
dotProduct = 0
while (node && otherNode) {
if (node.idx < otherNode.idx) {
node = node.next
} else if (node.idx > otherNode.idx) {
otherNode = otherNode.next
} else {
dotProduct += node.val * otherNode.val
node = node.next
otherNode = otherNode.next
}
}
return dotProduct
}
return dotProduct
}
/**
* Calculates the cosine similarity between this vector and another
* vector.
*
* @param {lunr.Vector} otherVector The other vector to calculate the
* similarity with.
* @returns {Number}
* @memberOf Vector
*/
lunr.Vector.prototype.similarity = function (otherVector) {
return this.dot(otherVector) / (this.magnitude() * otherVector.magnitude())
}
/*!
* lunr.SortedSet
* Copyright (C) 2014 Oliver Nightingale
*/
/**
* Calculates the cosine similarity between this vector and another
* vector.
*
* @param {lunr.Vector} otherVector The other vector to calculate the
* similarity with.
* @returns {Number}
* @memberOf Vector
*/
lunr.Vector.prototype.similarity = function (otherVector) {
return this.dot(otherVector) / (this.magnitude() * otherVector.magnitude())
}
/*!
* lunr.SortedSet
* Copyright (C) 2014 Oliver Nightingale
*/
/**
* lunr.SortedSets are used to maintain an array of uniq values in a sorted
* order.
*
* @constructor
*/
lunr.SortedSet = function () {
this.length = 0
this.elements = []
}
/**
* lunr.SortedSets are used to maintain an array of uniq values in a sorted
* order.
*
* @constructor
*/
lunr.SortedSet = function () {
this.length = 0
this.elements = []
}
/**
* Loads a previously serialised sorted set.
*
* @param {Array} serialisedData The serialised set to load.
* @returns {lunr.SortedSet}
* @memberOf SortedSet
*/
lunr.SortedSet.load = function (serialisedData) {
var set = new this
/**
* Loads a previously serialised sorted set.
*
* @param {Array} serialisedData The serialised set to load.
* @returns {lunr.SortedSet}
* @memberOf SortedSet
*/
lunr.SortedSet.load = function (serialisedData) {
var set = new this
set.elements = serialisedData
set.length = serialisedData.length
set.elements = serialisedData
set.length = serialisedData.length
return set
}
return set
}
/**
* Inserts new items into the set in the correct position to maintain the
* order.
*
* @param {Object} The objects to add to this set.
* @memberOf SortedSet
*/
lunr.SortedSet.prototype.add = function () {
Array.prototype.slice.call(arguments).forEach(function (element) {
if (~this.indexOf(element)) return
this.elements.splice(this.locationFor(element), 0, element)
}, this)
/**
* Inserts new items into the set in the correct position to maintain the
* order.
*
* @param {Object} The objects to add to this set.
* @memberOf SortedSet
*/
lunr.SortedSet.prototype.add = function () {
Array.prototype.slice.call(arguments).forEach(function (element) {
if (~this.indexOf(element)) return
this.elements.splice(this.locationFor(element), 0, element)
}, this)
this.length = this.elements.length
}
this.length = this.elements.length
}
/**
* Converts this sorted set into an array.
*
* @returns {Array}
* @memberOf SortedSet
*/
lunr.SortedSet.prototype.toArray = function () {
return this.elements.slice()
}
/**
* Converts this sorted set into an array.
*
* @returns {Array}
* @memberOf SortedSet
*/
lunr.SortedSet.prototype.toArray = function () {
return this.elements.slice()
}
/**
* Creates a new array with the results of calling a provided function on every
* element in this sorted set.
*
* Delegates to Array.prototype.map and has the same signature.
*
* @param {Function} fn The function that is called on each element of the
* set.
* @param {Object} ctx An optional object that can be used as the context
* for the function fn.
* @returns {Array}
* @memberOf SortedSet
*/
lunr.SortedSet.prototype.map = function (fn, ctx) {
return this.elements.map(fn, ctx)
}
/**
* Creates a new array with the results of calling a provided function on every
* element in this sorted set.
*
* Delegates to Array.prototype.map and has the same signature.
*
* @param {Function} fn The function that is called on each element of the
* set.
* @param {Object} ctx An optional object that can be used as the context
* for the function fn.
* @returns {Array}
* @memberOf SortedSet
*/
lunr.SortedSet.prototype.map = function (fn, ctx) {
return this.elements.map(fn, ctx)
}
/**
* Executes a provided function once per sorted set element.
*
* Delegates to Array.prototype.forEach and has the same signature.
*
* @param {Function} fn The function that is called on each element of the
* set.
* @param {Object} ctx An optional object that can be used as the context
* @memberOf SortedSet
* for the function fn.
*/
lunr.SortedSet.prototype.forEach = function (fn, ctx) {
return this.elements.forEach(fn, ctx)
}
/**
* Executes a provided function once per sorted set element.
*
* Delegates to Array.prototype.forEach and has the same signature.
*
* @param {Function} fn The function that is called on each element of the
* set.
* @param {Object} ctx An optional object that can be used as the context
* @memberOf SortedSet
* for the function fn.
*/
lunr.SortedSet.prototype.forEach = function (fn, ctx) {
return this.elements.forEach(fn, ctx)
}
/**
* Returns the index at which a given element can be found in the
* sorted set, or -1 if it is not present.
*
* @param {Object} elem The object to locate in the sorted set.
* @param {Number} start An optional index at which to start searching from
* within the set.
* @param {Number} end An optional index at which to stop search from within
* the set.
* @returns {Number}
* @memberOf SortedSet
*/
lunr.SortedSet.prototype.indexOf = function (elem, start, end) {
var start = start || 0,
end = end || this.elements.length,
sectionLength = end - start,
pivot = start + Math.floor(sectionLength / 2),
pivotElem = this.elements[pivot]
if (sectionLength <= 1) {
if (pivotElem === elem) {
return pivot
} else {
return -1
}
}
/**
* Returns the index at which a given element can be found in the
* sorted set, or -1 if it is not present.
*
* @param {Object} elem The object to locate in the sorted set.
* @param {Number} start An optional index at which to start searching from
* within the set.
* @param {Number} end An optional index at which to stop search from within
* the set.
* @returns {Number}
* @memberOf SortedSet
*/
lunr.SortedSet.prototype.indexOf = function (elem, start, end) {
var start = start || 0,
end = end || this.elements.length,
sectionLength = end - start,
pivot = start + Math.floor(sectionLength / 2),
pivotElem = this.elements[pivot]
if (sectionLength <= 1) {
if (pivotElem === elem) {
return pivot
} else {
return -1
if (pivotElem < elem) return this.indexOf(elem, pivot, end)
if (pivotElem > elem) return this.indexOf(elem, start, pivot)
if (pivotElem === elem) return pivot
}
/**
* Returns the position within the sorted set that an element should be
* inserted at to maintain the current order of the set.
*
* This function assumes that the element to search for does not already exist
* in the sorted set.
*
* @param {Object} elem The elem to find the position for in the set
* @param {Number} start An optional index at which to start searching from
* within the set.
* @param {Number} end An optional index at which to stop search from within
* the set.
* @returns {Number}
* @memberOf SortedSet
*/
lunr.SortedSet.prototype.locationFor = function (elem, start, end) {
var start = start || 0,
end = end || this.elements.length,
sectionLength = end - start,
pivot = start + Math.floor(sectionLength / 2),
pivotElem = this.elements[pivot]
if (sectionLength <= 1) {
if (pivotElem > elem) return pivot
if (pivotElem < elem) return pivot + 1
}
if (pivotElem < elem) return this.locationFor(elem, pivot, end)
if (pivotElem > elem) return this.locationFor(elem, start, pivot)
}
if (pivotElem < elem) return this.indexOf(elem, pivot, end)
if (pivotElem > elem) return this.indexOf(elem, start, pivot)
if (pivotElem === elem) return pivot
}
/**
* Creates a new lunr.SortedSet that contains the elements in the intersection
* of this set and the passed set.
*
* @param {lunr.SortedSet} otherSet The set to intersect with this set.
* @returns {lunr.SortedSet}
* @memberOf SortedSet
*/
lunr.SortedSet.prototype.intersect = function (otherSet) {
var intersectSet = new lunr.SortedSet,
i = 0, j = 0,
a_len = this.length, b_len = otherSet.length,
a = this.elements, b = otherSet.elements
while (true) {
if (i > a_len - 1 || j > b_len - 1) break
if (a[i] === b[j]) {
intersectSet.add(a[i])
i++, j++
continue
}
/**
* Returns the position within the sorted set that an element should be
* inserted at to maintain the current order of the set.
*
* This function assumes that the element to search for does not already exist
* in the sorted set.
*
* @param {Object} elem The elem to find the position for in the set
* @param {Number} start An optional index at which to start searching from
* within the set.
* @param {Number} end An optional index at which to stop search from within
* the set.
* @returns {Number}
* @memberOf SortedSet
*/
lunr.SortedSet.prototype.locationFor = function (elem, start, end) {
var start = start || 0,
end = end || this.elements.length,
sectionLength = end - start,
pivot = start + Math.floor(sectionLength / 2),
pivotElem = this.elements[pivot]
if (a[i] < b[j]) {
i++
continue
}
if (sectionLength <= 1) {
if (pivotElem > elem) return pivot
if (pivotElem < elem) return pivot + 1
if (a[i] > b[j]) {
j++
continue
}
};
return intersectSet
}
if (pivotElem < elem) return this.locationFor(elem, pivot, end)
if (pivotElem > elem) return this.locationFor(elem, start, pivot)
}
/**
* Makes a copy of this set
*
* @returns {lunr.SortedSet}
* @memberOf SortedSet
*/
lunr.SortedSet.prototype.clone = function () {
var clone = new lunr.SortedSet
/**
* Creates a new lunr.SortedSet that contains the elements in the intersection
* of this set and the passed set.
*
* @param {lunr.SortedSet} otherSet The set to intersect with this set.
* @returns {lunr.SortedSet}
* @memberOf SortedSet
*/
lunr.SortedSet.prototype.intersect = function (otherSet) {
var intersectSet = new lunr.SortedSet,
i = 0, j = 0,
a_len = this.length, b_len = otherSet.length,
a = this.elements, b = otherSet.elements
while (true) {
if (i > a_len - 1 || j > b_len - 1) break
if (a[i] === b[j]) {
intersectSet.add(a[i])
i++, j++
continue
}
clone.elements = this.toArray()
clone.length = clone.elements.length
if (a[i] < b[j]) {
i++
continue
}
return clone
}
if (a[i] > b[j]) {
j++
continue
/**
* Creates a new lunr.SortedSet that contains the elements in the union
* of this set and the passed set.
*
* @param {lunr.SortedSet} otherSet The set to union with this set.
* @returns {lunr.SortedSet}
* @memberOf SortedSet
*/
lunr.SortedSet.prototype.union = function (otherSet) {
var longSet, shortSet, unionSet
if (this.length >= otherSet.length) {
longSet = this, shortSet = otherSet
} else {
longSet = otherSet, shortSet = this
}
};
return intersectSet
}
unionSet = longSet.clone()
/**
* Makes a copy of this set
*
* @returns {lunr.SortedSet}
* @memberOf SortedSet
*/
lunr.SortedSet.prototype.clone = function () {
var clone = new lunr.SortedSet
unionSet.add.apply(unionSet, shortSet.toArray())
clone.elements = this.toArray()
clone.length = clone.elements.length
return unionSet
}
return clone
}
/**
* Returns a representation of the sorted set ready for serialisation.
*
* @returns {Array}
* @memberOf SortedSet
*/
lunr.SortedSet.prototype.toJSON = function () {
return this.toArray()
}
/*!
* lunr.Index
* Copyright (C) 2014 Oliver Nightingale
*/
/**
* Creates a new lunr.SortedSet that contains the elements in the union
* of this set and the passed set.
*
* @param {lunr.SortedSet} otherSet The set to union with this set.
* @returns {lunr.SortedSet}
* @memberOf SortedSet
*/
lunr.SortedSet.prototype.union = function (otherSet) {
var longSet, shortSet, unionSet
/**
* lunr.Index is object that manages a search index. It contains the indexes
* and stores all the tokens and document lookups. It also provides the main
* user facing API for the library.
*
* @constructor
*/
lunr.Index = function () {
this._fields = []
this._ref = 'id'
this.pipeline = new lunr.Pipeline
this.documentStore = new lunr.Store
this.tokenStore = new lunr.TokenStore
this.corpusTokens = new lunr.SortedSet
this.eventEmitter = new lunr.EventEmitter
if (this.length >= otherSet.length) {
longSet = this, shortSet = otherSet
} else {
longSet = otherSet, shortSet = this
}
this._idfCache = {}
unionSet = longSet.clone()
this.on('add', 'remove', 'update', (function () {
this._idfCache = {}
}).bind(this))
}
unionSet.add.apply(unionSet, shortSet.toArray())
/**
* Bind a handler to events being emitted by the index.
*
* The handler can be bound to many events at the same time.
*
* @param {String} [eventName] The name(s) of events to bind the function to.
* @param {Function} handler The serialised set to load.
* @memberOf Index
*/
lunr.Index.prototype.on = function () {
var args = Array.prototype.slice.call(arguments)
return this.eventEmitter.addListener.apply(this.eventEmitter, args)
}
return unionSet
}
/**
* Removes a handler from an event being emitted by the index.
*
* @param {String} eventName The name of events to remove the function from.
* @param {Function} handler The serialised set to load.
* @memberOf Index
*/
lunr.Index.prototype.off = function (name, fn) {
return this.eventEmitter.removeListener(name, fn)
}
/**
* Returns a representation of the sorted set ready for serialisation.
*
* @returns {Array}
* @memberOf SortedSet
*/
lunr.SortedSet.prototype.toJSON = function () {
return this.toArray()
}
/*!
* lunr.Index
* Copyright (C) 2014 Oliver Nightingale
*/
/**
* Loads a previously serialised index.
*
* Issues a warning if the index being imported was serialised
* by a different version of lunr.
*
* @param {Object} serialisedData The serialised set to load.
* @returns {lunr.Index}
* @memberOf Index
*/
lunr.Index.load = function (serialisedData) {
if (serialisedData.version !== lunr.version) {
lunr.utils.warn('version mismatch: current ' + lunr.version + ' importing ' + serialisedData.version)
}
/**
* lunr.Index is object that manages a search index. It contains the indexes
* and stores all the tokens and document lookups. It also provides the main
* user facing API for the library.
*
* @constructor
*/
lunr.Index = function () {
this._fields = []
this._ref = 'id'
this.pipeline = new lunr.Pipeline
this.documentStore = new lunr.Store
this.tokenStore = new lunr.TokenStore
this.corpusTokens = new lunr.SortedSet
this.eventEmitter = new lunr.EventEmitter
this._idfCache = {}
this.on('add', 'remove', 'update', (function () {
this._idfCache = {}
}).bind(this))
}
var idx = new this
/**
* Bind a handler to events being emitted by the index.
*
* The handler can be bound to many events at the same time.
*
* @param {String} [eventName] The name(s) of events to bind the function to.
* @param {Function} handler The serialised set to load.
* @memberOf Index
*/
lunr.Index.prototype.on = function () {
var args = Array.prototype.slice.call(arguments)
return this.eventEmitter.addListener.apply(this.eventEmitter, args)
}
idx._fields = serialisedData.fields
idx._ref = serialisedData.ref
/**
* Removes a handler from an event being emitted by the index.
*
* @param {String} eventName The name of events to remove the function from.
* @param {Function} handler The serialised set to load.
* @memberOf Index
*/
lunr.Index.prototype.off = function (name, fn) {
return this.eventEmitter.removeListener(name, fn)
}
idx.documentStore = lunr.Store.load(serialisedData.documentStore)
idx.tokenStore = lunr.TokenStore.load(serialisedData.tokenStore)
idx.corpusTokens = lunr.SortedSet.load(serialisedData.corpusTokens)
idx.pipeline = lunr.Pipeline.load(serialisedData.pipeline)
/**
* Loads a previously serialised index.
*
* Issues a warning if the index being imported was serialised
* by a different version of lunr.
*
* @param {Object} serialisedData The serialised set to load.
* @returns {lunr.Index}
* @memberOf Index
*/
lunr.Index.load = function (serialisedData) {
if (serialisedData.version !== lunr.version) {
lunr.utils.warn('version mismatch: current ' + lunr.version + ' importing ' + serialisedData.version)
return idx
}
var idx = new this
idx._fields = serialisedData.fields
idx._ref = serialisedData.ref
/**
* Adds a field to the list of fields that will be searchable within documents
* in the index.
*
* An optional boost param can be passed to affect how much tokens in this field
* rank in search results, by default the boost value is 1.
*
* Fields should be added before any documents are added to the index, fields
* that are added after documents are added to the index will only apply to new
* documents added to the index.
*
* @param {String} fieldName The name of the field within the document that
* should be indexed
* @param {Number} boost An optional boost that can be applied to terms in this
* field.
* @returns {lunr.Index}
* @memberOf Index
*/
lunr.Index.prototype.field = function (fieldName, opts) {
var opts = opts || {},
field = { name: fieldName, boost: opts.boost || 1 }
idx.documentStore = lunr.Store.load(serialisedData.documentStore)
idx.tokenStore = lunr.TokenStore.load(serialisedData.tokenStore)
idx.corpusTokens = lunr.SortedSet.load(serialisedData.corpusTokens)
idx.pipeline = lunr.Pipeline.load(serialisedData.pipeline)
this._fields.push(field)
return this
}
return idx
}
/**
* Sets the property used to uniquely identify documents added to the index,
* by default this property is 'id'.
*
* This should only be changed before adding documents to the index, changing
* the ref property without resetting the index can lead to unexpected results.
*
* @param {String} refName The property to use to uniquely identify the
* documents in the index.
* @param {Boolean} emitEvent Whether to emit add events, defaults to true
* @returns {lunr.Index}
* @memberOf Index
*/
lunr.Index.prototype.ref = function (refName) {
this._ref = refName
return this
}
/**
* Adds a field to the list of fields that will be searchable within documents
* in the index.
*
* An optional boost param can be passed to affect how much tokens in this field
* rank in search results, by default the boost value is 1.
*
* Fields should be added before any documents are added to the index, fields
* that are added after documents are added to the index will only apply to new
* documents added to the index.
*
* @param {String} fieldName The name of the field within the document that
* should be indexed
* @param {Number} boost An optional boost that can be applied to terms in this
* field.
* @returns {lunr.Index}
* @memberOf Index
*/
lunr.Index.prototype.field = function (fieldName, opts) {
var opts = opts || {},
field = { name: fieldName, boost: opts.boost || 1 }
/**
* Add a document to the index.
*
* This is the way new documents enter the index, this function will run the
* fields from the document through the index's pipeline and then add it to
* the index, it will then show up in search results.
*
* An 'add' event is emitted with the document that has been added and the index
* the document has been added to. This event can be silenced by passing false
* as the second argument to add.
*
* @param {Object} doc The document to add to the index.
* @param {Boolean} emitEvent Whether or not to emit events, default true.
* @memberOf Index
*/
lunr.Index.prototype.add = function (doc, emitEvent) {
var docTokens = {},
allDocumentTokens = new lunr.SortedSet,
docRef = doc[this._ref],
emitEvent = emitEvent === undefined ? true : emitEvent
this._fields.push(field)
return this
}
this._fields.forEach(function (field) {
var fieldTokens = this.pipeline.run(lunr.tokenizer(doc[field.name]))
/**
* Sets the property used to uniquely identify documents added to the index,
* by default this property is 'id'.
*
* This should only be changed before adding documents to the index, changing
* the ref property without resetting the index can lead to unexpected results.
*
* @param {String} refName The property to use to uniquely identify the
* documents in the index.
* @param {Boolean} emitEvent Whether to emit add events, defaults to true
* @returns {lunr.Index}
* @memberOf Index
*/
lunr.Index.prototype.ref = function (refName) {
this._ref = refName
return this
}
docTokens[field.name] = fieldTokens
lunr.SortedSet.prototype.add.apply(allDocumentTokens, fieldTokens)
}, this)
/**
* Add a document to the index.
*
* This is the way new documents enter the index, this function will run the
* fields from the document through the index's pipeline and then add it to
* the index, it will then show up in search results.
*
* An 'add' event is emitted with the document that has been added and the index
* the document has been added to. This event can be silenced by passing false
* as the second argument to add.
*
* @param {Object} doc The document to add to the index.
* @param {Boolean} emitEvent Whether or not to emit events, default true.
* @memberOf Index
*/
lunr.Index.prototype.add = function (doc, emitEvent) {
var docTokens = {},
allDocumentTokens = new lunr.SortedSet,
docRef = doc[this._ref],
emitEvent = emitEvent === undefined ? true : emitEvent
this.documentStore.set(docRef, allDocumentTokens)
lunr.SortedSet.prototype.add.apply(this.corpusTokens, allDocumentTokens.toArray())
this._fields.forEach(function (field) {
var fieldTokens = this.pipeline.run(lunr.tokenizer(doc[field.name]))
for (var i = 0; i < allDocumentTokens.length; i++) {
var token = allDocumentTokens.elements[i]
var tf = this._fields.reduce(function (memo, field) {
var fieldLength = docTokens[field.name].length
docTokens[field.name] = fieldTokens
lunr.SortedSet.prototype.add.apply(allDocumentTokens, fieldTokens)
}, this)
if (!fieldLength) return memo
this.documentStore.set(docRef, allDocumentTokens)
lunr.SortedSet.prototype.add.apply(this.corpusTokens, allDocumentTokens.toArray())
var tokenCount = docTokens[field.name].filter(function (t) { return t === token }).length
for (var i = 0; i < allDocumentTokens.length; i++) {
var token = allDocumentTokens.elements[i]
var tf = this._fields.reduce(function (memo, field) {
var fieldLength = docTokens[field.name].length
return memo + (tokenCount / fieldLength * field.boost)
}, 0)
if (!fieldLength) return memo
this.tokenStore.add(token, { ref: docRef, tf: tf })
};
var tokenCount = docTokens[field.name].filter(function (t) { return t === token }).length
if (emitEvent) this.eventEmitter.emit('add', doc, this)
}
return memo + (tokenCount / fieldLength * field.boost)
}, 0)
/**
* Removes a document from the index.
*
* To make sure documents no longer show up in search results they can be
* removed from the index using this method.
*
* The document passed only needs to have the same ref property value as the
* document that was added to the index, they could be completely different
* objects.
*
* A 'remove' event is emitted with the document that has been removed and the index
* the document has been removed from. This event can be silenced by passing false
* as the second argument to remove.
*
* @param {Object} doc The document to remove from the index.
* @param {Boolean} emitEvent Whether to emit remove events, defaults to true
* @memberOf Index
*/
lunr.Index.prototype.remove = function (doc, emitEvent) {
var docRef = doc[this._ref],
emitEvent = emitEvent === undefined ? true : emitEvent
this.tokenStore.add(token, { ref: docRef, tf: tf })
};
if (!this.documentStore.has(docRef)) return
if (emitEvent) this.eventEmitter.emit('add', doc, this)
}
var docTokens = this.documentStore.get(docRef)
/**
* Removes a document from the index.
*
* To make sure documents no longer show up in search results they can be
* removed from the index using this method.
*
* The document passed only needs to have the same ref property value as the
* document that was added to the index, they could be completely different
* objects.
*
* A 'remove' event is emitted with the document that has been removed and the index
* the document has been removed from. This event can be silenced by passing false
* as the second argument to remove.
*
* @param {Object} doc The document to remove from the index.
* @param {Boolean} emitEvent Whether to emit remove events, defaults to true
* @memberOf Index
*/
lunr.Index.prototype.remove = function (doc, emitEvent) {
var docRef = doc[this._ref],
emitEvent = emitEvent === undefined ? true : emitEvent
this.documentStore.remove(docRef)
if (!this.documentStore.has(docRef)) return
docTokens.forEach(function (token) {
this.tokenStore.remove(token, docRef)
}, this)
var docTokens = this.documentStore.get(docRef)
if (emitEvent) this.eventEmitter.emit('remove', doc, this)
}
this.documentStore.remove(docRef)
/**
* Updates a document in the index.
*
* When a document contained within the index gets updated, fields changed,
* added or removed, to make sure it correctly matched against search queries,
* it should be updated in the index.
*
* This method is just a wrapper around `remove` and `add`
*
* An 'update' event is emitted with the document that has been updated and the index.
* This event can be silenced by passing false as the second argument to update. Only
* an update event will be fired, the 'add' and 'remove' events of the underlying calls
* are silenced.
*
* @param {Object} doc The document to update in the index.
* @param {Boolean} emitEvent Whether to emit update events, defaults to true
* @see Index.prototype.remove
* @see Index.prototype.add
* @memberOf Index
*/
lunr.Index.prototype.update = function (doc, emitEvent) {
var emitEvent = emitEvent === undefined ? true : emitEvent
docTokens.forEach(function (token) {
this.tokenStore.remove(token, docRef)
}, this)
this.remove(doc, false)
this.add(doc, false)
if (emitEvent) this.eventEmitter.emit('remove', doc, this)
}
if (emitEvent) this.eventEmitter.emit('update', doc, this)
}
/**
* Updates a document in the index.
*
* When a document contained within the index gets updated, fields changed,
* added or removed, to make sure it correctly matched against search queries,
* it should be updated in the index.
*
* This method is just a wrapper around `remove` and `add`
*
* An 'update' event is emitted with the document that has been updated and the index.
* This event can be silenced by passing false as the second argument to update. Only
* an update event will be fired, the 'add' and 'remove' events of the underlying calls
* are silenced.
*
* @param {Object} doc The document to update in the index.
* @param {Boolean} emitEvent Whether to emit update events, defaults to true
* @see Index.prototype.remove
* @see Index.prototype.add
* @memberOf Index
*/
lunr.Index.prototype.update = function (doc, emitEvent) {
var emitEvent = emitEvent === undefined ? true : emitEvent
/**
* Calculates the inverse document frequency for a token within the index.
*
* @param {String} token The token to calculate the idf of.
* @see Index.prototype.idf
* @private
* @memberOf Index
*/
lunr.Index.prototype.idf = function (term) {
var cacheKey = "@" + term
if (Object.prototype.hasOwnProperty.call(this._idfCache, cacheKey)) return this._idfCache[cacheKey]
this.remove(doc, false)
this.add(doc, false)
var documentFrequency = this.tokenStore.count(term),
idf = 1
if (emitEvent) this.eventEmitter.emit('update', doc, this)
}
if (documentFrequency > 0) {
idf = 1 + Math.log(this.tokenStore.length / documentFrequency)
}
/**
* Calculates the inverse document frequency for a token within the index.
*
* @param {String} token The token to calculate the idf of.
* @see Index.prototype.idf
* @private
* @memberOf Index
*/
lunr.Index.prototype.idf = function (term) {
var cacheKey = "@" + term
if (Object.prototype.hasOwnProperty.call(this._idfCache, cacheKey)) return this._idfCache[cacheKey]
return this._idfCache[cacheKey] = idf
}
var documentFrequency = this.tokenStore.count(term),
idf = 1
/**
* Searches the index using the passed query.
*
* Queries should be a string, multiple words are allowed and will lead to an
* AND based query, e.g. `idx.search('foo bar')` will run a search for
* documents containing both 'foo' and 'bar'.
*
* All query tokens are passed through the same pipeline that document tokens
* are passed through, so any language processing involved will be run on every
* query term.
*
* Each query term is expanded, so that the term 'he' might be expanded to
* 'hello' and 'help' if those terms were already included in the index.
*
* Matching documents are returned as an array of objects, each object contains
* the matching document ref, as set for this index, and the similarity score
* for this document against the query.
*
* @param {String} query The query to search the index with.
* @returns {Object}
* @see Index.prototype.idf
* @see Index.prototype.documentVector
* @memberOf Index
*/
lunr.Index.prototype.search = function (query) {
var queryTokens = this.pipeline.run(lunr.tokenizer(query)),
queryVector = new lunr.Vector,
documentSets = [],
fieldBoosts = this._fields.reduce(function (memo, f) { return memo + f.boost }, 0)
var hasSomeToken = queryTokens.some(function (token) {
return this.tokenStore.has(token)
}, this)
if (documentFrequency > 0) {
idf = 1 + Math.log(this.tokenStore.length / documentFrequency)
}
if (!hasSomeToken) return []
return this._idfCache[cacheKey] = idf
}
queryTokens
.forEach(function (token, i, tokens) {
var tf = 1 / tokens.length * this._fields.length * fieldBoosts,
self = this
/**
* Searches the index using the passed query.
*
* Queries should be a string, multiple words are allowed and will lead to an
* AND based query, e.g. `idx.search('foo bar')` will run a search for
* documents containing both 'foo' and 'bar'.
*
* All query tokens are passed through the same pipeline that document tokens
* are passed through, so any language processing involved will be run on every
* query term.
*
* Each query term is expanded, so that the term 'he' might be expanded to
* 'hello' and 'help' if those terms were already included in the index.
*
* Matching documents are returned as an array of objects, each object contains
* the matching document ref, as set for this index, and the similarity score
* for this document against the query.
*
* @param {String} query The query to search the index with.
* @returns {Object}
* @see Index.prototype.idf
* @see Index.prototype.documentVector
* @memberOf Index
*/
lunr.Index.prototype.search = function (query) {
var queryTokens = this.pipeline.run(lunr.tokenizer(query)),
queryVector = new lunr.Vector,
documentSets = [],
fieldBoosts = this._fields.reduce(function (memo, f) { return memo + f.boost }, 0)
var hasSomeToken = queryTokens.some(function (token) {
return this.tokenStore.has(token)
}, this)
if (!hasSomeToken) return []
queryTokens
.forEach(function (token, i, tokens) {
var tf = 1 / tokens.length * this._fields.length * fieldBoosts,
self = this
var set = this.tokenStore.expand(token).reduce(function (memo, key) {
var pos = self.corpusTokens.indexOf(key),
idf = self.idf(key),
similarityBoost = 1,
set = new lunr.SortedSet
// if the expanded key is not an exact match to the token then
// penalise the score for this key by how different the key is
// to the token.
if (key !== token) {
var diff = Math.max(3, key.length - token.length)
similarityBoost = 1 / Math.log(diff)
}
var set = this.tokenStore.expand(token).reduce(function (memo, key) {
var pos = self.corpusTokens.indexOf(key),
idf = self.idf(key),
similarityBoost = 1,
set = new lunr.SortedSet
// calculate the query tf-idf score for this token
// applying an similarityBoost to ensure exact matches
// these rank higher than expanded terms
if (pos > -1) queryVector.insert(pos, tf * idf * similarityBoost)
// if the expanded key is not an exact match to the token then
// penalise the score for this key by how different the key is
// to the token.
if (key !== token) {
var diff = Math.max(3, key.length - token.length)
similarityBoost = 1 / Math.log(diff)
}
// add all the documents that have this key into a set
Object.keys(self.tokenStore.get(key)).forEach(function (ref) { set.add(ref) })
// calculate the query tf-idf score for this token
// applying an similarityBoost to ensure exact matches
// these rank higher than expanded terms
if (pos > -1) queryVector.insert(pos, tf * idf * similarityBoost)
return memo.union(set)
}, new lunr.SortedSet)
// add all the documents that have this key into a set
Object.keys(self.tokenStore.get(key)).forEach(function (ref) { set.add(ref) })
documentSets.push(set)
}, this)
return memo.union(set)
}, new lunr.SortedSet)
var documentSet = documentSets.reduce(function (memo, set) {
return memo.intersect(set)
})
documentSets.push(set)
}, this)
return documentSet
.map(function (ref) {
return { ref: ref, score: queryVector.similarity(this.documentVector(ref)) }
}, this)
.sort(function (a, b) {
return b.score - a.score
var documentSet = documentSets.reduce(function (memo, set) {
return memo.intersect(set)
})
}
/**
* Generates a vector containing all the tokens in the document matching the
* passed documentRef.
*
* The vector contains the tf-idf score for each token contained in the
* document with the passed documentRef. The vector will contain an element
* for every token in the indexes corpus, if the document does not contain that
* token the element will be 0.
*
* @param {Object} documentRef The ref to find the document with.
* @returns {lunr.Vector}
* @private
* @memberOf Index
*/
lunr.Index.prototype.documentVector = function (documentRef) {
var documentTokens = this.documentStore.get(documentRef),
documentTokensLength = documentTokens.length,
documentVector = new lunr.Vector
return documentSet
.map(function (ref) {
return { ref: ref, score: queryVector.similarity(this.documentVector(ref)) }
}, this)
.sort(function (a, b) {
return b.score - a.score
})
}
for (var i = 0; i < documentTokensLength; i++) {
var token = documentTokens.elements[i],
tf = this.tokenStore.get(token)[documentRef].tf,
idf = this.idf(token)
/**
* Generates a vector containing all the tokens in the document matching the
* passed documentRef.
*
* The vector contains the tf-idf score for each token contained in the
* document with the passed documentRef. The vector will contain an element
* for every token in the indexes corpus, if the document does not contain that
* token the element will be 0.
*
* @param {Object} documentRef The ref to find the document with.
* @returns {lunr.Vector}
* @private
* @memberOf Index
*/
lunr.Index.prototype.documentVector = function (documentRef) {
var documentTokens = this.documentStore.get(documentRef),
documentTokensLength = documentTokens.length,
documentVector = new lunr.Vector
documentVector.insert(this.corpusTokens.indexOf(token), tf * idf)
};
for (var i = 0; i < documentTokensLength; i++) {
var token = documentTokens.elements[i],
tf = this.tokenStore.get(token)[documentRef].tf,
idf = this.idf(token)
return documentVector
}
documentVector.insert(this.corpusTokens.indexOf(token), tf * idf)
};
/**
* Returns a representation of the index ready for serialisation.
*
* @returns {Object}
* @memberOf Index
*/
lunr.Index.prototype.toJSON = function () {
return {
version: lunr.version,
fields: this._fields,
ref: this._ref,
documentStore: this.documentStore.toJSON(),
tokenStore: this.tokenStore.toJSON(),
corpusTokens: this.corpusTokens.toJSON(),
pipeline: this.pipeline.toJSON()
}
}
return documentVector
}
/**
* Applies a plugin to the current index.
*
* A plugin is a function that is called with the index as its context.
* Plugins can be used to customise or extend the behaviour the index
* in some way. A plugin is just a function, that encapsulated the custom
* behaviour that should be applied to the index.
*
* The plugin function will be called with the index as its argument, additional
* arguments can also be passed when calling use. The function will be called
* with the index as its context.
*
* Example:
*
* var myPlugin = function (idx, arg1, arg2) {
/**
* Returns a representation of the index ready for serialisation.
*
* @returns {Object}
* @memberOf Index
*/
lunr.Index.prototype.toJSON = function () {
return {
version: lunr.version,
fields: this._fields,
ref: this._ref,
documentStore: this.documentStore.toJSON(),
tokenStore: this.tokenStore.toJSON(),
corpusTokens: this.corpusTokens.toJSON(),
pipeline: this.pipeline.toJSON()
}
}
/**
* Applies a plugin to the current index.
*
* A plugin is a function that is called with the index as its context.
* Plugins can be used to customise or extend the behaviour the index
* in some way. A plugin is just a function, that encapsulated the custom
* behaviour that should be applied to the index.
*
* The plugin function will be called with the index as its argument, additional
* arguments can also be passed when calling use. The function will be called
* with the index as its context.
*
* Example:
*
* var myPlugin = function (idx, arg1, arg2) {
* // `this` is the index to be extended
* // apply any extensions etc here.
* }
*
* var idx = lunr(function () {
*
* var idx = lunr(function () {
* this.use(myPlugin, 'arg1', 'arg2')
* })
*
* @param {Function} plugin The plugin to apply.
* @memberOf Index
*/
lunr.Index.prototype.use = function (plugin) {
var args = Array.prototype.slice.call(arguments, 1)
args.unshift(this)
plugin.apply(this, args)
}
/*!
* lunr.Store
* Copyright (C) 2014 Oliver Nightingale
*/
*
* @param {Function} plugin The plugin to apply.
* @memberOf Index
*/
lunr.Index.prototype.use = function (plugin) {
var args = Array.prototype.slice.call(arguments, 1)
args.unshift(this)
plugin.apply(this, args)
}
/*!
* lunr.Store
* Copyright (C) 2014 Oliver Nightingale
*/
/**
* lunr.Store is a simple key-value store used for storing sets of tokens for
* documents stored in index.
*
* @constructor
* @module
*/
lunr.Store = function () {
this.store = {}
this.length = 0
}
/**
* lunr.Store is a simple key-value store used for storing sets of tokens for
* documents stored in index.
*
* @constructor
* @module
*/
lunr.Store = function () {
this.store = {}
this.length = 0
}
/**
* Loads a previously serialised store
*
* @param {Object} serialisedData The serialised store to load.
* @returns {lunr.Store}
* @memberOf Store
*/
lunr.Store.load = function (serialisedData) {
var store = new this
/**
* Loads a previously serialised store
*
* @param {Object} serialisedData The serialised store to load.
* @returns {lunr.Store}
* @memberOf Store
*/
lunr.Store.load = function (serialisedData) {
var store = new this
store.length = serialisedData.length
store.store = Object.keys(serialisedData.store).reduce(function (memo, key) {
memo[key] = lunr.SortedSet.load(serialisedData.store[key])
return memo
}, {})
store.length = serialisedData.length
store.store = Object.keys(serialisedData.store).reduce(function (memo, key) {
memo[key] = lunr.SortedSet.load(serialisedData.store[key])
return memo
}, {})
return store
}
return store
}
/**
* Stores the given tokens in the store against the given id.
*
* @param {Object} id The key used to store the tokens against.
* @param {Object} tokens The tokens to store against the key.
* @memberOf Store
*/
lunr.Store.prototype.set = function (id, tokens) {
this.store[id] = tokens
this.length = Object.keys(this.store).length
}
/**
* Stores the given tokens in the store against the given id.
*
* @param {Object} id The key used to store the tokens against.
* @param {Object} tokens The tokens to store against the key.
* @memberOf Store
*/
lunr.Store.prototype.set = function (id, tokens) {
if (!this.has(id)) this.length++
this.store[id] = tokens
}
/**
* Retrieves the tokens from the store for a given key.
*
* @param {Object} id The key to lookup and retrieve from the store.
* @returns {Object}
* @memberOf Store
*/
lunr.Store.prototype.get = function (id) {
return this.store[id]
}
/**
* Retrieves the tokens from the store for a given key.
*
* @param {Object} id The key to lookup and retrieve from the store.
* @returns {Object}
* @memberOf Store
*/
lunr.Store.prototype.get = function (id) {
return this.store[id]
}
/**
* Checks whether the store contains a key.
*
* @param {Object} id The id to look up in the store.
* @returns {Boolean}
* @memberOf Store
*/
lunr.Store.prototype.has = function (id) {
return id in this.store
}
/**
* Checks whether the store contains a key.
*
* @param {Object} id The id to look up in the store.
* @returns {Boolean}
* @memberOf Store
*/
lunr.Store.prototype.has = function (id) {
return id in this.store
}
/**
* Removes the value for a key in the store.
*
* @param {Object} id The id to remove from the store.
* @memberOf Store
*/
lunr.Store.prototype.remove = function (id) {
if (!this.has(id)) return
/**
* Removes the value for a key in the store.
*
* @param {Object} id The id to remove from the store.
* @memberOf Store
*/
lunr.Store.prototype.remove = function (id) {
if (!this.has(id)) return
delete this.store[id]
this.length--
}
delete this.store[id]
this.length--
}
/**
* Returns a representation of the store ready for serialisation.
*
* @returns {Object}
* @memberOf Store
*/
lunr.Store.prototype.toJSON = function () {
return {
store: this.store,
length: this.length
/**
* Returns a representation of the store ready for serialisation.
*
* @returns {Object}
* @memberOf Store
*/
lunr.Store.prototype.toJSON = function () {
return {
store: this.store,
length: this.length
}
}
}
/*!
* lunr.stemmer
* Copyright (C) 2014 Oliver Nightingale
* Includes code from - http://tartarus.org/~martin/PorterStemmer/js.txt
*/
/*!
* lunr.stemmer
* Copyright (C) 2014 Oliver Nightingale
* Includes code from - http://tartarus.org/~martin/PorterStemmer/js.txt
*/
/**
* lunr.stemmer is an english language stemmer, this is a JavaScript
* implementation of the PorterStemmer taken from http://tartaurs.org/~martin
*
* @module
* @param {String} str The string to stem
* @returns {String}
* @see lunr.Pipeline
*/
lunr.stemmer = (function(){
var step2list = {
"ational" : "ate",
"tional" : "tion",
"enci" : "ence",
"anci" : "ance",
"izer" : "ize",
"bli" : "ble",
"alli" : "al",
"entli" : "ent",
"eli" : "e",
"ousli" : "ous",
"ization" : "ize",
"ation" : "ate",
"ator" : "ate",
"alism" : "al",
"iveness" : "ive",
"fulness" : "ful",
"ousness" : "ous",
"aliti" : "al",
"iviti" : "ive",
"biliti" : "ble",
"logi" : "log"
},
step3list = {
"icate" : "ic",
"ative" : "",
"alize" : "al",
"iciti" : "ic",
"ical" : "ic",
"ful" : "",
"ness" : ""
},
c = "[^aeiou]", // consonant
v = "[aeiouy]", // vowel
C = c + "[^aeiouy]*", // consonant sequence
V = v + "[aeiou]*", // vowel sequence
mgr0 = "^(" + C + ")?" + V + C, // [C]VC... is m>0
meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$", // [C]VC[V] is m=1
mgr1 = "^(" + C + ")?" + V + C + V + C, // [C]VCVC... is m>1
s_v = "^(" + C + ")?" + v; // vowel in stem
return function (w) {
var stem,
suffix,
firstch,
re,
re2,
re3,
re4;
if (w.length < 3) { return w; }
firstch = w.substr(0,1);
if (firstch == "y") {
w = firstch.toUpperCase() + w.substr(1);
}
/**
* lunr.stemmer is an english language stemmer, this is a JavaScript
* implementation of the PorterStemmer taken from http://tartaurs.org/~martin
*
* @module
* @param {String} str The string to stem
* @returns {String}
* @see lunr.Pipeline
*/
lunr.stemmer = (function(){
var step2list = {
"ational" : "ate",
"tional" : "tion",
"enci" : "ence",
"anci" : "ance",
"izer" : "ize",
"bli" : "ble",
"alli" : "al",
"entli" : "ent",
"eli" : "e",
"ousli" : "ous",
"ization" : "ize",
"ation" : "ate",
"ator" : "ate",
"alism" : "al",
"iveness" : "ive",
"fulness" : "ful",
"ousness" : "ous",
"aliti" : "al",
"iviti" : "ive",
"biliti" : "ble",
"logi" : "log"
},
step3list = {
"icate" : "ic",
"ative" : "",
"alize" : "al",
"iciti" : "ic",
"ical" : "ic",
"ful" : "",
"ness" : ""
},
c = "[^aeiou]", // consonant
v = "[aeiouy]", // vowel
C = c + "[^aeiouy]*", // consonant sequence
V = v + "[aeiou]*", // vowel sequence
mgr0 = "^(" + C + ")?" + V + C, // [C]VC... is m>0
meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$", // [C]VC[V] is m=1
mgr1 = "^(" + C + ")?" + V + C + V + C, // [C]VCVC... is m>1
s_v = "^(" + C + ")?" + v; // vowel in stem
var re_mgr0 = new RegExp(mgr0);
var re_mgr1 = new RegExp(mgr1);
var re_meq1 = new RegExp(meq1);
var re_s_v = new RegExp(s_v);
var re_1a = /^(.+?)(ss|i)es$/;
var re2_1a = /^(.+?)([^s])s$/;
var re_1b = /^(.+?)eed$/;
var re2_1b = /^(.+?)(ed|ing)$/;
var re_1b_2 = /.$/;
var re2_1b_2 = /(at|bl|iz)$/;
var re3_1b_2 = new RegExp("([^aeiouylsz])\\1$");
var re4_1b_2 = new RegExp("^" + C + v + "[^aeiouwxy]$");
var re_1c = /^(.+?[^aeiou])y$/;
var re_2 = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;
var re_3 = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;
var re_4 = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;
var re2_4 = /^(.+?)(s|t)(ion)$/;
var re_5 = /^(.+?)e$/;
var re_5_1 = /ll$/;
var re3_5 = new RegExp("^" + C + v + "[^aeiouwxy]$");
var porterStemmer = function porterStemmer(w) {
var stem,
suffix,
firstch,
re,
re2,
re3,
re4;
if (w.length < 3) { return w; }
firstch = w.substr(0,1);
if (firstch == "y") {
w = firstch.toUpperCase() + w.substr(1);
}
// Step 1a
re = /^(.+?)(ss|i)es$/;
re2 = /^(.+?)([^s])s$/;
if (re.test(w)) { w = w.replace(re,"$1$2"); }
else if (re2.test(w)) { w = w.replace(re2,"$1$2"); }
// Step 1b
re = /^(.+?)eed$/;
re2 = /^(.+?)(ed|ing)$/;
if (re.test(w)) {
var fp = re.exec(w);
re = new RegExp(mgr0);
if (re.test(fp[1])) {
re = /.$/;
w = w.replace(re,"");
// Step 1a
re = re_1a
re2 = re2_1a;
if (re.test(w)) { w = w.replace(re,"$1$2"); }
else if (re2.test(w)) { w = w.replace(re2,"$1$2"); }
// Step 1b
re = re_1b;
re2 = re2_1b;
if (re.test(w)) {
var fp = re.exec(w);
re = re_mgr0;
if (re.test(fp[1])) {
re = re_1b_2;
w = w.replace(re,"");
}
} else if (re2.test(w)) {
var fp = re2.exec(w);
stem = fp[1];
re2 = re_s_v;
if (re2.test(stem)) {
w = stem;
re2 = re2_1b_2;
re3 = re3_1b_2;
re4 = re4_1b_2;
if (re2.test(w)) { w = w + "e"; }
else if (re3.test(w)) { re = re_1b_2; w = w.replace(re,""); }
else if (re4.test(w)) { w = w + "e"; }
}
}
} else if (re2.test(w)) {
var fp = re2.exec(w);
stem = fp[1];
re2 = new RegExp(s_v);
if (re2.test(stem)) {
w = stem;
re2 = /(at|bl|iz)$/;
re3 = new RegExp("([^aeiouylsz])\\1$");
re4 = new RegExp("^" + C + v + "[^aeiouwxy]$");
if (re2.test(w)) { w = w + "e"; }
else if (re3.test(w)) { re = /.$/; w = w.replace(re,""); }
else if (re4.test(w)) { w = w + "e"; }
// Step 1c - replace suffix y or Y by i if preceded by a non-vowel which is not the first letter of the word (so cry -> cri, by -> by, say -> say)
re = re_1c;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
w = stem + "i";
}
}
// Step 1c
re = /^(.+?)y$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
re = new RegExp(s_v);
if (re.test(stem)) { w = stem + "i"; }
}
// Step 2
re = re_2;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
suffix = fp[2];
re = re_mgr0;
if (re.test(stem)) {
w = stem + step2list[suffix];
}
}
// Step 2
re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
suffix = fp[2];
re = new RegExp(mgr0);
if (re.test(stem)) {
w = stem + step2list[suffix];
// Step 3
re = re_3;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
suffix = fp[2];
re = re_mgr0;
if (re.test(stem)) {
w = stem + step3list[suffix];
}
}
}
// Step 3
re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
suffix = fp[2];
re = new RegExp(mgr0);
if (re.test(stem)) {
w = stem + step3list[suffix];
// Step 4
re = re_4;
re2 = re2_4;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
re = re_mgr1;
if (re.test(stem)) {
w = stem;
}
} else if (re2.test(w)) {
var fp = re2.exec(w);
stem = fp[1] + fp[2];
re2 = re_mgr1;
if (re2.test(stem)) {
w = stem;
}
}
}
// Step 4
re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;
re2 = /^(.+?)(s|t)(ion)$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
re = new RegExp(mgr1);
if (re.test(stem)) {
w = stem;
// Step 5
re = re_5;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
re = re_mgr1;
re2 = re_meq1;
re3 = re3_5;
if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) {
w = stem;
}
}
} else if (re2.test(w)) {
var fp = re2.exec(w);
stem = fp[1] + fp[2];
re2 = new RegExp(mgr1);
if (re2.test(stem)) {
w = stem;
re = re_5_1;
re2 = re_mgr1;
if (re.test(w) && re2.test(w)) {
re = re_1b_2;
w = w.replace(re,"");
}
}
// Step 5
re = /^(.+?)e$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
re = new RegExp(mgr1);
re2 = new RegExp(meq1);
re3 = new RegExp("^" + C + v + "[^aeiouwxy]$");
if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) {
w = stem;
// and turn initial Y back to y
if (firstch == "y") {
w = firstch.toLowerCase() + w.substr(1);
}
}
re = /ll$/;
re2 = new RegExp(mgr1);
if (re.test(w) && re2.test(w)) {
re = /.$/;
w = w.replace(re,"");
}
return w;
};
// and turn initial Y back to y
return porterStemmer;
})();
if (firstch == "y") {
w = firstch.toLowerCase() + w.substr(1);
}
lunr.Pipeline.registerFunction(lunr.stemmer, 'stemmer')
/*!
* lunr.stopWordFilter
* Copyright (C) 2014 Oliver Nightingale
*/
return w;
/**
* lunr.stopWordFilter is an English language stop word list filter, any words
* contained in the list will not be passed through the filter.
*
* This is intended to be used in the Pipeline. If the token does not pass the
* filter then undefined will be returned.
*
* @module
* @param {String} token The token to pass through the filter
* @returns {String}
* @see lunr.Pipeline
*/
lunr.stopWordFilter = function (token) {
if (lunr.stopWordFilter.stopWords.indexOf(token) === -1) return token
}
})();
lunr.Pipeline.registerFunction(lunr.stemmer, 'stemmer')
/*!
* lunr.stopWordFilter
* Copyright (C) 2014 Oliver Nightingale
*/
lunr.stopWordFilter.stopWords = new lunr.SortedSet
lunr.stopWordFilter.stopWords.length = 119
lunr.stopWordFilter.stopWords.elements = [
"",
"a",
"able",
"about",
"across",
"after",
"all",
"almost",
"also",
"am",
"among",
"an",
"and",
"any",
"are",
"as",
"at",
"be",
"because",
"been",
"but",
"by",
"can",
"cannot",
"could",
"dear",
"did",
"do",
"does",
"either",
"else",
"ever",
"every",
"for",
"from",
"get",
"got",
"had",
"has",
"have",
"he",
"her",
"hers",
"him",
"his",
"how",
"however",
"i",
"if",
"in",
"into",
"is",
"it",
"its",
"just",
"least",
"let",
"like",
"likely",
"may",
"me",
"might",
"most",
"must",
"my",
"neither",
"no",
"nor",
"not",
"of",
"off",
"often",
"on",
"only",
"or",
"other",
"our",
"own",
"rather",
"said",
"say",
"says",
"she",
"should",
"since",
"so",
"some",
"than",
"that",
"the",
"their",
"them",
"then",
"there",
"these",
"they",
"this",
"tis",
"to",
"too",
"twas",
"us",
"wants",
"was",
"we",
"were",
"what",
"when",
"where",
"which",
"while",
"who",
"whom",
"why",
"will",
"with",
"would",
"yet",
"you",
"your"
]
lunr.Pipeline.registerFunction(lunr.stopWordFilter, 'stopWordFilter')
/*!
* lunr.trimmer
* Copyright (C) 2014 Oliver Nightingale
*/
/**
* lunr.stopWordFilter is an English language stop word list filter, any words
* contained in the list will not be passed through the filter.
*
* This is intended to be used in the Pipeline. If the token does not pass the
* filter then undefined will be returned.
*
* @module
* @param {String} token The token to pass through the filter
* @returns {String}
* @see lunr.Pipeline
*/
lunr.stopWordFilter = function (token) {
if (lunr.stopWordFilter.stopWords.indexOf(token) === -1) return token
}
lunr.stopWordFilter.stopWords = new lunr.SortedSet
lunr.stopWordFilter.stopWords.length = 119
lunr.stopWordFilter.stopWords.elements = [
"",
"a",
"able",
"about",
"across",
"after",
"all",
"almost",
"also",
"am",
"among",
"an",
"and",
"any",
"are",
"as",
"at",
"be",
"because",
"been",
"but",
"by",
"can",
"cannot",
"could",
"dear",
"did",
"do",
"does",
"either",
"else",
"ever",
"every",
"for",
"from",
"get",
"got",
"had",
"has",
"have",
"he",
"her",
"hers",
"him",
"his",
"how",
"however",
"i",
"if",
"in",
"into",
"is",
"it",
"its",
"just",
"least",
"let",
"like",
"likely",
"may",
"me",
"might",
"most",
"must",
"my",
"neither",
"no",
"nor",
"not",
"of",
"off",
"often",
"on",
"only",
"or",
"other",
"our",
"own",
"rather",
"said",
"say",
"says",
"she",
"should",
"since",
"so",
"some",
"than",
"that",
"the",
"their",
"them",
"then",
"there",
"these",
"they",
"this",
"tis",
"to",
"too",
"twas",
"us",
"wants",
"was",
"we",
"were",
"what",
"when",
"where",
"which",
"while",
"who",
"whom",
"why",
"will",
"with",
"would",
"yet",
"you",
"your"
]
lunr.Pipeline.registerFunction(lunr.stopWordFilter, 'stopWordFilter')
/*!
* lunr.trimmer
* Copyright (C) 2014 Oliver Nightingale
*/
/**
* lunr.trimmer is a pipeline function for trimming non word
* characters from the begining and end of tokens before they
* enter the index.
*
* This implementation may not work correctly for non latin
* characters and should either be removed or adapted for use
* with languages with non-latin characters.
*
* @module
* @param {String} token The token to pass through the filter
* @returns {String}
* @see lunr.Pipeline
*/
lunr.trimmer = function (token) {
return token
.replace(/^\W+/, '')
.replace(/\W+$/, '')
}
/**
* lunr.trimmer is a pipeline function for trimming non word
* characters from the begining and end of tokens before they
* enter the index.
*
* This implementation may not work correctly for non latin
* characters and should either be removed or adapted for use
* with languages with non-latin characters.
*
* @module
* @param {String} token The token to pass through the filter
* @returns {String}
* @see lunr.Pipeline
*/
lunr.trimmer = function (token) {
return token
.replace(/^\W+/, '')
.replace(/\W+$/, '')
}
lunr.Pipeline.registerFunction(lunr.trimmer, 'trimmer')
/*!
* lunr.stemmer
* Copyright (C) 2014 Oliver Nightingale
* Includes code from - http://tartarus.org/~martin/PorterStemmer/js.txt
*/
lunr.Pipeline.registerFunction(lunr.trimmer, 'trimmer')
/*!
* lunr.stemmer
* Copyright (C) 2014 Oliver Nightingale
* Includes code from - http://tartarus.org/~martin/PorterStemmer/js.txt
*/
/**
* lunr.TokenStore is used for efficient storing and lookup of the reverse
* index of token to document ref.
*
* @constructor
*/
lunr.TokenStore = function () {
this.root = { docs: {} }
this.length = 0
}
/**
* lunr.TokenStore is used for efficient storing and lookup of the reverse
* index of token to document ref.
*
* @constructor
*/
lunr.TokenStore = function () {
this.root = { docs: {} }
this.length = 0
}
/**
* Loads a previously serialised token store
*
* @param {Object} serialisedData The serialised token store to load.
* @returns {lunr.TokenStore}
* @memberOf TokenStore
*/
lunr.TokenStore.load = function (serialisedData) {
var store = new this
/**
* Loads a previously serialised token store
*
* @param {Object} serialisedData The serialised token store to load.
* @returns {lunr.TokenStore}
* @memberOf TokenStore
*/
lunr.TokenStore.load = function (serialisedData) {
var store = new this
store.root = serialisedData.root
store.length = serialisedData.length
store.root = serialisedData.root
store.length = serialisedData.length
return store
}
return store
}
/**
* Adds a new token doc pair to the store.
*
* By default this function starts at the root of the current store, however
* it can start at any node of any token store if required.
*
* @param {String} token The token to store the doc under
* @param {Object} doc The doc to store against the token
* @param {Object} root An optional node at which to start looking for the
* correct place to enter the doc, by default the root of this lunr.TokenStore
* is used.
* @memberOf TokenStore
*/
lunr.TokenStore.prototype.add = function (token, doc, root) {
var root = root || this.root,
key = token[0],
rest = token.slice(1)
/**
* Adds a new token doc pair to the store.
*
* By default this function starts at the root of the current store, however
* it can start at any node of any token store if required.
*
* @param {String} token The token to store the doc under
* @param {Object} doc The doc to store against the token
* @param {Object} root An optional node at which to start looking for the
* correct place to enter the doc, by default the root of this lunr.TokenStore
* is used.
* @memberOf TokenStore
*/
lunr.TokenStore.prototype.add = function (token, doc, root) {
var root = root || this.root,
key = token[0],
rest = token.slice(1)
if (!(key in root)) root[key] = {docs: {}}
if (!(key in root)) root[key] = {docs: {}}
if (rest.length === 0) {
root[key].docs[doc.ref] = doc
this.length += 1
return
} else {
return this.add(rest, doc, root[key])
if (rest.length === 0) {
root[key].docs[doc.ref] = doc
this.length += 1
return
} else {
return this.add(rest, doc, root[key])
}
}
}
/**
* Checks whether this key is contained within this lunr.TokenStore.
*
* By default this function starts at the root of the current store, however
* it can start at any node of any token store if required.
*
* @param {String} token The token to check for
* @param {Object} root An optional node at which to start
* @memberOf TokenStore
*/
lunr.TokenStore.prototype.has = function (token) {
if (!token) return false
/**
* Checks whether this key is contained within this lunr.TokenStore.
*
* By default this function starts at the root of the current store, however
* it can start at any node of any token store if required.
*
* @param {String} token The token to check for
* @param {Object} root An optional node at which to start
* @memberOf TokenStore
*/
lunr.TokenStore.prototype.has = function (token) {
if (!token) return false
var node = this.root
var node = this.root
for (var i = 0; i < token.length; i++) {
if (!node[token[i]]) return false
for (var i = 0; i < token.length; i++) {
if (!node[token[i]]) return false
node = node[token[i]]
}
node = node[token[i]]
return true
}
return true
}
/**
* Retrieve a node from the token store for a given token.
*
* By default this function starts at the root of the current store, however
* it can start at any node of any token store if required.
*
* @param {String} token The token to get the node for.
* @param {Object} root An optional node at which to start.
* @returns {Object}
* @see TokenStore.prototype.get
* @memberOf TokenStore
*/
lunr.TokenStore.prototype.getNode = function (token) {
if (!token) return {}
/**
* Retrieve a node from the token store for a given token.
*
* By default this function starts at the root of the current store, however
* it can start at any node of any token store if required.
*
* @param {String} token The token to get the node for.
* @param {Object} root An optional node at which to start.
* @returns {Object}
* @see TokenStore.prototype.get
* @memberOf TokenStore
*/
lunr.TokenStore.prototype.getNode = function (token) {
if (!token) return {}
var node = this.root
var node = this.root
for (var i = 0; i < token.length; i++) {
if (!node[token[i]]) return {}
for (var i = 0; i < token.length; i++) {
if (!node[token[i]]) return {}
node = node[token[i]]
}
node = node[token[i]]
return node
}
return node
}
/**
* Retrieve the documents for a node for the given token.
*
* By default this function starts at the root of the current store, however
* it can start at any node of any token store if required.
*
* @param {String} token The token to get the documents for.
* @param {Object} root An optional node at which to start.
* @returns {Object}
* @memberOf TokenStore
*/
lunr.TokenStore.prototype.get = function (token, root) {
return this.getNode(token, root).docs || {}
}
/**
* Retrieve the documents for a node for the given token.
*
* By default this function starts at the root of the current store, however
* it can start at any node of any token store if required.
*
* @param {String} token The token to get the documents for.
* @param {Object} root An optional node at which to start.
* @returns {Object}
* @memberOf TokenStore
*/
lunr.TokenStore.prototype.get = function (token, root) {
return this.getNode(token, root).docs || {}
}
lunr.TokenStore.prototype.count = function (token, root) {
return Object.keys(this.get(token, root)).length
}
lunr.TokenStore.prototype.count = function (token, root) {
return Object.keys(this.get(token, root)).length
}
/**
* Remove the document identified by ref from the token in the store.
*
* By default this function starts at the root of the current store, however
* it can start at any node of any token store if required.
*
* @param {String} token The token to get the documents for.
* @param {String} ref The ref of the document to remove from this token.
* @param {Object} root An optional node at which to start.
* @returns {Object}
* @memberOf TokenStore
*/
lunr.TokenStore.prototype.remove = function (token, ref) {
if (!token) return
var node = this.root
/**
* Remove the document identified by ref from the token in the store.
*
* By default this function starts at the root of the current store, however
* it can start at any node of any token store if required.
*
* @param {String} token The token to get the documents for.
* @param {String} ref The ref of the document to remove from this token.
* @param {Object} root An optional node at which to start.
* @returns {Object}
* @memberOf TokenStore
*/
lunr.TokenStore.prototype.remove = function (token, ref) {
if (!token) return
var node = this.root
for (var i = 0; i < token.length; i++) {
if (!(token[i] in node)) return
node = node[token[i]]
}
for (var i = 0; i < token.length; i++) {
if (!(token[i] in node)) return
node = node[token[i]]
delete node.docs[ref]
}
delete node.docs[ref]
}
/**
* Find all the possible suffixes of the passed token using tokens
* currently in the store.
*
* @param {String} token The token to expand.
* @returns {Array}
* @memberOf TokenStore
*/
lunr.TokenStore.prototype.expand = function (token, memo) {
var root = this.getNode(token),
docs = root.docs || {},
memo = memo || []
/**
* Find all the possible suffixes of the passed token using tokens
* currently in the store.
*
* @param {String} token The token to expand.
* @returns {Array}
* @memberOf TokenStore
*/
lunr.TokenStore.prototype.expand = function (token, memo) {
var root = this.getNode(token),
docs = root.docs || {},
memo = memo || []
if (Object.keys(docs).length) memo.push(token)
if (Object.keys(docs).length) memo.push(token)
Object.keys(root)
.forEach(function (key) {
if (key === 'docs') return
Object.keys(root)
.forEach(function (key) {
if (key === 'docs') return
memo.concat(this.expand(token + key, memo))
}, this)
memo.concat(this.expand(token + key, memo))
}, this)
return memo
}
return memo
}
/**
* Returns a representation of the token store ready for serialisation.
*
* @returns {Object}
* @memberOf TokenStore
*/
lunr.TokenStore.prototype.toJSON = function () {
return {
root: this.root,
length: this.length
/**
* Returns a representation of the token store ready for serialisation.
*
* @returns {Object}
* @memberOf TokenStore
*/
lunr.TokenStore.prototype.toJSON = function () {
return {
root: this.root,
length: this.length
}
}
}
/**
* export the module via AMD, CommonnJS or as a browser global
* export the module via AMD, CommonJS or as a browser global
* Export code from https://github.com/umdjs/umd/blob/master/returnExports.js
*/
;(function (root, factory) {
......
......@@ -24,7 +24,7 @@ under the License.
<%= stylesheet_link_tag :screen, media: :screen %>
<%= stylesheet_link_tag :print, media: :print %>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<% if current_page.data.search %>
<%= javascript_include_tag "all" %>
<% else %>
......
/*! normalize.css v2.0.1 | MIT License | git.io/normalize */
/*! normalize.css v3.0.2 | MIT License | git.io/normalize */
/* ==========================================================================
HTML5 display definitions
/**
* 1. Set default font family to sans-serif.
* 2. Prevent iOS text size adjust after orientation change, without disabling
* user zoom.
*/
html {
font-family: sans-serif; /* 1 */
-ms-text-size-adjust: 100%; /* 2 */
-webkit-text-size-adjust: 100%; /* 2 */
}
/**
* Remove default margin.
*/
body {
margin: 0;
}
/* HTML5 display definitions
========================================================================== */
/*
* Corrects `block` display not defined in IE 8/9.
/**
* Correct `block` display not defined for any HTML5 element in IE 8/9.
* Correct `block` display not defined for `details` or `summary` in IE 10/11
* and Firefox.
* Correct `block` display not defined for `main` in IE 11.
*/
article,
......@@ -16,24 +38,29 @@ figure,
footer,
header,
hgroup,
main,
menu,
nav,
section,
summary {
display: block;
}
/*
* Corrects `inline-block` display not defined in IE 8/9.
/**
* 1. Correct `inline-block` display not defined in IE 8/9.
* 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
*/
audio,
canvas,
progress,
video {
display: inline-block;
display: inline-block; /* 1 */
vertical-align: baseline; /* 2 */
}
/*
* Prevents modern browsers from displaying `audio` without controls.
/**
* Prevent modern browsers from displaying `audio` without controls.
* Remove excess height in iOS 5 devices.
*/
......@@ -42,52 +69,29 @@ audio:not([controls]) {
height: 0;
}
/*
* Addresses styling for `hidden` attribute not present in IE 8/9.
/**
* Address `[hidden]` styling not present in IE 8/9/10.
* Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.
*/
[hidden] {
[hidden],
template {
display: none;
}
/* ==========================================================================
Base
/* Links
========================================================================== */
/*
* 1. Sets default font family to sans-serif.
* 2. Prevents iOS text size adjust after orientation change, without disabling
* user zoom.
/**
* Remove the gray background color from active links in IE 10.
*/
html {
font-family: sans-serif; /* 1 */
-webkit-text-size-adjust: 100%; /* 2 */
-ms-text-size-adjust: 100%; /* 2 */
a {
background-color: transparent;
}
/*
* Removes default margin.
*/
body {
margin: 0;
}
/* ==========================================================================
Links
========================================================================== */
/*
* Addresses `outline` inconsistency between Chrome and other browsers.
*/
a:focus {
outline: thin dotted;
}
/*
* Improves readability when focused and also mouse hovered in all browsers.
/**
* Improve readability when focused and also mouse hovered in all browsers.
*/
a:active,
......@@ -95,29 +99,19 @@ a:hover {
outline: 0;
}
/* ==========================================================================
Typography
/* Text-level semantics
========================================================================== */
/*
* Addresses `h1` font sizes within `section` and `article` in Firefox 4+,
* Safari 5, and Chrome.
*/
h1 {
font-size: 2em;
}
/*
* Addresses styling not present in IE 8/9, Safari 5, and Chrome.
/**
* Address styling not present in IE 8/9/10/11, Safari, and Chrome.
*/
abbr[title] {
border-bottom: 1px dotted;
}
/*
* Addresses style set to `bolder` in Firefox 4+, Safari 5, and Chrome.
/**
* Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
*/
b,
......@@ -125,64 +119,43 @@ strong {
font-weight: bold;
}
/*
* Addresses styling not present in Safari 5 and Chrome.
/**
* Address styling not present in Safari and Chrome.
*/
dfn {
font-style: italic;
}
/*
* Addresses styling not present in IE 8/9.
*/
mark {
background: #ff0;
color: #000;
}
/*
* Corrects font family set oddly in Safari 5 and Chrome.
/**
* Address variable `h1` font-size and margin within `section` and `article`
* contexts in Firefox 4+, Safari, and Chrome.
*/
code,
kbd,
pre,
samp {
font-family: monospace, serif;
font-size: 1em;
}
/*
* Improves readability of pre-formatted text in all browsers.
*/
pre {
white-space: pre;
white-space: pre-wrap;
word-wrap: break-word;
h1 {
font-size: 2em;
margin: 0.67em 0;
}
/*
* Sets consistent quote types.
/**
* Address styling not present in IE 8/9.
*/
q {
quotes: "\201C" "\201D" "\2018" "\2019";
mark {
background: #ff0;
color: #000;
}
/*
* Addresses inconsistent and variable font size in all browsers.
/**
* Address inconsistent and variable font size in all browsers.
*/
small {
font-size: 80%;
}
/*
* Prevents `sub` and `sup` affecting `line-height` in all browsers.
/**
* Prevent `sub` and `sup` affecting `line-height` in all browsers.
*/
sub,
......@@ -201,92 +174,116 @@ sub {
bottom: -0.25em;
}
/* ==========================================================================
Embedded content
/* Embedded content
========================================================================== */
/*
* Removes border when inside `a` element in IE 8/9.
/**
* Remove border when inside `a` element in IE 8/9/10.
*/
img {
border: 0;
}
/*
* Corrects overflow displayed oddly in IE 9.
/**
* Correct overflow not hidden in IE 9/10/11.
*/
svg:not(:root) {
overflow: hidden;
}
/* ==========================================================================
Figures
/* Grouping content
========================================================================== */
/*
* Addresses margin not present in IE 8/9 and Safari 5.
/**
* Address margin not present in IE 8/9 and Safari.
*/
figure {
margin: 0;
margin: 1em 40px;
}
/* ==========================================================================
Forms
========================================================================== */
/**
* Address differences between Firefox and other browsers.
*/
/*
* Define consistent border, margin, and padding.
hr {
-moz-box-sizing: content-box;
box-sizing: content-box;
height: 0;
}
/**
* Contain overflow in all browsers.
*/
fieldset {
border: 1px solid #c0c0c0;
margin: 0 2px;
padding: 0.35em 0.625em 0.75em;
pre {
overflow: auto;
}
/*
* 1. Corrects color not being inherited in IE 8/9.
* 2. Remove padding so people aren't caught out if they zero out fieldsets.
/**
* Address odd `em`-unit font size rendering in all browsers.
*/
legend {
border: 0; /* 1 */
padding: 0; /* 2 */
code,
kbd,
pre,
samp {
font-family: monospace, monospace;
font-size: 1em;
}
/*
* 1. Corrects font family not being inherited in all browsers.
* 2. Corrects font size not being inherited in all browsers.
* 3. Addresses margins set differently in Firefox 4+, Safari 5, and Chrome
/* Forms
========================================================================== */
/**
* Known limitation: by default, Chrome and Safari on OS X allow very limited
* styling of `select`, unless a `border` property is set.
*/
/**
* 1. Correct color not being inherited.
* Known issue: affects color of disabled elements.
* 2. Correct font properties not being inherited.
* 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
*/
button,
input,
optgroup,
select,
textarea {
font-family: inherit; /* 1 */
font-size: 100%; /* 2 */
color: inherit; /* 1 */
font: inherit; /* 2 */
margin: 0; /* 3 */
}
/*
* Addresses Firefox 4+ setting `line-height` on `input` using `!important` in
* the UA stylesheet.
/**
* Address `overflow` set to `hidden` in IE 8/9/10/11.
*/
button {
overflow: visible;
}
/**
* Address inconsistent `text-transform` inheritance for `button` and `select`.
* All other form control elements do not inherit `text-transform` values.
* Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
* Correct `select` style inheritance in Firefox.
*/
button,
input {
line-height: normal;
select {
text-transform: none;
}
/*
/**
* 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
* and `video` controls.
* 2. Corrects inability to style clickable `input` types in iOS.
* 3. Improves usability and consistency of cursor style between image-type
* 2. Correct inability to style clickable `input` types in iOS.
* 3. Improve usability and consistency of cursor style between image-type
* `input` and others.
*/
......@@ -298,18 +295,40 @@ input[type="submit"] {
cursor: pointer; /* 3 */
}
/*
/**
* Re-set default cursor for disabled elements.
*/
button[disabled],
input[disabled] {
html input[disabled] {
cursor: default;
}
/*
* 1. Addresses box sizing set to `content-box` in IE 8/9.
* 2. Removes excess padding in IE 8/9.
/**
* Remove inner padding and border in Firefox 4+.
*/
button::-moz-focus-inner,
input::-moz-focus-inner {
border: 0;
padding: 0;
}
/**
* Address Firefox 4+ setting `line-height` on `input` using `!important` in
* the UA stylesheet.
*/
input {
line-height: normal;
}
/**
* It's recommended that you don't attempt to style these elements.
* Firefox's implementation doesn't respect box-sizing, padding, or width.
*
* 1. Address box sizing set to `content-box` in IE 8/9/10.
* 2. Remove excess padding in IE 8/9/10.
*/
input[type="checkbox"],
......@@ -318,9 +337,20 @@ input[type="radio"] {
padding: 0; /* 2 */
}
/*
* 1. Addresses `appearance` set to `searchfield` in Safari 5 and Chrome.
* 2. Addresses `box-sizing` set to `border-box` in Safari 5 and Chrome
/**
* Fix the cursor style for Chrome's increment/decrement buttons. For certain
* `font-size` values of the `input`, it causes the cursor style of the
* decrement button to change from `default` to `text`.
*/
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
height: auto;
}
/**
* 1. Address `appearance` set to `searchfield` in Safari and Chrome.
* 2. Address `box-sizing` set to `border-box` in Safari and Chrome
* (include `-moz` to future-proof).
*/
......@@ -331,9 +361,10 @@ input[type="search"] {
box-sizing: content-box;
}
/*
* Removes inner padding and search cancel button in Safari 5 and Chrome
* on OS X.
/**
* Remove inner padding and search cancel button in Safari and Chrome on OS X.
* Safari (but not Chrome) clips the cancel button when the search input has
* padding (and `textfield` appearance).
*/
input[type="search"]::-webkit-search-cancel-button,
......@@ -341,35 +372,56 @@ input[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
/*
* Removes inner padding and border in Firefox 4+.
/**
* Define consistent border, margin, and padding.
*/
button::-moz-focus-inner,
input::-moz-focus-inner {
border: 0;
padding: 0;
fieldset {
border: 1px solid #c0c0c0;
margin: 0 2px;
padding: 0.35em 0.625em 0.75em;
}
/*
* 1. Removes default vertical scrollbar in IE 8/9.
* 2. Improves readability and alignment in all browsers.
/**
* 1. Correct `color` not being inherited in IE 8/9/10/11.
* 2. Remove padding so people aren't caught out if they zero out fieldsets.
*/
legend {
border: 0; /* 1 */
padding: 0; /* 2 */
}
/**
* Remove default vertical scrollbar in IE 8/9/10/11.
*/
textarea {
overflow: auto; /* 1 */
vertical-align: top; /* 2 */
overflow: auto;
}
/* ==========================================================================
Tables
/**
* Don't inherit the `font-weight` (applied by a rule above).
* NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
*/
optgroup {
font-weight: bold;
}
/* Tables
========================================================================== */
/*
/**
* Remove most spacing between table cells.
*/
table {
border-collapse: collapse;
border-spacing: 0;
}
\ No newline at end of file
}
td,
th {
padding: 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment