Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

major overhaul including update to latest version of twitter bootstra…

…p. work in progress
  • Loading branch information...
commit 1c025fdea1e6b59299d15ded1205276c7a318091 1 parent 114105d
@markmacgillivray markmacgillivray authored
View
117 README.rst
@@ -12,8 +12,8 @@ Development is now taking place in this repo: http://github.com/okfn/facetview
Demo
====
-See http://okfnlabs.org/facetview/ or just take a look at index.html (if you
-have the source).
+See http://okfnlabs.org/facetview/ or if you have the source just take a look
+at index.html or simple.html
Status
@@ -29,32 +29,35 @@ Using FacetView
Add the following code to your web page::
- <script src="JQUERY-SOURCE"></script>
- <script type="text/javascript" src="YOUR-FACETVIEW-SOURCE"></script>
+ <script type="text/javascript" src="vendor/jquery/1.7.1/jquery-1.7.1.min.js"></script>
+ <script type="text/javascript" src="jquery.facetview.js"></script>
+
+ <link rel="stylesheet" href="vendor/bootstrap/css/bootstrap.min.css">
+ <script type="text/javascript" src="vendor/bootstrap/js/bootstrap.min.js"></script>
- <script type="text/javascript">
- jQuery(document).ready(function() {
- jQuery('jquery-selector').facetview();
- });
- </script>
+ <link rel="stylesheet" href="css/facetview.css">
-* JQUERY-SOURCE – change this to wherever you get your jQuery from. For
- example, https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.js. If you
- already have jQuery on your page / site, then you can miss out that first
- script tag entirely.
-* YOUR-FACETVIEW-SOURCE – change this to whatever online you put your copy of
- facetview at. For example, http://bibsoup.net/static/jquery.facetview.js
-* YOUR-PAGE-PART – change this to identify whatever part of the page you want
- to append the FacetView into. For example, ‘body’ would do, or you could have
- a <div> on your page like this::
+* BUT change the src URLs to something sensible depending on where you install
+ the files
- <div id="your-page-part></div>
-.. note::
-
- You may also want to include css. The out of the box html and css is
- Bootstrap plus css/facetview.css. However, you are welcome to customize
- this or add your own.
+Then add a script somewhere to your page that actually calls and sets up the
+facetview on a particular page element:
+
+ <script type="text/javascript">
+ jQuery(document).ready(function($) {
+ $('.facet-view-simple').facetview({
+ search_url: 'http://bibsoup.net/query?',
+ search_index: 'elasticsearch',
+ facets: [
+ {'field': 'publisher.exact', 'size': 100, 'order':'term', 'display': 'publisher'},
+ {'field': 'author.name.exact', 'display': 'author'},
+ {'field': 'year.exact', 'display': 'year'}
+ ],
+ });
+ });
+ </script>
+
Now that you have everything ready, you will probably want to customize to
get it looking the way you want it.
@@ -69,64 +72,39 @@ customisation. There are a few ways to do this:
Edit the config in jquery.facetview.js
--------------------------------------
-Specify the defaults::
-
- var defaults = {
- "config_file":false,
- "default_filters":["journal","author","year"],
- "result_display_headers":["title","journal","author"],
- "ignore_fields":["_id","_rev"],
- "show_advanced":false,
- "search_url":"",
- "search_index":"elasticsearch",
- "default_url_params":{},
- "freetext_submit_delay":"700",
- "query_parameter":"q",
- "q":"*:*",
- "predefined_query_values":{},
- "default_paging":{}
- };
-
-* config_file – the location of an external config file (explained below)
-* default_filters – the filters you want to see down the right hand side, for
- filtering your results by.
-* filter_query_key –
-* result_display_headers – which fields to display in the result list (other
- fields are shown when you click on the result)
-* ignore_fields – any fields not to show at all
-* show_advanced – for now, just shows or hides the advanced panel, which at the
- moment only gives the options to add more filters
-* search_url – the endpoint for submitting search queries to
+View the config options near the top of the file to learn more. Some
+important points:
+
+* result_display - there is a long example of result display. It is a list of
+ lists; each list represents a line; each line contains objects; the objects
+ specify the field they should output, and pre and post information to surround
+ it with
+* search_url – you need this. Should be an elasticsearch or SOLR query endpoint
* search_index – your index type, solr or elasticsearch
* default_url_params – parameters to pass through with every query; should
include “wt”:”json” for SOLR queries to return JSON, and probably
“facet.mincount”:1 for SOLR queries to ignore zero counts on facet values
-* freetext_submit_delay – the delay in milliseconds before the free text search
- field triggers a result update
-* query_parameter – the name of the search query parameter that should be
- passed to your index. usually this is “q”
-* q – the default blank search query parameter, such as “:“
-* predefined_query_values – any values you want embedded into the query every
- time a query is submitted, to restrict the result set
-* default_paging – default result size, and default starting result
+* predefined_filters – use these to apply some filters that will be appended
+ to every search. For example, customise a facetview display to only show
+ records with a particular owner / collection / tag / whatever
Pass in config settings when calling FacetView
----------------------------------------------
-All of the above settings can also be defined when calling FacetView, and will
+All of the settings can also be defined when calling FacetView, and will
overwrite the values set in the file itself. So you can do something like
this::
<script type="text/javascript">
jQuery(document).ready(function() {
jQuery('YOUR-PAGE-PART').facetview({
- "search_index":"solr",
- "query_parameter":"q"
+ "search_index":"elasticsearch",
+ ...
});
});
</script>
-Provide the location of an external config file
+Providing the location of an external config file
-----------------------------------------------
(in development)
@@ -138,11 +116,11 @@ call FacetView, and it will read that config file for you.
Change the layout by making and using a custom CSS file
-------------------------------------------------------
-When FacetView runs, it calls a default CSS file. Take a look at the
-jquery.facetview.js file – at the top, it defines a CSS file location, then
-calls it into your page. You can copy that CSS file, make your own version,
-then call your version instead. This will allow you to style it however you
-want.
+Facetview uses the latest `twitter bootstrap`_. When you embed facetview in a page,
+you need to include the calls to bootstrap js and css files (see the example
+index.html here for more info). You could restyle facetview any way you want,
+either with our without bootstrap - although it would be a hassle to strip
+bootstrap out; recommend working with or around it.
Copyright and License
@@ -152,5 +130,6 @@ Copyright 2011 Open Knowledge Foundation and Cottage Labs.
Licensed under the `MIT License`_
+.. _twitter bootstrap: http://twitter.github.com/bootstrap/
.. _MIT License: http://www.opensource.org/licenses/mit-license.php
View
92 css/facetview.css
@@ -1,9 +1,11 @@
-#facetview_freetext {
- width: 85%;
- display: block;
- margin: auto;
+#facetview_freetext{
+ -moz-border-radius: 0px;
+ -webkit-border-radius: 0px;
+ border-radius: 0px;
+}
+#facetview_filters h3{
+ margin:40px 0 20px 0;
}
-
#facetview_advanced{
float:left;
clear:left;
@@ -27,25 +29,12 @@
-webkit-border-radius: 2px;
border-radius: 2px;
}
-.facetview_filtertag{
- padding:2px 0;
- font-weight:bold;
- color:#373737;
-}
.facetview_filterchoice{
text-decoration:none;
color:#373737;
}
-#facetview_selectedfilters{
- list-style-type:none;
- margin:0;
- padding:0;
-}
.facetview_filterselected{
- color:green;
-}
-.facetview_filterhidden{
- display:none;
+ margin:5px;
}
.facetview_freetext_filterdiv{
float:left;
@@ -55,80 +44,15 @@
color:green;
width:100%;
}
-.facetview_freetextfilter{
- height:15px;
- width:130px;
- padding:0;
- margin:5px 0 5px 0;
- background:#fff;
- border:1px dotted #ddd;
- color:#888;
- -moz-border-radius: 2px;
- -webkit-border-radius: 2px;
- border-radius: 2px;
-}
.facetview_advancedshow{
text-decoration:none;
color:#a1a1a1;
}
-.facetview_result{
- color:#373737;
- border-bottom:1px dotted #373737;
- padding:5px;
- margin:5px;
-}
-a.facetview_clear{
- text-decoration:none;
- color:red;
- font-weight:bold;
- font-size:12px;
- padding:0 0 0 5px;
-}
-a.facetview_more{
- font-weight:bold;
- color:#a1a1a1;
-}
-.facetview_moretabletitle{
- min-width:100px;
- text-align:right;
- vertical-align:text-top;
- color:#a1a1a1;
- overflow:hidden;
-}
-.facetview_moreinfo{
- display:none;
- font-size:11px;
-}
-.facetview_searchthis{
- display:none;
-}
-.facetview_raw{
- padding:5px;
- margin:5px;
- background:#eee;
- -moz-border-radius: 3px;
- -webkit-border-radius: 3px;
- border-radius: 3px;
-}
.facetview_resultactions a{
color:#353535;
font-weight:bold;
text-decoration:none;
margin:0 5px 0 5px;
}
-.facetview_green{
- color:green;
-}
-.facetview_editingbox{
-
-}
-.facetview_hidden{
- display:none;
-}
-
-td.facetview_fixed{
- width:340px;
- overflow:hidden;
-}
View
29 index.html
@@ -3,21 +3,27 @@
<head>
<meta charset="utf-8" />
<title>FacetView</title>
- <link rel="stylesheet" href="vendorjs/bootstrap/1.4.0/bootstrap.css">
- <link rel="stylesheet" href="css/style.css">
- <link rel="stylesheet" href="css/facetview.css">
- <script type="text/javascript" src="vendorjs/jquery/1.6.2/jquery.js"></script>
+ <script type="text/javascript" src="vendor/jquery/1.7.1/jquery-1.7.1.min.js"></script>
<script type="text/javascript" src="jquery.facetview.js"></script>
+ <link rel="stylesheet" href="vendor/bootstrap/css/bootstrap.min.css">
+ <script type="text/javascript" src="vendor/bootstrap/js/bootstrap.min.js"></script>
+
+ <link rel="stylesheet" href="css/facetview.css">
+
+ <link rel="stylesheet" href="css/style.css">
+
<script type="text/javascript">
jQuery(document).ready(function($) {
$('.facet-view-simple').facetview({
search_url: 'http://bibsoup.net/query?',
search_index: 'elasticsearch',
- default_filters: ['year', 'publisher'],
- result_display_headers: ['title','info'],
- default_paging: {
+ facets: [
+ {'field':'year.exact', 'display': 'year'},
+ {'field':'publisher.exact', 'display': 'publisher'}
+ ],
+ paging: {
from: 0,
size: 10
}
@@ -35,9 +41,11 @@
});
</script>
</head>
+
<body>
-<div class="topbar">
- <div class="fill">
+
+<div class="navbar navbar-fixed-top">
+ <div class="navbar-inner">
<div class="container">
<a class="brand" href="#">FacetView</a>
<ul class="nav">
@@ -52,6 +60,7 @@
</div>
</div>
</div>
+
<div class="container">
<div class="content">
<div class="page-header">
@@ -64,7 +73,7 @@
search indices.
</h4>
<h4>
- It's lets you easily embed a faceted browser and search front end into any web page. It also provides micro-framework you can build on when creating user interfaces to SOLR and ElasticSearch.
+ It lets you easily embed a faceted browser and search front end into any web page. It also provides a micro-framework you can build on when creating user interfaces to SOLR and ElasticSearch.
</h4>
<h2>Demo</h2>
View
644 jquery.facetview.js
@@ -17,30 +17,30 @@
// first define the bind with delay function from (saves loading it separately)
// https://github.com/bgrins/bindWithDelay/blob/master/bindWithDelay.js
(function($) {
-$.fn.bindWithDelay = function( type, data, fn, timeout, throttle ) {
-var wait = null;
-var that = this;
-
-if ( $.isFunction( data ) ) {
-throttle = timeout;
-timeout = fn;
-fn = data;
-data = undefined;
-}
-
-function cb() {
-var e = $.extend(true, { }, arguments[0]);
-var throttler = function() {
-wait = null;
-fn.apply(that, [e]);
-};
-
-if (!throttle) { clearTimeout(wait); }
-if (!throttle || !wait) { wait = setTimeout(throttler, timeout); }
-}
-
-return this.bind(type, data, cb);
-}
+ $.fn.bindWithDelay = function( type, data, fn, timeout, throttle ) {
+ var wait = null;
+ var that = this;
+
+ if ( $.isFunction( data ) ) {
+ throttle = timeout;
+ timeout = fn;
+ fn = data;
+ data = undefined;
+ }
+
+ function cb() {
+ var e = $.extend(true, { }, arguments[0]);
+ var throttler = function() {
+ wait = null;
+ fn.apply(that, [e]);
+ };
+
+ if (!throttle) { clearTimeout(wait); }
+ if (!throttle || !wait) { wait = setTimeout(throttler, timeout); }
+ }
+
+ return this.bind(type, data, cb);
+ }
})(jQuery);
@@ -48,25 +48,80 @@ return this.bind(type, data, cb);
(function($){
$.fn.facetview = function(options) {
+ // some big default values
+ var resdisplay = [
+ [
+ {
+ "field": "author.name"
+ },
+ {
+ "pre": "(",
+ "field": "year",
+ "post": ")"
+ }
+ ],
+ [
+ {
+ "pre": "<strong>",
+ "field": "title",
+ "post": "</strong>"
+ }
+ ],
+ [
+ {
+ "field": "howpublished"
+ },
+ {
+ "pre": "in <em>",
+ "field": "journal.name",
+ "post": "</em>,"
+ },
+ {
+ "pre": "<em>",
+ "field": "booktitle",
+ "post": "</em>,"
+ },
+ {
+ "pre": "vol. ",
+ "field": "volume",
+ "post": ","
+ },
+ {
+ "field": "pages"
+ },
+ {
+ "field": "publisher"
+ }
+ ],
+ [
+ {
+ "field": "link.url"
+ }
+ ]
+ ]
+
+
// specify the defaults
var defaults = {
"config_file":false,
- "default_filters":[],
- "result_display_headers":["title"],
+ "facets":[],
+ "result_display": resdisplay,
"ignore_fields":["_id","_rev"],
- "show_advanced":false,
+ "description":"",
"search_url":"",
"search_index":"elasticsearch",
"default_url_params":{},
"freetext_submit_delay":"700",
"query_parameter":"q",
"q":"*:*",
- "predefined_query_values":{},
- "default_paging":{}
+ "predefined_filters":{},
+ "paging":{}
};
// and add in any overrides from the call
var options = $.extend(defaults, options);
+ !options.paging.size ? options.paging.size = 10 : ""
+ !options.paging.from ? options.paging.from = 0 : ""
// ===============================================
// functions to do with filters
@@ -75,104 +130,115 @@ return this.bind(type, data, cb);
// show the filter values
var showfiltervals = function(event) {
event.preventDefault();
- if ( jQuery(this).hasClass('facetview_open') ) {
- jQuery(this).removeClass('facetview_open');
- jQuery('#facetview_' + jQuery(this).attr('rel') ).children().hide();
- jQuery('#facetview_freetext_' + jQuery(this).attr('rel') ).parent().hide();
+ if ( $(this).hasClass('facetview_open') ) {
+ $(this).removeClass('facetview_open');
+ $('#facetview_' + $(this).attr('rel') ).children().hide();
+ $('#facetview_freetext_' + $(this).attr('rel') ).parent().hide();
} else {
- jQuery(this).addClass('facetview_open');
- jQuery('#facetview_' + jQuery(this).attr('rel') ).children().show();
- jQuery('#facetview_freetext_' + jQuery(this).attr('rel') ).parent().show();
+ $(this).addClass('facetview_open');
+ $('#facetview_' + $(this).attr('rel') ).children().show();
+ $('#facetview_freetext_' + $(this).attr('rel') ).parent().show();
}
}
- // show the advanced functions
- var showadvanced = function(event) {
- event.preventDefault();
- if ( jQuery(this).hasClass('facetview_open') ) {
- jQuery(this).removeClass('facetview_open').siblings().hide();
- } else {
- jQuery(this).addClass('facetview_open').siblings().show();
- }
- }
-
- // limit the filter values available based on text input
- // by running a search with additional filter param and rebuilding filter values
- var limitfilters = function(event) {
- var query = searchquery();
- jQuery('.facetview_freetextfilter').each(function() {
- if ( jQuery(this).val().length > 0 ) {
- if ( query.indexOf("*:*") != -1 ) {
- query = query.replace("*:*","");
- } else {
- query += ' AND ';
- }
- var facet = jQuery(this).attr("id").replace("facetview_freetext_","");
- var terms = jQuery(this).val().split(" ");
- for (var item in terms) {
- if ( terms[item].length > 0 ) {
- query += facet + ':"' + terms[item] + '*" AND ';
- }
+ // function to perform for sorting of filters
+ var sortfilters = function(event) {
+ event.preventDefault()
+ var sortwhat = $(this).attr('href')
+ var which = 0
+ for (item in options.facets) {
+ if ('field' in options.facets[item]) {
+ if ( options.facets[item]['field'] == sortwhat) {
+ which = item
}
}
- });
- query = query.replace(/ AND $/,"");
- jQuery.ajax( {
- type: "get", url: query, dataType: "jsonp", jsonp:"json.wrf", success: function(data) {
- putvalsinfilters(data);
- }
- });
+ }
+ if ( $(this).hasClass('facetview_count') ) {
+ options.facets[which]['order'] = 'count'
+ } else if ( $(this).hasClass('facetview_term') ) {
+ options.facets[which]['order'] = 'term'
+ } else if ( $(this).hasClass('facetview_rcount') ) {
+ options.facets[which]['order'] = 'reverse_count'
+ } else if ( $(this).hasClass('facetview_rterm') ) {
+ options.facets[which]['order'] = 'reverse_term'
+ }
+ dosearch()
}
// pass a list of filters to be displayed
var buildfilters = function() {
- var filters = options.default_filters;
- var thefilters = "<h4>Filters</h4>";
+ var filters = options.facets;
+ var thefilters = "<h3>Filter by</h3>";
for ( var idx in filters ) {
var _filterTmpl = ' \
- <h5> \
- <a class="facetview_filtershow" \
+ <div class="btn-group"> \
+ <a style="text-align:left; min-width:70%;" class="facetview_filtershow btn" \
rel="{{FILTER_NAME}}" href=""> \
- {{FILTER_NAME}}</a> \
- </h5> \
+ <i class="icon-plus"></i> \
+ {{FILTER_DISPLAY}}</a> \
+ <a class="btn dropdown-toggle" data-toggle="dropdown" \
+ href="#"><span class="caret"></span></a> \
+ <ul class="dropdown-menu"> \
+ <li><a class="facetview_sort facetview_count" href="{{FILTER_NAME}}">sort by count</a></li> \
+ <li><a class="facetview_sort facetview_term" href="{{FILTER_NAME}}">sort by term</a></li> \
+ <li><a class="facetview_sort facetview_rcount" href="{{FILTER_NAME}}">sort reverse count</a></li> \
+ <li><a class="facetview_sort facetview_rterm" href="{{FILTER_NAME}}">sort reverse term</a></li> \
+ </ul></div> \
<ul id="facetview_{{FILTER_NAME}}" \
class="facetview_filters"></ul> \
';
- thefilters += _filterTmpl.replace(/{{FILTER_NAME}}/g, filters[idx]);
+ thefilters += _filterTmpl.replace(/{{FILTER_NAME}}/g, filters[idx]['field'].replace(/\./gi,'_'));
+ if ('display' in filters[idx]) {
+ thefilters = thefilters.replace(/{{FILTER_DISPLAY}}/g, filters[idx]['display'])
+ } else {
+ thefilters = thefilters.replace(/{{FILTER_DISPLAY}}/g, filters[idx]['field'])
+ }
}
- $('#facetview_filters').append(thefilters);
- $('.facetview_filtershow').bind('click',showfiltervals);
- $('.facetview_freetextfilter').bindWithDelay('keyup',limitfilters,options.freetext_submit_delay);
- $('.facetview_freetext_filterdiv').hide();
- }
-
- // add a filter when a new one is provided
- var addfilters = function() {
- options.default_filters.push(jQuery(this).val());
- // remove any current filters
- jQuery('#facetview_filters').html("");
- buildfilters();
- dosearch();
+ $('#facetview_filters').append(thefilters)
+ $('.facetview_sort').bind('click',sortfilters)
+ $('.facetview_filtershow').bind('click',showfiltervals)
}
// set the available filter values based on results
var putvalsinfilters = function(data) {
// for each filter setup, find the results for it and append them to the relevant filter
- for ( var each in options.default_filters ) {
- jQuery('#facetview_' + options.default_filters[each]).children().remove();
- var records = data["facets"][ options.default_filters[each] ];
+ for ( var each in options.facets ) {
+ $('#facetview_' + options.facets[each]['field'].replace(/\./gi,'_')).children().remove();
+ var records = data["facets"][ options.facets[each]['field'] ];
for ( var item in records ) {
var append = '<li><a class="facetview_filterchoice' +
- '" rel="' + options.default_filters[each] + '" href="' + item + '">' + item +
+ '" rel="' + options.facets[each]['field'] + '" href="' + item + '">' + item +
' (' + records[item] + ')</a></li>';
- jQuery('#facetview_' + options.default_filters[each]).append(append);
+ $('#facetview_' + options.facets[each]['field'].replace(/\./gi,'_')).append(append);
}
- if ( !jQuery('.facetview_filtershow[rel="' + options.default_filters[each] + '"]').hasClass('facetview_open') ) {
- jQuery('#facetview_' + options.default_filters[each] ).children().hide();
+ if ( !$('.facetview_filtershow[rel="' + options.facets[each]['field'].replace(/\./gi,'_') + '"]').hasClass('facetview_open') ) {
+ $('#facetview_' + options.facets[each]['field'].replace(/\./gi,'_') ).children().hide();
}
}
- //jQuery('.facetview_open').removeClass('facetview_open');
- jQuery('.facetview_filterchoice').bind('click',clickfilterchoice);
+ $('.facetview_filterchoice').bind('click',clickfilterchoice);
+ }
+
+ // ===============================================
+ // functions to do with filter options
+ // ===============================================
+
+ // show the advanced functions
+ var showadvanced = function(event) {
+ event.preventDefault();
+ if ( $(this).hasClass('facetview_open') ) {
+ $(this).removeClass('facetview_open').siblings().hide();
+ } else {
+ $(this).addClass('facetview_open').siblings().show();
+ }
+ }
+
+ // add a filter when a new one is provided
+ var addfilters = function() {
+ options.facets.push({'field':$(this).val()});
+ // remove any current filters
+ $('#facetview_filters').html("");
+ buildfilters();
+ dosearch();
}
// set the user admin filters
@@ -180,8 +246,8 @@ return this.bind(type, data, cb);
var advanceddiv = '<div id="facetview_advanced">' +
'<a class="facetview_advancedshow" href="">ADVANCED ...</a>' +
'<p>add filter:<br /><select id="facetview_addfilters"></select></p></div>';
- jQuery('#facetview_filters').after(advanceddiv);
- jQuery('.facetview_advancedshow').bind('click',showadvanced).siblings().hide();
+ $('#facetview_filters').after(advanceddiv);
+ $('.facetview_advancedshow').bind('click',showadvanced).siblings().hide();
}
// populate the advanced options
@@ -191,13 +257,12 @@ return this.bind(type, data, cb);
for (var item in data["records"][0]) {
options += '<option>' + item + '</option>';
}
- jQuery('#facetview_addfilters').html("");
- jQuery('#facetview_addfilters').append(options);
- jQuery('#facetview_addfilters').change(addfilters);
+ $('#facetview_addfilters').html("");
+ $('#facetview_addfilters').append(options);
+ $('#facetview_addfilters').change(addfilters);
}
-
-
+
// ===============================================
// functions to do with building results
// ===============================================
@@ -223,6 +288,7 @@ return this.bind(type, data, cb);
}
resultobj["facets"][item] = facetsobj;
}
+ } else if ( options.search_index == "bibserver" ) {
} else {
resultobj["records"] = dataobj.response.docs;
resultobj["start"] = dataobj.response.start;
@@ -244,28 +310,12 @@ return this.bind(type, data, cb);
return resultobj;
}
- // write objects to string
- var to_s = function(thing) {
- var s = (thing instanceof Array) ? "[" : "{";
- for (i in thing) {
- if (thing[i] && typeof thing[i] == "object") {
- s += ' "' + i + '":' + to_s(thing[i]) + ', ';
- } else {
- s += (thing instanceof Array) ? "" : '"' + i + '":';
- s += '"' + thing[i] + '", ';
- }
- }
- s += (thing instanceof Array) ? "]" : "}";
- s = s.replace(/, ]/g,"]").replace(/, }/g,"}");
- return s;
- }
-
// decrement result set
var decrement = function(event) {
event.preventDefault();
- options.default_paging.from = parseInt(jQuery(this).attr('href')) - options.default_paging.size;
- if ( options.default_paging.from < 0 ) {
- options.default_paging.from = 0;
+ options.paging.from = parseInt($(this).attr('href')) - options.paging.size;
+ if ( options.paging.from < 0 ) {
+ options.paging.from = 0;
}
dosearch();
}
@@ -273,7 +323,7 @@ return this.bind(type, data, cb);
// increment result set
var increment = function(event) {
event.preventDefault();
- options.default_paging.from = parseInt(jQuery(this).attr('href'));
+ options.paging.from = parseInt($(this).attr('href'));
dosearch();
}
@@ -288,57 +338,69 @@ return this.bind(type, data, cb);
</ul> \
</div> \
';
- var meta = metaTmpl.replace(/{{from}}/g, options.default_paging.from);
- meta = meta.replace(/{{to}}/g, options.default_paging.from+10);
- meta = meta.replace(/{{total}}/g, data.found);
- jQuery('#facetview_metadata').html("").append(meta);
- jQuery('#facetview_decrement').bind('click',decrement);
- jQuery('#facetview_increment').bind('click',increment);
+ $('#facetview_metadata').html("Not found...")
+ if (data.found) {
+ var meta = metaTmpl.replace(/{{from}}/g, options.paging.from + 1);
+ meta = meta.replace(/{{to}}/g, options.paging.from+options.paging.size);
+ meta = meta.replace(/{{total}}/g, data.found);
+ $('#facetview_metadata').html("").append(meta);
+ $('#facetview_decrement').bind('click',decrement);
+ $('#facetview_increment').bind('click',increment);
+ }
}
// given a result record, build how it should look on the page
var buildrecord = function(record) {
- var result = '<div class="facetview_result">';
- var displays = options.result_display_headers
- for (var item in displays) {
- if ( item == 0 ) {
- if ( record[displays[item]] ) {
- result += '<a class="facetview_more" href="">' +
- record[displays[item]] + '</a>';
+ var result = '<tr><td>';
+ result += ' \
+ <div style="float:right;" class="btn-group"> \
+ <a class="btn dropdown-toggle" data-toggle="dropdown" href="#"> \
+ <i class="icon-cog"></i> <span class="caret"></span></a> \
+ <ul class="dropdown-menu"> \
+ <li><a href="">no options yet...</a></li> \
+ </ul> \
+ </div>';
+ var display = options.result_display
+ var lines = ''
+ for (lineitem in display) {
+ line = ""
+ for (object in display[lineitem]) {
+ var thekey = display[lineitem][object]['field']
+ parts = thekey.split('.')
+ // TODO: this should perhaps recurse..
+ if (parts.length == 1) {
+ var res = record
+ } else if (parts.length == 2) {
+ var res = record[parts[0]]
+ }
+ var counter = parts.length - 1
+ if (res && res.constructor.toString().indexOf("Array") == -1) {
+ var thevalue = res[parts[counter]] // if this is a dict
} else {
- result += '<a class="facetview_more" href="">UNKNOWN ITEM</a>';
- }
- } else {
- if ( record[displays[item]] ) {
- result += '<div class="facetview_resultextra">' +
- record[displays[item]] + '</div>';
+ var thevalue = []
+ for (var row in res) {
+ thevalue.push(res[row][parts[counter]])
+ }
+ }
+ if (thevalue) {
+ display[lineitem][object]['pre']
+ ? line += display[lineitem][object]['pre'] : false
+ line += thevalue
+ display[lineitem][object]['post']
+ ? line += display[lineitem][object]['post'] : false
+ line += ' '
}
}
- }
- result += '<table class="facetview_moreinfo">';
- for ( var each in record ) {
- if ( jQuery.inArray(each,options.ignore_fields) == -1 ) {
- result += '<tr><td class="facetview_moretabletitle">' +
- each + '</td>' + '<td class="facetview_fixed">' + record[each] + '</td></tr>';
+ if (line) {
+ lines += line.replace(/^\s/,'').replace(/\s$/,'').replace(/\,$/,'') + "<br />"
}
}
- result += '</table>';
+ lines ? result += lines : result += 'unidentified item'
+ result += '</td></tr>'
return result;
}
- // show more details of an event, and trigger the book search
- var showmore = function(event) {
- event.preventDefault();
- if ( !jQuery(this).hasClass('facetview_open') ) {
- jQuery(this).addClass('facetview_open').siblings().show();
- jQuery(this).siblings('.facetview_resultextra').hide();
- } else {
- jQuery(this).removeClass('facetview_open').siblings().not('.facetview_resultextra').hide();
- jQuery(this).siblings('.facetview_resultextra').show();
- }
- }
-
// put the results on the page
showresults = function(sdata) {
// get the data and parse from the solr / es layout
@@ -350,16 +412,21 @@ return this.bind(type, data, cb);
// populate the advanced options
populateadvanced(data);
// put the filtered results on the page
- jQuery('#facetview_results').html("");
+ $('#facetview_results').html("");
var infofiltervals = new Array();
- jQuery.each(data.records, function(index, value) {
+ $.each(data.records, function(index, value) {
// write them out to the results div
- jQuery('#facetview_results').append( buildrecord(value) );
+ $('#facetview_results').append( buildrecord(value) );
});
// bind the more action to show the hidden details
- jQuery('.facetview_more').bind('click',showmore);
+ $('.facetview_more').bind('click',showmore);
}
+ // show more details of an event, and trigger the book search
+ var showmore = function(event) {
+ event.preventDefault();
+ alert("show record view options")
+ }
// ===============================================
// functions to do with searching
@@ -374,29 +441,29 @@ return this.bind(type, data, cb);
}
// do paging params
var pageparams = "";
- for (var item in options.default_paging) {
- pageparams += item + "=" + options.default_paging[item] + "&";
+ for (var item in options.paging) {
+ pageparams += item + "=" + options.paging[item] + "&";
}
// set facet params
var urlfilters = "";
- for (var item in options.default_filters) {
- urlfilters += "facet.field=" + options.default_filters[item] + "&";
+ for (var item in options.facets) {
+ urlfilters += "facet.field=" + options.facets[item]['field'] + "&";
}
// build starting URL
var theurl = options.search_url + urlparams + pageparams + urlfilters + options.query_parameter + "=";
// add default query values
// build the query, starting with default values
var query = "";
- for (var item in options.predefined_query_values) {
- query += item + ":" + options.predefined_query_values[item] + " AND ";
+ for (var item in options.predefined_filters) {
+ query += item + ":" + options.predefined_filters[item] + " AND ";
}
- jQuery('.facetview_filterselected',obj).each(function() {
- query += jQuery(this).attr('rel') + ':"' +
- jQuery(this).attr('href') + '" AND ';
+ $('.facetview_filterselected',obj).each(function() {
+ query += $(this).attr('rel') + ':"' +
+ $(this).attr('href') + '" AND ';
});
// add any freetext filter
- if (jQuery('#facetview_freetext').val() != "") {
- query += jQuery('#facetview_freetext').val() + '*';
+ if ($('#facetview_freetext').val() != "") {
+ query += $('#facetview_freetext').val() + '*';
}
query = query.replace(/ AND $/,"");
// set a default for blank search
@@ -409,46 +476,47 @@ return this.bind(type, data, cb);
// build the search query URL based on current params
var elasticsearchquery = function() {
- // build the query, starting with default values
- var query = "";
- for (var item in options.predefined_query_values) {
- query += item + ":" + options.predefined_query_values[item] + " AND ";
- }
- jQuery('.facetview_filterselected',obj).each(function() {
- query += jQuery(this).attr('rel') + ':' +
- jQuery(this).attr('href').replace(/:/g,"_") + ' AND ';
+ var qs = {}
+ var bool = false
+ $('.facetview_filterselected',obj).each(function() {
+ !bool ? bool = {'must': [] } : ""
+ var obj = {'term':{}}
+ obj['term'][ $(this).attr('rel') ] = $(this).attr('href')
+ bool['must'].push(obj)
});
- // add any freetext filter
- if (jQuery('#facetview_freetext').val() != "") {
- query += jQuery('#facetview_freetext').val() + '*';
- }
- query = query.replace(/ AND $/,"");
- var querystring = '{';
- if ( options.default_paging.from != 0 ) {
- querystring += '"from":' + options.default_paging.from + ',';
+ for (var item in options.predefined_filters) {
+ !bool ? bool = {'must': [] } : ""
+ var obj = {'term': {}}
+ obj['term'][ item ] = options.predefined_filters[item]
+ bool['must'].push(obj)
}
- if ( options.default_paging.size != 10 ) {
- querystring += '"size":' + options.default_paging.size + ',';
- }
- // set a default for blank search
- if (query == "") {
- querystring += '"query":{"match_all":{}}';
+ if (bool) {
+ $('#facetview_freetext').val() != ""
+ ? bool['must'].push( {'query_string': { 'query': $('#facetview_freetext').val() } } )
+ : ""
+ qs['query'] = {'bool': bool}
} else {
- querystring += '"query":{"query_string":{"query":"' + query + '"}}';
+ $('#facetview_freetext').val() != ""
+ ? qs['query'] = {'query_string': { 'query': $('#facetview_freetext').val() } }
+ : qs['query'] = {'match_all': {}}
}
- querystring += ',"facets":{';
- for (var item in options.default_filters) {
- querystring += '"' + options.default_filters[item] + '":{"terms":{"field":"' + options.default_filters[item] + '","size":200,"order":"term"}},';
+ // set any paging
+ options.paging.from != 0 ? qs['from'] = options.paging.from : ""
+ options.paging.size != 10 ? qs['size'] = options.paging.size : ""
+ // set any facets
+ qs['facets'] = {};
+ for (var item in options.facets) {
+ var obj = options.facets[item]
+ delete obj['display']
+ qs['facets'][obj['field']] = {"terms":obj}
}
- querystring = querystring.replace(/\,$/,"");
- querystring += '}}';
- return querystring;
+ return JSON.stringify(qs)
}
// execute a search
var dosearch = function() {
if ( options.search_index == "elasticsearch" ) {
- jQuery.ajax({
+ $.ajax({
type: "get",
url: options.search_url,
data: {source: elasticsearchquery()},
@@ -457,50 +525,138 @@ return this.bind(type, data, cb);
success: showresults
});
} else {
- jQuery.ajax( { type: "get", url: solrsearchquery(), dataType:"jsonp", jsonp:"json.wrf", success: function(data) { showresults(data) } } );
+ $.ajax( { type: "get", url: solrsearchquery(), dataType:"jsonp", jsonp:"json.wrf", success: function(data) { showresults(data) } } );
}
}
// trigger a search when a filter choice is clicked
var clickfilterchoice = function(event) {
event.preventDefault();
- var newobj = '<li><a class="facetview_filterselected" rel="' +
- jQuery(this).attr("rel") + '" href="' + jQuery(this).attr("href") + '">' +
- jQuery(this).html() + '</a><a class="facetview_clear" href="">x</a></li>';
- jQuery('#facetview_selectedfilters').append(newobj);
- jQuery('.facetview_clear').unbind('click',clearfilter);
- jQuery('.facetview_clear').bind('click',clearfilter);
+ var newobj = '<a class="facetview_filterselected facetview_clear ' +
+ 'btn btn-info" rel="' + $(this).attr("rel") +
+ '" alt="remove" title="remove"' +
+ ' href="' + $(this).attr("href") + '">' +
+ $(this).html().replace(/\(.*\)/,'') + ' <i class="icon-remove"></i></a>';
+ $('#facetview_selectedfilters').append(newobj);
+ $('.facetview_filterselected').unbind('click',clearfilter);
+ $('.facetview_filterselected').bind('click',clearfilter);
+ options.paging.from = 0
dosearch();
}
// clear a filter when clear button is pressed, and re-do the search
var clearfilter = function(event) {
event.preventDefault();
- if ( jQuery(this).attr('id') == "facetview_clearall" ) {
- jQuery('#facetview_freetext',obj).val("");
- } else {
- jQuery(this).parent().remove();
- }
+ $(this).remove();
dosearch();
}
+ // do search options
+ var fixmatch = function(event) {
+ event.preventDefault();
+ if ( $(this).attr('id') == "facetview_partial_match" ) {
+ var newvals = $('#facetview_freetext').val().replace(/"/gi,'').replace(/\*/gi,'').replace(/\~/gi,'').split(' ');
+ var newstring = "";
+ for (item in newvals) {
+ if (newvals[item].length > 0 && newvals[item] != ' ') {
+ if (newvals[item] == 'OR' || newvals[item] == 'AND') {
+ newstring += newvals[item] + ' ';
+ } else {
+ newstring += '*' + newvals[item] + '* ';
+ }
+ }
+ }
+ $('#facetview_freetext').val(newstring);
+ } else if ( $(this).attr('id') == "facetview_fuzzy_match" ) {
+ var newvals = $('#facetview_freetext').val().replace(/"/gi,'').replace(/\*/gi,'').replace(/\~/gi,'').split(' ');
+ var newstring = "";
+ for (item in newvals) {
+ if (newvals[item].length > 0 && newvals[item] != ' ') {
+ if (newvals[item] == 'OR' || newvals[item] == 'AND') {
+ newstring += newvals[item] + ' ';
+ } else {
+ newstring += newvals[item] + '~ ';
+ }
+ }
+ }
+ $('#facetview_freetext').val(newstring);
+ } else if ( $(this).attr('id') == "facetview_exact_match" ) {
+ var newvals = $('#facetview_freetext').val().replace(/"/gi,'').replace(/\*/gi,'').replace(/\~/gi,'').split(' ');
+ var newstring = "";
+ for (item in newvals) {
+ if (newvals[item].length > 0 && newvals[item] != ' ') {
+ if (newvals[item] == 'OR' || newvals[item] == 'AND') {
+ newstring += newvals[item] + ' ';
+ } else {
+ newstring += '"' + newvals[item] + '" ';
+ }
+ }
+ }
+ $.trim(newstring,' ');
+ $('#facetview_freetext').val(newstring);
+ } else if ( $(this).attr('id') == "facetview_match_all" ) {
+ $('#facetview_freetext').val($.trim($('#facetview_freetext').val().replace(/ OR /gi,' ')));
+ $('#facetview_freetext').val($('#facetview_freetext').val().replace(/ /gi,' AND '));
+ } else if ( $(this).attr('id') == "facetview_match_any" ) {
+ $('#facetview_freetext').val($.trim($('#facetview_freetext').val().replace(/ AND /gi,' ')));
+ $('#facetview_freetext').val($('#facetview_freetext').val().replace(/ /gi,' OR '));
+ }
+ $('#facetview_freetext').focus().trigger('keyup');
+ }
+
+
+ // adjust how many results are shown
+ var howmany = function(event) {
+ event.preventDefault()
+ var newhowmany = prompt('Currently displaying ' + options.paging.size +
+ ' results per page. How many would you like instead?')
+ if (newhowmany) {
+ options.paging.size = parseInt(newhowmany)
+ options.paging.from = 0
+ dosearch()
+ }
+ }
// the facet view object to be appended to the page
var thefacetview = ' \
<div id="facetview"> \
- <form method="GET" action="#search"> \
- <input id="facetview_freetext" name="q" value="" placeholder="search term" autofocus > \
- <ul id="facetview_selectedfilters"></ul> \
- </form> \
- <div class="row"> \
- <div class="span4 facets" id="facetview_filters"></div> \
- <div class="span12 results"> \
- <div id="facetview_results"></div> \
- <div id="facetview_metadata"></div> \
- </div> \
- </div> \
- </div> \
- ';
+ <div class="row-fluid"> \
+ <div class="span3"> \
+ <div id="facetview_filters"></div> \
+ </div> \
+ <div class="span9"> \
+ <form method="GET" action="#search"> \
+ <div id="facetview_searchbar" style="display:inline; float:left;" class="input-prepend"> \
+ <span class="add-on"><i class="icon-search"></i></span> \
+ <input class="span4" id="facetview_freetext" name="q" value="" placeholder="search term" autofocus /> \
+ </div> \
+ <div style="display:inline; float:left;margin-left:-2px;" class="btn-group"> \
+ <a style="-moz-border-radius:0px 3px 3px 0px; \
+ -webkit-border-radius:0px 3px 3px 0px; border-radius:0px 3px 3px 0px;" \
+ class="btn dropdown-toggle" data-toggle="dropdown" href="#"> \
+ <i class="icon-cog"></i> <span class="caret"></span></a> \
+ <ul class="dropdown-menu"> \
+ <li><a id="facetview_partial_match" href="">partial match</a></li> \
+ <li><a id="facetview_exact_match" href="">exact match</a></li> \
+ <li><a id="facetview_fuzzy_match" href="">fuzzy match</a></li> \
+ <li><a id="facetview_match_all" href="">match all</a></li> \
+ <li><a id="facetview_match_any" href="">match any</a></li> \
+ <li><a href="#">clear all</a></li> \
+ <li><a target="_blank" \
+ href="http://lucene.apache.org/java/2_9_1/queryparsersyntax.html"> \
+ learn more</a></li> \
+ <li class="divider"></li> \
+ <li><a id="facetview_howmany" href="#">pagination: {{HOW_MANY}}</a></li> \
+ </ul> \
+ </div> \
+ <div style="clear:both;" id="facetview_selectedfilters"></div> \
+ </form> \
+ <table class="table table-striped" id="facetview_results"></table> \
+ <div id="facetview_metadata"></div> \
+ </div> \
+ </div> \
+ </div> \
+ ';
// ===============================================
@@ -510,15 +666,29 @@ return this.bind(type, data, cb);
obj = $(this);
// append the facetview object to this object
+ thefacetview = thefacetview.replace(/{{HOW_MANY}}/gi,options.paging.size)
$(obj).append(thefacetview);
+ // setup search option triggers
+ $('#facetview_partial_match').bind('click',fixmatch)
+ $('#facetview_exact_match').bind('click',fixmatch)
+ $('#facetview_fuzzy_match').bind('click',fixmatch)
+ $('#facetview_match_any').bind('click',fixmatch)
+ $('#facetview_match_all').bind('click',fixmatch)
+ $('#facetview_howmany').bind('click',howmany)
+
+ // resize the searchbar
+ var thewidth = $('#facetview_searchbar').parent().parent().width()
+ $('#facetview_searchbar').css('width',thewidth - 50 + 'px')
+ $('#facetview_freetext').css('width', thewidth - 88 + 'px')
+
// append the filters to the facetview object
buildfilters();
+ if (options.description) {
+ $('#facetview_filters').append('<div><h3>Meta</h3>' + options.description + '</div>')
+ }
$('#facetview_freetext',obj).bindWithDelay('keyup',dosearch,options.freetext_submit_delay);
- // add userconfig functions
- options.show_advanced ? advanced() : "";
-
// trigger the search once on load, to get all results
dosearch();
View
49 simple.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8" />
+ <title>FacetView</title>
+
+ <script type="text/javascript" src="vendor/jquery/1.7.1/jquery-1.7.1.min.js"></script>
+ <script type="text/javascript" src="jquery.facetview.js"></script>
+
+ <link rel="stylesheet" href="vendor/bootstrap/css/bootstrap.min.css">
+ <script type="text/javascript" src="vendor/bootstrap/js/bootstrap.min.js"></script>
+
+ <link rel="stylesheet" href="css/facetview.css">
+
+ <script type="text/javascript">
+jQuery(document).ready(function($) {
+ $('.facet-view-simple').facetview({
+ search_url: 'http://bibsoup.net/query?',
+ search_index: 'elasticsearch',
+ facets: [
+ {'field': 'publisher.exact', 'size': 100, 'order':'term', 'display': 'publisher'},
+ {'field': 'author.name.exact', 'display': 'author'},
+ {'field': 'year.exact', 'display': 'year'}
+ ],
+ paging: {
+ size: 10
+ },
+ predefined_filters: {
+ 'owner.exact': 'test'
+ }
+ });
+});
+ </script>
+
+<style type="text/css">
+.facet-view-simple{
+ width:800px;
+ height:600px;
+ margin:20px auto 0 auto;
+}
+</style>
+
+</head>
+<body>
+
+ <div class="facet-view-simple"></div>
+
+</body>
+</html>
View
4,067 vendor/bootstrap/css/bootstrap.css
@@ -0,0 +1,4067 @@
+/*!
+ * Bootstrap v2.0.0
+ *
+ * Copyright 2012 Twitter, Inc
+ * Licensed under the Apache License v2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Designed and built with all the love in the world @twitter by @mdo and @fat.
+ */
+.clearfix {
+ *zoom: 1;
+}
+.clearfix:before, .clearfix:after {
+ display: table;
+ content: "";
+}
+.clearfix:after {
+ clear: both;
+}
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+nav,
+section {
+ display: block;
+}
+audio, canvas, video {
+ display: inline-block;
+ *display: inline;
+ *zoom: 1;
+}
+audio:not([controls]) {
+ display: none;
+}
+html {
+ font-size: 100%;
+ -webkit-text-size-adjust: 100%;
+ -ms-text-size-adjust: 100%;
+}
+a:focus {
+ outline: thin dotted #333;
+ outline: 5px auto -webkit-focus-ring-color;
+ outline-offset: -2px;
+}
+a:hover, a:active {
+ outline: 0;
+}
+sub, sup {
+ position: relative;
+ font-size: 75%;
+ line-height: 0;
+ vertical-align: baseline;
+}
+sup {
+ top: -0.5em;
+}
+sub {
+ bottom: -0.25em;
+}
+img {
+ max-width: 100%;
+ height: auto;
+ border: 0;
+ -ms-interpolation-mode: bicubic;
+}
+button,
+input,
+select,
+textarea {
+ margin: 0;
+ font-size: 100%;
+ vertical-align: middle;
+}
+button, input {
+ *overflow: visible;
+ line-height: normal;
+}
+button::-moz-focus-inner, input::-moz-focus-inner {
+ padding: 0;
+ border: 0;
+}
+button,
+input[type="button"],
+input[type="reset"],
+input[type="submit"] {
+ cursor: pointer;
+ -webkit-appearance: button;
+}
+input[type="search"] {
+ -webkit-appearance: textfield;
+ -webkit-box-sizing: content-box;
+ -moz-box-sizing: content-box;
+ box-sizing: content-box;
+}
+input[type="search"]::-webkit-search-decoration, input[type="search"]::-webkit-search-cancel-button {
+ -webkit-appearance: none;
+}
+textarea {
+ overflow: auto;
+ vertical-align: top;
+}
+body {
+ margin: 0;
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+ font-size: 13px;
+ line-height: 18px;
+ color: #333333;
+ background-color: #ffffff;
+}
+a {
+ color: #0088cc;
+ text-decoration: none;
+}
+a:hover {
+ color: #005580;
+ text-decoration: underline;
+}
+.row {
+ margin-left: -20px;
+ *zoom: 1;
+}
+.row:before, .row:after {
+ display: table;
+ content: "";
+}
+.row:after {
+ clear: both;
+}
+[class*="span"] {
+ float: left;
+ margin-left: 20px;
+}
+.span1 {
+ width: 60px;
+}
+.span2 {
+ width: 140px;
+}
+.span3 {
+ width: 220px;
+}
+.span4 {
+ width: 300px;
+}
+.span5 {
+ width: 380px;
+}
+.span6 {
+ width: 460px;
+}
+.span7 {
+ width: 540px;
+}
+.span8 {
+ width: 620px;
+}
+.span9 {
+ width: 700px;
+}
+.span10 {
+ width: 780px;
+}
+.span11 {
+ width: 860px;
+}
+.span12, .container {
+ width: 940px;
+}
+.offset1 {
+ margin-left: 100px;
+}
+.offset2 {
+ margin-left: 180px;
+}
+.offset3 {
+ margin-left: 260px;
+}
+.offset4 {
+ margin-left: 340px;
+}
+.offset5 {
+ margin-left: 420px;
+}
+.offset6 {
+ margin-left: 500px;
+}
+.offset7 {
+ margin-left: 580px;
+}
+.offset8 {
+ margin-left: 660px;
+}
+.offset9 {
+ margin-left: 740px;
+}
+.offset10 {
+ margin-left: 820px;
+}
+.offset11 {
+ margin-left: 900px;
+}
+.row-fluid {
+ width: 100%;
+ *zoom: 1;
+}
+.row-fluid:before, .row-fluid:after {
+ display: table;
+ content: "";
+}
+.row-fluid:after {
+ clear: both;
+}
+.row-fluid > [class*="span"] {
+ float: left;
+ margin-left: 2.127659574%;
+}
+.row-fluid > [class*="span"]:first-child {
+ margin-left: 0;
+}
+.row-fluid > .span1 {
+ width: 6.382978723%;
+}
+.row-fluid > .span2 {
+ width: 14.89361702%;
+}
+.row-fluid > .span3 {
+ width: 23.404255317%;
+}
+.row-fluid > .span4 {
+ width: 31.914893614%;
+}
+.row-fluid > .span5 {
+ width: 40.425531911%;
+}
+.row-fluid > .span6 {
+ width: 48.93617020799999%;
+}
+.row-fluid > .span7 {
+ width: 57.446808505%;
+}
+.row-fluid > .span8 {
+ width: 65.95744680199999%;
+}
+.row-fluid > .span9 {
+ width: 74.468085099%;
+}
+.row-fluid > .span10 {
+ width: 82.97872339599999%;
+}
+.row-fluid > .span11 {
+ width: 91.489361693%;
+}
+.row-fluid > .span12 {
+ width: 99.99999998999999%;
+}
+.container {
+ width: 940px;
+ margin-left: auto;
+ margin-right: auto;
+ *zoom: 1;
+}
+.container:before, .container:after {
+ display: table;
+ content: "";
+}
+.container:after {
+ clear: both;
+}
+.container-fluid {
+ padding-left: 20px;
+ padding-right: 20px;
+ *zoom: 1;
+}
+.container-fluid:before, .container-fluid:after {
+ display: table;
+ content: "";
+}
+.container-fluid:after {
+ clear: both;
+}
+p {
+ margin: 0 0 9px;
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+ font-size: 13px;
+ line-height: 18px;
+}
+p small {
+ font-size: 11px;
+ color: #999999;
+}
+.lead {
+ margin-bottom: 18px;
+ font-size: 20px;
+ font-weight: 200;
+ line-height: 27px;
+}
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ margin: 0;
+ font-weight: bold;
+ color: #333333;
+ text-rendering: optimizelegibility;
+}
+h1 small,
+h2 small,
+h3 small,
+h4 small,
+h5 small,
+h6 small {
+ font-weight: normal;
+ color: #999999;
+}
+h1 {
+ font-size: 30px;
+ line-height: 36px;
+}
+h1 small {
+ font-size: 18px;
+}
+h2 {
+ font-size: 24px;
+ line-height: 36px;
+}
+h2 small {
+ font-size: 18px;
+}
+h3 {
+ line-height: 27px;
+ font-size: 18px;
+}
+h3 small {
+ font-size: 14px;
+}
+h4, h5, h6 {
+ line-height: 18px;
+}
+h4 {
+ font-size: 14px;
+}
+h4 small {
+ font-size: 12px;
+}
+h5 {
+ font-size: 12px;
+}
+h6 {
+ font-size: 11px;
+ color: #999999;
+ text-transform: uppercase;
+}
+.page-header {
+ padding-bottom: 17px;
+ margin: 18px 0;
+ border-bottom: 1px solid #eeeeee;
+}
+.page-header h1 {
+ line-height: 1;
+}
+ul, ol {
+ padding: 0;
+ margin: 0 0 9px 25px;
+}
+ul ul,
+ul ol,
+ol ol,
+ol ul {
+ margin-bottom: 0;
+}
+ul {
+ list-style: disc;
+}
+ol {
+ list-style: decimal;
+}
+li {
+ line-height: 18px;
+}
+ul.unstyled, ol.unstyled {
+ margin-left: 0;
+ list-style: none;
+}
+dl {
+ margin-bottom: 18px;
+}
+dt, dd {
+ line-height: 18px;
+}
+dt {
+ font-weight: bold;
+}
+dd {
+ margin-left: 9px;
+}
+hr {
+ margin: 18px 0;
+ border: 0;
+ border-top: 1px solid #eeeeee;
+ border-bottom: 1px solid #ffffff;
+}
+strong {
+ font-weight: bold;
+}
+em {
+ font-style: italic;
+}
+.muted {
+ color: #999999;
+}
+abbr {
+ font-size: 90%;
+ text-transform: uppercase;
+ border-bottom: 1px dotted #ddd;
+ cursor: help;
+}
+blockquote {
+ padding: 0 0 0 15px;
+ margin: 0 0 18px;
+ border-left: 5px solid #eeeeee;
+}
+blockquote p {
+ margin-bottom: 0;
+ font-size: 16px;
+ font-weight: 300;
+ line-height: 22.5px;
+}
+blockquote small {
+ display: block;
+ line-height: 18px;
+ color: #999999;
+}
+blockquote small:before {
+ content: '\2014 \00A0';
+}
+blockquote.pull-right {
+ float: right;
+ padding-left: 0;
+ padding-right: 15px;
+ border-left: 0;
+ border-right: 5px solid #eeeeee;
+}
+blockquote.pull-right p, blockquote.pull-right small {
+ text-align: right;
+}
+q:before,
+q:after,
+blockquote:before,
+blockquote:after {
+ content: "";
+}
+address {
+ display: block;
+ margin-bottom: 18px;
+ line-height: 18px;
+ font-style: normal;
+}
+small {
+ font-size: 100%;
+}
+cite {
+ font-style: normal;
+}
+code, pre {
+ padding: 0 3px 2px;
+ font-family: Menlo, Monaco, "Courier New", monospace;
+ font-size: 12px;
+ color: #333333;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+}
+code {
+ padding: 3px 4px;
+ color: #d14;
+ background-color: #f7f7f9;
+ border: 1px solid #e1e1e8;
+}
+pre {
+ display: block;
+ padding: 8.5px;
+ margin: 0 0 9px;
+ font-size: 12px;
+ line-height: 18px;
+ background-color: #f5f5f5;
+ border: 1px solid #ccc;
+ border: 1px solid rgba(0, 0, 0, 0.15);
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+ white-space: pre;
+ white-space: pre-wrap;
+ word-break: break-all;
+ word-wrap: break-word;
+}
+pre.prettyprint {
+ margin-bottom: 18px;
+}
+pre code {
+ padding: 0;
+ color: inherit;
+ background-color: transparent;
+ border: 0;
+}
+.pre-scrollable {
+ max-height: 340px;
+ overflow-y: scroll;
+}
+.label {
+ padding: 2px 4px 3px;
+ font-size: 11.049999999999999px;
+ font-weight: bold;
+ color: #ffffff;
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+ background-color: #999999;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+}
+.label:hover {
+ color: #ffffff;
+ text-decoration: none;
+}
+.label-important {
+ background-color: #b94a48;
+}
+.label-important:hover {
+ background-color: #953b39;
+}
+.label-warning {
+ background-color: #f89406;
+}
+.label-warning:hover {
+ background-color: #c67605;
+}
+.label-success {
+ background-color: #468847;
+}
+.label-success:hover {
+ background-color: #356635;
+}
+.label-info {
+ background-color: #3a87ad;
+}
+.label-info:hover {
+ background-color: #2d6987;
+}
+table {
+ max-width: 100%;
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+.table {
+ width: 100%;
+ margin-bottom: 18px;
+}
+.table th, .table td {
+ padding: 8px;
+ line-height: 18px;
+ text-align: left;
+ vertical-align: top;
+ border-top: 1px solid #ddd;
+}
+.table th {
+ font-weight: bold;
+}
+.table thead th {
+ vertical-align: bottom;
+}
+.table thead:first-child tr th, .table thead:first-child tr td {
+ border-top: 0;
+}
+.table tbody + tbody {
+ border-top: 2px solid #ddd;
+}
+.table-condensed th, .table-condensed td {
+ padding: 4px 5px;
+}
+.table-bordered {
+ border: 1px solid #ddd;
+ border-collapse: separate;
+ *border-collapse: collapsed;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+}
+.table-bordered th + th,
+.table-bordered td + td,
+.table-bordered th + td,
+.table-bordered td + th {
+ border-left: 1px solid #ddd;
+}
+.table-bordered thead:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child td {
+ border-top: 0;
+}
+.table-bordered thead:first-child tr:first-child th:first-child, .table-bordered tbody:first-child tr:first-child td:first-child {
+ -webkit-border-radius: 4px 0 0 0;
+ -moz-border-radius: 4px 0 0 0;
+ border-radius: 4px 0 0 0;
+}
+.table-bordered thead:first-child tr:first-child th:last-child, .table-bordered tbody:first-child tr:first-child td:last-child {
+ -webkit-border-radius: 0 4px 0 0;
+ -moz-border-radius: 0 4px 0 0;
+ border-radius: 0 4px 0 0;
+}
+.table-bordered thead:last-child tr:last-child th:first-child, .table-bordered tbody:last-child tr:last-child td:first-child {
+ -webkit-border-radius: 0 0 0 4px;
+ -moz-border-radius: 0 0 0 4px;
+ border-radius: 0 0 0 4px;
+}
+.table-bordered thead:last-child tr:last-child th:last-child, .table-bordered tbody:last-child tr:last-child td:last-child {
+ -webkit-border-radius: 0 0 4px 0;
+ -moz-border-radius: 0 0 4px 0;
+ border-radius: 0 0 4px 0;
+}
+.table-striped tbody tr:nth-child(odd) td, .table-striped tbody tr:nth-child(odd) th {
+ background-color: #f9f9f9;
+}
+.table tbody tr:hover td, .table tbody tr:hover th {
+ background-color: #f5f5f5;
+}
+table .span1 {
+ float: none;
+ width: 44px;
+ margin-left: 0;
+}
+table .span2 {
+ float: none;
+ width: 124px;
+ margin-left: 0;
+}
+table .span3 {
+ float: none;
+ width: 204px;
+ margin-left: 0;
+}
+table .span4 {
+ float: none;
+ width: 284px;
+ margin-left: 0;
+}
+table .span5 {
+ float: none;
+ width: 364px;
+ margin-left: 0;
+}
+table .span6 {
+ float: none;
+ width: 444px;
+ margin-left: 0;
+}
+table .span7 {
+ float: none;
+ width: 524px;
+ margin-left: 0;
+}
+table .span8 {
+ float: none;
+ width: 604px;
+ margin-left: 0;
+}
+table .span9 {
+ float: none;
+ width: 684px;
+ margin-left: 0;
+}
+table .span10 {
+ float: none;
+ width: 764px;
+ margin-left: 0;
+}
+table .span11 {
+ float: none;
+ width: 844px;
+ margin-left: 0;