Merge branch 'master' into gh-pages
This commit is contained in:
@@ -20,29 +20,31 @@
|
|||||||
|
|
||||||
.header .recline-query-editor {
|
.header .recline-query-editor {
|
||||||
float: right;
|
float: right;
|
||||||
margin: 4px;
|
height: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header .recline-query-editor label {
|
.header .recline-query-editor .input-prepend {
|
||||||
float: none;
|
margin-bottom: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header .recline-query-editor label {
|
.header .recline-query-editor .text-query input {
|
||||||
float: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header .recline-query-editor input.text-query {
|
|
||||||
float: left;
|
float: left;
|
||||||
margin-top: 1px;
|
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header .recline-query-editor .pagination input {
|
.header .recline-query-editor .pagination input {
|
||||||
width: 30px;
|
width: 30px;
|
||||||
|
height: 18px;
|
||||||
|
padding: 2px 4px;
|
||||||
|
margin-top: -4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header .recline-query-editor .pagination a {
|
.header .recline-query-editor .pagination a {
|
||||||
line-height: 28px;
|
line-height: 26px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header .recline-query-editor form .btn {
|
||||||
|
vertical-align: top;
|
||||||
}
|
}
|
||||||
|
|
||||||
.data-view-container {
|
.data-view-container {
|
||||||
@@ -50,96 +52,15 @@
|
|||||||
clear: both;
|
clear: both;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* bootstrap btn */
|
|
||||||
.btn {
|
|
||||||
cursor: pointer;
|
|
||||||
display: inline-block;
|
|
||||||
background-color: #e6e6e6;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), color-stop(25%, #ffffff), to(#e6e6e6));
|
|
||||||
background-image: -webkit-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);
|
|
||||||
background-image: -moz-linear-gradient(top, #ffffff, #ffffff 25%, #e6e6e6);
|
|
||||||
background-image: -ms-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);
|
|
||||||
background-image: -o-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);
|
|
||||||
background-image: linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);
|
|
||||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);
|
|
||||||
padding: 5px 14px 6px;
|
|
||||||
text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
|
|
||||||
color: #333;
|
|
||||||
font-size: 13px;
|
|
||||||
line-height: normal;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
border-bottom-color: #bbb;
|
|
||||||
-webkit-border-radius: 4px;
|
|
||||||
-moz-border-radius: 4px;
|
|
||||||
border-radius: 4px;
|
|
||||||
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
|
|
||||||
-moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
|
|
||||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
|
|
||||||
-webkit-transition: 0.1s linear all;
|
|
||||||
-moz-transition: 0.1s linear all;
|
|
||||||
-ms-transition: 0.1s linear all;
|
|
||||||
-o-transition: 0.1s linear all;
|
|
||||||
transition: 0.1s linear all;
|
|
||||||
}
|
|
||||||
.btn:hover {
|
|
||||||
background-position: 0 -15px;
|
|
||||||
color: #333;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
.btn:focus {
|
|
||||||
outline: 1px dotted #666;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* twitter btn.disabled but for button link that is active. used in navigation */
|
|
||||||
.active .btn {
|
|
||||||
cursor: default;
|
|
||||||
background-image: none;
|
|
||||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
|
||||||
filter: alpha(opacity=65);
|
|
||||||
-khtml-opacity: 0.65;
|
|
||||||
-moz-opacity: 0.65;
|
|
||||||
opacity: 0.65;
|
|
||||||
-webkit-box-shadow: none;
|
|
||||||
-moz-box-shadow: none;
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**********************************************************
|
/**********************************************************
|
||||||
* Notifications
|
* Notifications
|
||||||
*********************************************************/
|
*********************************************************/
|
||||||
|
|
||||||
.notification-container {
|
|
||||||
width: 400px;
|
|
||||||
left: 520px;
|
|
||||||
display: none;
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
z-index: 100;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.notification {
|
|
||||||
display: inline-block;
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 5px 8px 4px;
|
|
||||||
font-size: 1.3em;
|
|
||||||
text-align: left;
|
|
||||||
font-weight: bold;
|
|
||||||
background: #fe8;
|
|
||||||
-moz-border-radius: 2px;
|
|
||||||
-webkit-border-radius: 2px;
|
|
||||||
border-radius: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.notification-action {
|
|
||||||
padding-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.notification-loader {
|
.notification-loader {
|
||||||
padding: 0 3px 0 0;
|
width: 18px;
|
||||||
opacity: 0.3;
|
margin-left: 5px;
|
||||||
|
background: url(images/small-spinner.gif) no-repeat;
|
||||||
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -155,11 +76,13 @@
|
|||||||
.data-table {
|
.data-table {
|
||||||
border: 1px solid #ccc;
|
border: 1px solid #ccc;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.data-table td, .data-table th {
|
.data-table td, .data-table th {
|
||||||
border-left: 1px solid #ccc;
|
border-left: 1px solid #ccc;
|
||||||
padding: 3px 4px;
|
padding: 3px 4px;
|
||||||
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.data-table tr td:first-child, .data-table tr th:first-child {
|
.data-table tr td:first-child, .data-table tr th:first-child {
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
56
demo/built.html
Normal file
56
demo/built.html
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>Recline Data Explorer Demo</title>
|
||||||
|
<meta name="description" content="A demo of the Recline Data Explorer">
|
||||||
|
<meta name="author" content="Rufus Pollock and Max Ogden">
|
||||||
|
|
||||||
|
<!-- Le HTML5 shim, for IE6-8 support of HTML elements -->
|
||||||
|
<!--[if lt IE 9]>
|
||||||
|
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
|
||||||
|
<![endif]-->
|
||||||
|
<link rel="stylesheet" href="../vendor/bootstrap/2.0.0/css/bootstrap.css">
|
||||||
|
<link rel="stylesheet" href="../css/data-explorer.css">
|
||||||
|
<link rel="stylesheet" href="../css/graph-flot.css">
|
||||||
|
<link rel="stylesheet" href="../css/bootstrap.css">
|
||||||
|
|
||||||
|
<script type="text/javascript" src="../vendor/jquery-1.7.1.js"></script>
|
||||||
|
<script type="text/javascript" src="../vendor/underscore-1.1.6.js"></script>
|
||||||
|
<script type="text/javascript" src="../vendor/backbone-0.5.1.js"></script>
|
||||||
|
<script type="text/javascript" src="../vendor/jquery-ui-1.8.14.custom.min.js"></script>
|
||||||
|
<script type="text/javascript" src="../vendor/jquery.flot-0.7.js"></script>
|
||||||
|
<script type="text/javascript" src="../vendor/jquery.mustache.js"></script>
|
||||||
|
<script type="text/javascript" src="../vendor/bootstrap/2.0.0/bootstrap.js"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript" src="../recline.js"></script>
|
||||||
|
<script type="text/javascript" src="js/app.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="navbar navbar-fixed-top">
|
||||||
|
<div class="navbar-inner">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<a class="brand" href="#">Recline Data Explorer</a>
|
||||||
|
<ul class="nav pull-right">
|
||||||
|
<li><a class="set-read-only" title="Put into read-only mode">Read-only</a></li>
|
||||||
|
</ul>
|
||||||
|
<form class="webstore-load pull-right navbar-search" title="Update from the specified webstore dataset">
|
||||||
|
<input type="text" name="source" size="50" />
|
||||||
|
<select name="backend_type">
|
||||||
|
<option value="elasticsearch">ElasticSearch</option>
|
||||||
|
<option value="dataproxy">DataProxy</option>
|
||||||
|
<option value="webstore">Webstore</option>
|
||||||
|
</select>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="content">
|
||||||
|
<div class="data-explorer-here"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
@@ -10,31 +10,49 @@
|
|||||||
<!--[if lt IE 9]>
|
<!--[if lt IE 9]>
|
||||||
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
|
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
|
||||||
<![endif]-->
|
<![endif]-->
|
||||||
<link rel="stylesheet" href="../vendor/bootstrap/1.4.0/bootstrap.css">
|
<link rel="stylesheet" href="../vendor/bootstrap/2.0.0/css/bootstrap.css">
|
||||||
<link rel="stylesheet" href="../css/data-explorer.css">
|
<link rel="stylesheet" href="../css/data-explorer.css">
|
||||||
<link rel="stylesheet" href="../css/graph-flot.css">
|
<link rel="stylesheet" href="../css/graph-flot.css">
|
||||||
<link rel="stylesheet" href="../css/bootstrap.css">
|
<link rel="stylesheet" href="../css/bootstrap.css">
|
||||||
|
<link rel="stylesheet" href="../vendor/bootstrap/2.0.0/css/bootstrap-responsive.css">
|
||||||
|
|
||||||
<script type="text/javascript" src="../vendor/000-jquery-1.6.1.min.js"></script>
|
<!-- 3rd party libraries -->
|
||||||
<script type="text/javascript" src="../vendor/000-underscore-1.1.6.js"></script>
|
<script type="text/javascript" src="../vendor/jquery-1.7.1.js"></script>
|
||||||
|
<script type="text/javascript" src="../vendor/underscore-1.1.6.js"></script>
|
||||||
<script type="text/javascript" src="../vendor/backbone-0.5.1.js"></script>
|
<script type="text/javascript" src="../vendor/backbone-0.5.1.js"></script>
|
||||||
<script type="text/javascript" src="../vendor/jquery-ui-1.8.14.custom.min.js"></script>
|
<script type="text/javascript" src="../vendor/jquery-ui-1.8.14.custom.min.js"></script>
|
||||||
<script type="text/javascript" src="../vendor/jquery.flot-0.7.js"></script>
|
<script type="text/javascript" src="../vendor/jquery.flot-0.7.js"></script>
|
||||||
<script type="text/javascript" src="../vendor/jquery.mustache.js"></script>
|
<script type="text/javascript" src="../vendor/jquery.mustache.js"></script>
|
||||||
<script type="text/javascript" src="../vendor/bootstrap/1.4.0/bootstrap-alerts.js"></script>
|
<script type="text/javascript" src="../vendor/bootstrap/2.0.0/bootstrap.js"></script>
|
||||||
|
|
||||||
<script type="text/javascript" src="../recline.js"></script>
|
<!-- recline library -->
|
||||||
|
<!-- in normal use would just the single recline.js library file. However, for testing it
|
||||||
|
is easier to reference individual files. See built.html for example using just recline.js -->
|
||||||
|
<script type="text/javascript" src="../src/util.js"></script>
|
||||||
|
<script type="text/javascript" src="../src/costco.js"></script>
|
||||||
|
<script type="text/javascript" src="../src/model.js"></script>
|
||||||
|
<script type="text/javascript" src="../src/backend/base.js"></script>
|
||||||
|
<script type="text/javascript" src="../src/backend/memory.js"></script>
|
||||||
|
<script type="text/javascript" src="../src/backend/webstore.js"></script>
|
||||||
|
<script type="text/javascript" src="../src/backend/dataproxy.js"></script>
|
||||||
|
<script type="text/javascript" src="../src/backend/elasticsearch.js"></script>
|
||||||
|
<script type="text/javascript" src="../src/view.js"></script>
|
||||||
|
<script type="text/javascript" src="../src/view-grid.js"></script>
|
||||||
|
<script type="text/javascript" src="../src/view-flot-graph.js"></script>
|
||||||
|
<script type="text/javascript" src="../src/view-transform-dialog.js"></script>
|
||||||
|
|
||||||
|
<!-- non-library javascript specific to this demo -->
|
||||||
<script type="text/javascript" src="js/app.js"></script>
|
<script type="text/javascript" src="js/app.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="topbar">
|
<div class="navbar navbar-fixed-top">
|
||||||
<div class="topbar-inner">
|
<div class="navbar-inner">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<a class="brand" href="#">Recline Data Explorer</a>
|
<a class="brand" href="#">Recline Data Explorer</a>
|
||||||
<ul class="nav secondary-nav">
|
<ul class="nav pull-right">
|
||||||
<li><a class="set-read-only" title="Put into read-only mode">Read-only</a></li>
|
<li><a class="set-read-only" title="Put into read-only mode">Read-only</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<form class="webstore-load pull-right" title="Update from the specified webstore dataset">
|
<form class="webstore-load pull-right navbar-search" title="Update from the specified webstore dataset">
|
||||||
<input type="text" name="source" size="50" />
|
<input type="text" name="source" size="50" />
|
||||||
<select name="backend_type">
|
<select name="backend_type">
|
||||||
<option value="elasticsearch">ElasticSearch</option>
|
<option value="elasticsearch">ElasticSearch</option>
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ function demoDataset() {
|
|||||||
|
|
||||||
function setupLoadFromWebstore(callback) {
|
function setupLoadFromWebstore(callback) {
|
||||||
// pre-populate webstore load form with an example url
|
// pre-populate webstore load form with an example url
|
||||||
var demoUrl = 'http://webstore.thedatahub.org/rufuspollock/gold_prices/data';
|
var demoUrl = 'http://thedatahub.org/api/data/b9aae52b-b082-4159-b46f-7bb9c158d013';
|
||||||
$('form.webstore-load input[name="source"]').val(demoUrl);
|
$('form.webstore-load input[name="source"]').val(demoUrl);
|
||||||
$('form.webstore-load').submit(function(e) {
|
$('form.webstore-load').submit(function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|||||||
@@ -170,7 +170,7 @@ note this.model and dataset returned are the same</p> </td>
|
|||||||
<span class="nx">my</span><span class="p">.</span><span class="nx">QueryEditor</span> <span class="o">=</span> <span class="nx">Backbone</span><span class="p">.</span><span class="nx">View</span><span class="p">.</span><span class="nx">extend</span><span class="p">({</span>
|
<span class="nx">my</span><span class="p">.</span><span class="nx">QueryEditor</span> <span class="o">=</span> <span class="nx">Backbone</span><span class="p">.</span><span class="nx">View</span><span class="p">.</span><span class="nx">extend</span><span class="p">({</span>
|
||||||
<span class="nx">className</span><span class="o">:</span> <span class="s1">'recline-query-editor'</span><span class="p">,</span>
|
<span class="nx">className</span><span class="o">:</span> <span class="s1">'recline-query-editor'</span><span class="p">,</span>
|
||||||
<span class="nx">template</span><span class="o">:</span> <span class="s1">' \</span>
|
<span class="nx">template</span><span class="o">:</span> <span class="s1">' \</span>
|
||||||
<span class="s1"> <form action="" method="GET"> \</span>
|
<span class="s1"> <form action="" method="GET" class="form-inline"> \</span>
|
||||||
<span class="s1"> <input type="text" name="q" value="{{q}}" class="text-query" /> \</span>
|
<span class="s1"> <input type="text" name="q" value="{{q}}" class="text-query" /> \</span>
|
||||||
<span class="s1"> <div class="pagination"> \</span>
|
<span class="s1"> <div class="pagination"> \</span>
|
||||||
<span class="s1"> <ul> \</span>
|
<span class="s1"> <ul> \</span>
|
||||||
@@ -260,7 +260,7 @@ note this.model and dataset returned are the same</p> </td>
|
|||||||
<span class="nb">window</span><span class="p">.</span><span class="nx">location</span><span class="p">.</span><span class="nx">hash</span> <span class="o">=</span> <span class="nb">window</span><span class="p">.</span><span class="nx">location</span><span class="p">.</span><span class="nx">hash</span><span class="p">.</span><span class="nx">split</span><span class="p">(</span><span class="s1">'?'</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="nx">my</span><span class="p">.</span><span class="nx">composeQueryString</span><span class="p">(</span><span class="nx">queryParams</span><span class="p">);</span>
|
<span class="nb">window</span><span class="p">.</span><span class="nx">location</span><span class="p">.</span><span class="nx">hash</span> <span class="o">=</span> <span class="nb">window</span><span class="p">.</span><span class="nx">location</span><span class="p">.</span><span class="nx">hash</span><span class="p">.</span><span class="nx">split</span><span class="p">(</span><span class="s1">'?'</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="nx">my</span><span class="p">.</span><span class="nx">composeQueryString</span><span class="p">(</span><span class="nx">queryParams</span><span class="p">);</span>
|
||||||
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-14">¶</a> </div> <h2>notify</h2>
|
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-14">¶</a> </div> <h2>notify</h2>
|
||||||
|
|
||||||
<p>Create a notification (a div.alert-message in div.alert-messsages) using provide messages and options. Options are:</p>
|
<p>Create a notification (a div.alert in div.alert-messsages) using provide messages and options. Options are:</p>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li>category: warning (default), success, error</li>
|
<li>category: warning (default), success, error</li>
|
||||||
@@ -274,12 +274,11 @@ note this.model and dataset returned are the same</p> </td>
|
|||||||
<span class="p">},</span>
|
<span class="p">},</span>
|
||||||
<span class="nx">options</span><span class="p">);</span>
|
<span class="nx">options</span><span class="p">);</span>
|
||||||
<span class="kd">var</span> <span class="nx">_template</span> <span class="o">=</span> <span class="s1">' \</span>
|
<span class="kd">var</span> <span class="nx">_template</span> <span class="o">=</span> <span class="s1">' \</span>
|
||||||
<span class="s1"> <div class="alert-message {{category}} fade in" data-alert="alert"><a class="close" href="#">×</a> \</span>
|
<span class="s1"> <div class="alert alert-{{category}} fade in" data-alert="alert"><a class="close" data-dismiss="alert" href="#">×</a> \</span>
|
||||||
<span class="s1"> <p>{{msg}} \</span>
|
<span class="s1"> {{msg}} \</span>
|
||||||
<span class="s1"> {{#loader}} \</span>
|
<span class="s1"> {{#loader}} \</span>
|
||||||
<span class="s1"> <img src="images/small-spinner.gif" class="notification-loader"> \</span>
|
<span class="s1"> <img src="images/small-spinner.gif" class="notification-loader"> \</span>
|
||||||
<span class="s1"> {{/loader}} \</span>
|
<span class="s1"> {{/loader}} \</span>
|
||||||
<span class="s1"> </p> \</span>
|
|
||||||
<span class="s1"> </div>'</span><span class="p">;</span>
|
<span class="s1"> </div>'</span><span class="p">;</span>
|
||||||
<span class="kd">var</span> <span class="nx">_templated</span> <span class="o">=</span> <span class="nx">$</span><span class="p">.</span><span class="nx">mustache</span><span class="p">(</span><span class="nx">_template</span><span class="p">,</span> <span class="nx">tmplData</span><span class="p">);</span>
|
<span class="kd">var</span> <span class="nx">_templated</span> <span class="o">=</span> <span class="nx">$</span><span class="p">.</span><span class="nx">mustache</span><span class="p">(</span><span class="nx">_template</span><span class="p">,</span> <span class="nx">tmplData</span><span class="p">);</span>
|
||||||
<span class="nx">_templated</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="nx">_templated</span><span class="p">).</span><span class="nx">appendTo</span><span class="p">(</span><span class="nx">$</span><span class="p">(</span><span class="s1">'.data-explorer .alert-messages'</span><span class="p">));</span>
|
<span class="nx">_templated</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="nx">_templated</span><span class="p">).</span><span class="nx">appendTo</span><span class="p">(</span><span class="nx">$</span><span class="p">(</span><span class="s1">'.data-explorer .alert-messages'</span><span class="p">));</span>
|
||||||
@@ -293,7 +292,7 @@ note this.model and dataset returned are the same</p> </td>
|
|||||||
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-15">¶</a> </div> <h2>clearNotifications</h2>
|
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-15">¶</a> </div> <h2>clearNotifications</h2>
|
||||||
|
|
||||||
<p>Clear all existing notifications</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">my</span><span class="p">.</span><span class="nx">clearNotifications</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
|
<p>Clear all existing notifications</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">my</span><span class="p">.</span><span class="nx">clearNotifications</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
|
||||||
<span class="kd">var</span> <span class="nx">$notifications</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="s1">'.data-explorer .alert-message'</span><span class="p">);</span>
|
<span class="kd">var</span> <span class="nx">$notifications</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="s1">'.data-explorer .alert-messages .alert'</span><span class="p">);</span>
|
||||||
<span class="nx">$notifications</span><span class="p">.</span><span class="nx">remove</span><span class="p">();</span>
|
<span class="nx">$notifications</span><span class="p">.</span><span class="nx">remove</span><span class="p">();</span>
|
||||||
<span class="p">}</span>
|
<span class="p">}</span>
|
||||||
|
|
||||||
|
|||||||
45
make
45
make
@@ -1,15 +1,34 @@
|
|||||||
#!/bin/bash
|
#!/usr/bin/env python
|
||||||
echo "** Combining js files"
|
import sys
|
||||||
cat src/*.js src/backend/*.js > recline.js
|
import os
|
||||||
|
|
||||||
# build docs
|
def cat():
|
||||||
echo "** Building docs"
|
print("** Combining js files")
|
||||||
docco src/model.js src/view.js src/view-grid.js src/view-flot-graph.js
|
cmd = 'cat src/*.js src/backend/*.js > recline.js'
|
||||||
mkdir -p /tmp/recline-docs
|
os.system(cmd)
|
||||||
mkdir -p docs/backend
|
|
||||||
PWD=`pwd`
|
def docs():
|
||||||
FILES=$PWD/src/backend/*.js
|
# build docs
|
||||||
DEST=$PWD/docs/backend
|
print("** Building docs")
|
||||||
cd /tmp/recline-docs && docco $FILES && mv docs/* $DEST
|
cmd = 'docco src/model.js src/view.js src/view-grid.js src/view-flot-graph.js'
|
||||||
echo "** Docs built ok"
|
os.system(cmd)
|
||||||
|
os.makedirs('/tmp/recline-docs')
|
||||||
|
os.system('mkdir -p docs/backend')
|
||||||
|
files = '%s/src/backend/*.js' % os.getcwd()
|
||||||
|
dest = '%s/docs/backend' % os.getcwd()
|
||||||
|
os.system('cd /tmp/recline-docs && docco %s && mv docs/* %s' % (files, dest))
|
||||||
|
print("** Docs built ok")
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
if not len(sys.argv) > 1:
|
||||||
|
print 'make cat | docs | all'
|
||||||
|
sys.exit(1)
|
||||||
|
action = sys.argv[1]
|
||||||
|
if action == 'cat':
|
||||||
|
cat()
|
||||||
|
elif action == 'docs':
|
||||||
|
docs()
|
||||||
|
elif action == 'all':
|
||||||
|
cat()
|
||||||
|
docs()
|
||||||
|
|
||||||
|
|||||||
767
recline.js
767
recline.js
@@ -812,7 +812,7 @@ my.DataGrid = Backbone.View.extend({
|
|||||||
template: ' \
|
template: ' \
|
||||||
<div class="data-table-menu-overlay" style="display: none; z-index: 101; "> </div> \
|
<div class="data-table-menu-overlay" style="display: none; z-index: 101; "> </div> \
|
||||||
<ul class="data-table-menu"></ul> \
|
<ul class="data-table-menu"></ul> \
|
||||||
<table class="data-table" cellspacing="0"> \
|
<table class="data-table table-striped" cellspacing="0"> \
|
||||||
<thead> \
|
<thead> \
|
||||||
<tr> \
|
<tr> \
|
||||||
{{#notEmpty}} \
|
{{#notEmpty}} \
|
||||||
@@ -872,7 +872,8 @@ my.DataGrid = Backbone.View.extend({
|
|||||||
// ## DataGridRow View for rendering an individual document.
|
// ## DataGridRow View for rendering an individual document.
|
||||||
//
|
//
|
||||||
// Since we want this to update in place it is up to creator to provider the element to attach to.
|
// Since we want this to update in place it is up to creator to provider the element to attach to.
|
||||||
// In addition you must pass in a fields in the constructor options. This should be list of fields for the DataGrid.
|
//
|
||||||
|
// In addition you *must* pass in a FieldList in the constructor options. This should be list of fields for the DataGrid.
|
||||||
//
|
//
|
||||||
// Additional options can be passed in a second hash argument. Options:
|
// Additional options can be passed in a second hash argument. Options:
|
||||||
//
|
//
|
||||||
@@ -881,6 +882,19 @@ my.DataGrid = Backbone.View.extend({
|
|||||||
// corresponding field object and document is the document object. Note
|
// corresponding field object and document is the document object. Note
|
||||||
// that implementing functions can ignore arguments (e.g.
|
// that implementing functions can ignore arguments (e.g.
|
||||||
// function(value) would be a valid cellRenderer function).
|
// function(value) would be a valid cellRenderer function).
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// <pre>
|
||||||
|
// var row = new DataGridRow({
|
||||||
|
// model: dataset-document,
|
||||||
|
// el: dom-element,
|
||||||
|
// fields: mydatasets.fields // a FieldList object
|
||||||
|
// }, {
|
||||||
|
// cellRenderer: my-cell-renderer-function
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
// </pre>
|
||||||
my.DataGridRow = Backbone.View.extend({
|
my.DataGridRow = Backbone.View.extend({
|
||||||
initialize: function(initData, options) {
|
initialize: function(initData, options) {
|
||||||
_.bindAll(this, 'render');
|
_.bindAll(this, 'render');
|
||||||
@@ -932,9 +946,8 @@ my.DataGridRow = Backbone.View.extend({
|
|||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
// Cell Editor
|
// ===================
|
||||||
// ===========
|
// Cell Editor methods
|
||||||
|
|
||||||
onEditClick: function(e) {
|
onEditClick: function(e) {
|
||||||
var editing = this.el.find('.data-table-cell-editor-editor');
|
var editing = this.el.find('.data-table-cell-editor-editor');
|
||||||
if (editing.length > 0) {
|
if (editing.length > 0) {
|
||||||
@@ -976,339 +989,6 @@ my.DataGridRow = Backbone.View.extend({
|
|||||||
this.recline = this.recline || {};
|
this.recline = this.recline || {};
|
||||||
this.recline.View = this.recline.View || {};
|
this.recline.View = this.recline.View || {};
|
||||||
|
|
||||||
(function($, my) {
|
|
||||||
// ## DataExplorer
|
|
||||||
//
|
|
||||||
// The primary view for the entire application. Usage:
|
|
||||||
//
|
|
||||||
// <pre>
|
|
||||||
// var myExplorer = new model.recline.DataExplorer({
|
|
||||||
// model: {{recline.Model.Dataset instance}}
|
|
||||||
// el: {{an existing dom element}}
|
|
||||||
// views: {{page views}}
|
|
||||||
// config: {{config options -- see below}}
|
|
||||||
// });
|
|
||||||
// </pre>
|
|
||||||
//
|
|
||||||
// ### Parameters
|
|
||||||
//
|
|
||||||
// **model**: (required) Dataset instance.
|
|
||||||
//
|
|
||||||
// **el**: (required) DOM element.
|
|
||||||
//
|
|
||||||
// **views**: (optional) the views (Grid, Graph etc) for DataExplorer to
|
|
||||||
// show. This is an array of view hashes. If not provided
|
|
||||||
// just initialize a DataGrid with id 'grid'. Example:
|
|
||||||
//
|
|
||||||
// <pre>
|
|
||||||
// var views = [
|
|
||||||
// {
|
|
||||||
// id: 'grid', // used for routing
|
|
||||||
// label: 'Grid', // used for view switcher
|
|
||||||
// view: new recline.View.DataGrid({
|
|
||||||
// model: dataset
|
|
||||||
// })
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// id: 'graph',
|
|
||||||
// label: 'Graph',
|
|
||||||
// view: new recline.View.FlotGraph({
|
|
||||||
// model: dataset
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// ];
|
|
||||||
// </pre>
|
|
||||||
//
|
|
||||||
// **config**: Config options like:
|
|
||||||
//
|
|
||||||
// * readOnly: true/false (default: false) value indicating whether to
|
|
||||||
// operate in read-only mode (hiding all editing options).
|
|
||||||
//
|
|
||||||
// NB: the element already being in the DOM is important for rendering of
|
|
||||||
// FlotGraph subview.
|
|
||||||
my.DataExplorer = Backbone.View.extend({
|
|
||||||
template: ' \
|
|
||||||
<div class="data-explorer"> \
|
|
||||||
<div class="alert-messages"></div> \
|
|
||||||
\
|
|
||||||
<div class="header"> \
|
|
||||||
<ul class="navigation"> \
|
|
||||||
{{#views}} \
|
|
||||||
<li><a href="#{{id}}" class="btn">{{label}}</a> \
|
|
||||||
{{/views}} \
|
|
||||||
</ul> \
|
|
||||||
<div class="recline-results-info"> \
|
|
||||||
Results found <span class="doc-count">{{docCount}}</span> \
|
|
||||||
</div> \
|
|
||||||
</div> \
|
|
||||||
<div class="data-view-container"></div> \
|
|
||||||
<div class="dialog-overlay" style="display: none; z-index: 101; "> </div> \
|
|
||||||
<div class="dialog ui-draggable" style="display: none; z-index: 102; top: 101px; "> \
|
|
||||||
<div class="dialog-frame" style="width: 700px; visibility: visible; "> \
|
|
||||||
<div class="dialog-content dialog-border"></div> \
|
|
||||||
</div> \
|
|
||||||
</div> \
|
|
||||||
</div> \
|
|
||||||
',
|
|
||||||
|
|
||||||
initialize: function(options) {
|
|
||||||
var self = this;
|
|
||||||
this.el = $(this.el);
|
|
||||||
this.config = _.extend({
|
|
||||||
readOnly: false
|
|
||||||
},
|
|
||||||
options.config);
|
|
||||||
if (this.config.readOnly) {
|
|
||||||
this.setReadOnly();
|
|
||||||
}
|
|
||||||
// Hash of 'page' views (i.e. those for whole page) keyed by page name
|
|
||||||
if (options.views) {
|
|
||||||
this.pageViews = options.views;
|
|
||||||
} else {
|
|
||||||
this.pageViews = [{
|
|
||||||
id: 'grid',
|
|
||||||
label: 'Grid',
|
|
||||||
view: new my.DataGrid({
|
|
||||||
model: this.model
|
|
||||||
})
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
// this must be called after pageViews are created
|
|
||||||
this.render();
|
|
||||||
|
|
||||||
this.router = new Backbone.Router();
|
|
||||||
this.setupRouting();
|
|
||||||
|
|
||||||
this.model.bind('query:start', function(eventName) {
|
|
||||||
my.notify('Loading data', {loader: true});
|
|
||||||
});
|
|
||||||
this.model.bind('query:done', function(eventName) {
|
|
||||||
my.clearNotifications();
|
|
||||||
self.el.find('.doc-count').text(self.model.docCount || 'Unknown');
|
|
||||||
my.notify('Data loaded', {category: 'success'});
|
|
||||||
});
|
|
||||||
this.model.bind('query:fail', function(eventName, error) {
|
|
||||||
my.clearNotifications();
|
|
||||||
my.notify(error.message, {category: 'error', persist: true});
|
|
||||||
});
|
|
||||||
|
|
||||||
// retrieve basic data like fields etc
|
|
||||||
// note this.model and dataset returned are the same
|
|
||||||
this.model.fetch()
|
|
||||||
.done(function(dataset) {
|
|
||||||
self.el.find('.doc-count').text(self.model.docCount || 'Unknown');
|
|
||||||
self.model.query();
|
|
||||||
})
|
|
||||||
.fail(function(error) {
|
|
||||||
my.notify(error.message, {category: 'error', persist: true});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
setReadOnly: function() {
|
|
||||||
this.el.addClass('read-only');
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function() {
|
|
||||||
var tmplData = this.model.toTemplateJSON();
|
|
||||||
tmplData.displayCount = this.config.displayCount;
|
|
||||||
tmplData.views = this.pageViews;
|
|
||||||
var template = $.mustache(this.template, tmplData);
|
|
||||||
$(this.el).html(template);
|
|
||||||
var $dataViewContainer = this.el.find('.data-view-container');
|
|
||||||
_.each(this.pageViews, function(view, pageName) {
|
|
||||||
$dataViewContainer.append(view.view.el)
|
|
||||||
});
|
|
||||||
var queryEditor = new my.QueryEditor({
|
|
||||||
model: this.model.queryState
|
|
||||||
});
|
|
||||||
this.el.find('.header').append(queryEditor.el);
|
|
||||||
},
|
|
||||||
|
|
||||||
setupRouting: function() {
|
|
||||||
var self = this;
|
|
||||||
// Default route
|
|
||||||
this.router.route('', this.pageViews[0].id, function() {
|
|
||||||
self.updateNav(self.pageViews[0].id);
|
|
||||||
});
|
|
||||||
$.each(this.pageViews, function(idx, view) {
|
|
||||||
self.router.route(/^([^?]+)(\?.*)?/, 'view', function(viewId, queryString) {
|
|
||||||
self.updateNav(viewId, queryString);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
updateNav: function(pageName, queryString) {
|
|
||||||
this.el.find('.navigation li').removeClass('active');
|
|
||||||
var $el = this.el.find('.navigation li a[href=#' + pageName + ']');
|
|
||||||
$el.parent().addClass('active');
|
|
||||||
// show the specific page
|
|
||||||
_.each(this.pageViews, function(view, idx) {
|
|
||||||
if (view.id === pageName) {
|
|
||||||
view.view.el.show();
|
|
||||||
} else {
|
|
||||||
view.view.el.hide();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
my.QueryEditor = Backbone.View.extend({
|
|
||||||
className: 'recline-query-editor',
|
|
||||||
template: ' \
|
|
||||||
<form action="" method="GET"> \
|
|
||||||
<input type="text" name="q" value="{{q}}" class="text-query" /> \
|
|
||||||
<div class="pagination"> \
|
|
||||||
<ul> \
|
|
||||||
<li class="prev action-pagination-update"><a>« back</a></li> \
|
|
||||||
<li class="active"><a><input name="from" type="text" value="{{from}}" /> – <input name="to" type="text" value="{{to}}" /> </a></li> \
|
|
||||||
<li class="next action-pagination-update"><a>next »</a></li> \
|
|
||||||
</ul> \
|
|
||||||
</div> \
|
|
||||||
<button type="submit" class="btn" style="">Update »</button> \
|
|
||||||
</form> \
|
|
||||||
',
|
|
||||||
|
|
||||||
events: {
|
|
||||||
'submit form': 'onFormSubmit',
|
|
||||||
'click .action-pagination-update': 'onPaginationUpdate'
|
|
||||||
},
|
|
||||||
|
|
||||||
initialize: function() {
|
|
||||||
_.bindAll(this, 'render');
|
|
||||||
this.el = $(this.el);
|
|
||||||
this.model.bind('change', this.render);
|
|
||||||
this.render();
|
|
||||||
},
|
|
||||||
onFormSubmit: function(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
var newFrom = parseInt(this.el.find('input[name="from"]').val());
|
|
||||||
var newSize = parseInt(this.el.find('input[name="to"]').val()) - newFrom;
|
|
||||||
var query = this.el.find('.text-query').val();
|
|
||||||
this.model.set({size: newSize, from: newFrom, q: query});
|
|
||||||
},
|
|
||||||
onPaginationUpdate: function(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
var $el = $(e.target);
|
|
||||||
if ($el.parent().hasClass('prev')) {
|
|
||||||
var newFrom = this.model.get('from') - Math.max(0, this.model.get('size'));
|
|
||||||
} else {
|
|
||||||
var newFrom = this.model.get('from') + this.model.get('size');
|
|
||||||
}
|
|
||||||
this.model.set({from: newFrom});
|
|
||||||
},
|
|
||||||
render: function() {
|
|
||||||
var tmplData = this.model.toJSON();
|
|
||||||
tmplData.to = this.model.get('from') + this.model.get('size');
|
|
||||||
var templated = $.mustache(this.template, tmplData);
|
|
||||||
this.el.html(templated);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
/* ========================================================== */
|
|
||||||
// ## Miscellaneous Utilities
|
|
||||||
|
|
||||||
var urlPathRegex = /^([^?]+)(\?.*)?/;
|
|
||||||
|
|
||||||
// Parse the Hash section of a URL into path and query string
|
|
||||||
my.parseHashUrl = function(hashUrl) {
|
|
||||||
var parsed = urlPathRegex.exec(hashUrl);
|
|
||||||
if (parsed == null) {
|
|
||||||
return {};
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
path: parsed[1],
|
|
||||||
query: parsed[2] || ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse a URL query string (?xyz=abc...) into a dictionary.
|
|
||||||
my.parseQueryString = function(q) {
|
|
||||||
var urlParams = {},
|
|
||||||
e, d = function (s) {
|
|
||||||
return unescape(s.replace(/\+/g, " "));
|
|
||||||
},
|
|
||||||
r = /([^&=]+)=?([^&]*)/g;
|
|
||||||
|
|
||||||
if (q && q.length && q[0] === '?') {
|
|
||||||
q = q.slice(1);
|
|
||||||
}
|
|
||||||
while (e = r.exec(q)) {
|
|
||||||
// TODO: have values be array as query string allow repetition of keys
|
|
||||||
urlParams[d(e[1])] = d(e[2]);
|
|
||||||
}
|
|
||||||
return urlParams;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the query string out of the URL hash
|
|
||||||
my.parseHashQueryString = function() {
|
|
||||||
q = my.parseHashUrl(window.location.hash).query;
|
|
||||||
return my.parseQueryString(q);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compse a Query String
|
|
||||||
my.composeQueryString = function(queryParams) {
|
|
||||||
var queryString = '?';
|
|
||||||
var items = [];
|
|
||||||
$.each(queryParams, function(key, value) {
|
|
||||||
items.push(key + '=' + JSON.stringify(value));
|
|
||||||
});
|
|
||||||
queryString += items.join('&');
|
|
||||||
return queryString;
|
|
||||||
}
|
|
||||||
|
|
||||||
my.setHashQueryString = function(queryParams) {
|
|
||||||
window.location.hash = window.location.hash.split('?')[0] + my.composeQueryString(queryParams);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ## notify
|
|
||||||
//
|
|
||||||
// Create a notification (a div.alert-message in div.alert-messsages) using provide messages and options. Options are:
|
|
||||||
//
|
|
||||||
// * category: warning (default), success, error
|
|
||||||
// * persist: if true alert is persistent, o/w hidden after 3s (default = false)
|
|
||||||
// * loader: if true show loading spinner
|
|
||||||
my.notify = function(message, options) {
|
|
||||||
if (!options) var options = {};
|
|
||||||
var tmplData = _.extend({
|
|
||||||
msg: message,
|
|
||||||
category: 'warning'
|
|
||||||
},
|
|
||||||
options);
|
|
||||||
var _template = ' \
|
|
||||||
<div class="alert-message {{category}} fade in" data-alert="alert"><a class="close" href="#">×</a> \
|
|
||||||
<p>{{msg}} \
|
|
||||||
{{#loader}} \
|
|
||||||
<img src="images/small-spinner.gif" class="notification-loader"> \
|
|
||||||
{{/loader}} \
|
|
||||||
</p> \
|
|
||||||
</div>';
|
|
||||||
var _templated = $.mustache(_template, tmplData);
|
|
||||||
_templated = $(_templated).appendTo($('.data-explorer .alert-messages'));
|
|
||||||
if (!options.persist) {
|
|
||||||
setTimeout(function() {
|
|
||||||
$(_templated).fadeOut(1000, function() {
|
|
||||||
$(this).remove();
|
|
||||||
});
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ## clearNotifications
|
|
||||||
//
|
|
||||||
// Clear all existing notifications
|
|
||||||
my.clearNotifications = function() {
|
|
||||||
var $notifications = $('.data-explorer .alert-message');
|
|
||||||
$notifications.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
})(jQuery, recline.View);
|
|
||||||
|
|
||||||
this.recline = this.recline || {};
|
|
||||||
this.recline.View = this.recline.View || {};
|
|
||||||
|
|
||||||
// Views module following classic module pattern
|
// Views module following classic module pattern
|
||||||
(function($, my) {
|
(function($, my) {
|
||||||
|
|
||||||
@@ -1512,6 +1192,356 @@ my.ColumnTransform = Backbone.View.extend({
|
|||||||
});
|
});
|
||||||
|
|
||||||
})(jQuery, recline.View);
|
})(jQuery, recline.View);
|
||||||
|
this.recline = this.recline || {};
|
||||||
|
this.recline.View = this.recline.View || {};
|
||||||
|
|
||||||
|
(function($, my) {
|
||||||
|
// ## DataExplorer
|
||||||
|
//
|
||||||
|
// The primary view for the entire application. Usage:
|
||||||
|
//
|
||||||
|
// <pre>
|
||||||
|
// var myExplorer = new model.recline.DataExplorer({
|
||||||
|
// model: {{recline.Model.Dataset instance}}
|
||||||
|
// el: {{an existing dom element}}
|
||||||
|
// views: {{page views}}
|
||||||
|
// config: {{config options -- see below}}
|
||||||
|
// });
|
||||||
|
// </pre>
|
||||||
|
//
|
||||||
|
// ### Parameters
|
||||||
|
//
|
||||||
|
// **model**: (required) Dataset instance.
|
||||||
|
//
|
||||||
|
// **el**: (required) DOM element.
|
||||||
|
//
|
||||||
|
// **views**: (optional) the views (Grid, Graph etc) for DataExplorer to
|
||||||
|
// show. This is an array of view hashes. If not provided
|
||||||
|
// just initialize a DataGrid with id 'grid'. Example:
|
||||||
|
//
|
||||||
|
// <pre>
|
||||||
|
// var views = [
|
||||||
|
// {
|
||||||
|
// id: 'grid', // used for routing
|
||||||
|
// label: 'Grid', // used for view switcher
|
||||||
|
// view: new recline.View.DataGrid({
|
||||||
|
// model: dataset
|
||||||
|
// })
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// id: 'graph',
|
||||||
|
// label: 'Graph',
|
||||||
|
// view: new recline.View.FlotGraph({
|
||||||
|
// model: dataset
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// ];
|
||||||
|
// </pre>
|
||||||
|
//
|
||||||
|
// **config**: Config options like:
|
||||||
|
//
|
||||||
|
// * readOnly: true/false (default: false) value indicating whether to
|
||||||
|
// operate in read-only mode (hiding all editing options).
|
||||||
|
//
|
||||||
|
// NB: the element already being in the DOM is important for rendering of
|
||||||
|
// FlotGraph subview.
|
||||||
|
my.DataExplorer = Backbone.View.extend({
|
||||||
|
template: ' \
|
||||||
|
<div class="data-explorer"> \
|
||||||
|
<div class="alert-messages"></div> \
|
||||||
|
\
|
||||||
|
<div class="header"> \
|
||||||
|
<ul class="navigation"> \
|
||||||
|
{{#views}} \
|
||||||
|
<li><a href="#{{id}}" class="btn">{{label}}</a> \
|
||||||
|
{{/views}} \
|
||||||
|
</ul> \
|
||||||
|
<div class="recline-results-info"> \
|
||||||
|
Results found <span class="doc-count">{{docCount}}</span> \
|
||||||
|
</div> \
|
||||||
|
</div> \
|
||||||
|
<div class="data-view-container"></div> \
|
||||||
|
<div class="dialog-overlay" style="display: none; z-index: 101; "> </div> \
|
||||||
|
<div class="dialog ui-draggable" style="display: none; z-index: 102; top: 101px; "> \
|
||||||
|
<div class="dialog-frame" style="width: 700px; visibility: visible; "> \
|
||||||
|
<div class="dialog-content dialog-border"></div> \
|
||||||
|
</div> \
|
||||||
|
</div> \
|
||||||
|
</div> \
|
||||||
|
',
|
||||||
|
|
||||||
|
initialize: function(options) {
|
||||||
|
var self = this;
|
||||||
|
this.el = $(this.el);
|
||||||
|
this.config = _.extend({
|
||||||
|
readOnly: false
|
||||||
|
},
|
||||||
|
options.config);
|
||||||
|
if (this.config.readOnly) {
|
||||||
|
this.setReadOnly();
|
||||||
|
}
|
||||||
|
// Hash of 'page' views (i.e. those for whole page) keyed by page name
|
||||||
|
if (options.views) {
|
||||||
|
this.pageViews = options.views;
|
||||||
|
} else {
|
||||||
|
this.pageViews = [{
|
||||||
|
id: 'grid',
|
||||||
|
label: 'Grid',
|
||||||
|
view: new my.DataGrid({
|
||||||
|
model: this.model
|
||||||
|
})
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
// this must be called after pageViews are created
|
||||||
|
this.render();
|
||||||
|
|
||||||
|
this.router = new Backbone.Router();
|
||||||
|
this.setupRouting();
|
||||||
|
|
||||||
|
this.model.bind('query:start', function() {
|
||||||
|
my.notify('Loading data', {loader: true});
|
||||||
|
});
|
||||||
|
this.model.bind('query:done', function() {
|
||||||
|
my.clearNotifications();
|
||||||
|
self.el.find('.doc-count').text(self.model.docCount || 'Unknown');
|
||||||
|
my.notify('Data loaded', {category: 'success'});
|
||||||
|
});
|
||||||
|
this.model.bind('query:fail', function(error) {
|
||||||
|
my.clearNotifications();
|
||||||
|
var msg = '';
|
||||||
|
if (typeof(error) == 'string') {
|
||||||
|
msg = error;
|
||||||
|
} else if (typeof(error) == 'object') {
|
||||||
|
if (error.title) {
|
||||||
|
msg = error.title + ': ';
|
||||||
|
}
|
||||||
|
if (error.message) {
|
||||||
|
msg += error.message;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
msg = 'There was an error querying the backend';
|
||||||
|
}
|
||||||
|
my.notify(msg, {category: 'error', persist: true});
|
||||||
|
});
|
||||||
|
|
||||||
|
// retrieve basic data like fields etc
|
||||||
|
// note this.model and dataset returned are the same
|
||||||
|
this.model.fetch()
|
||||||
|
.done(function(dataset) {
|
||||||
|
self.el.find('.doc-count').text(self.model.docCount || 'Unknown');
|
||||||
|
self.model.query();
|
||||||
|
})
|
||||||
|
.fail(function(error) {
|
||||||
|
my.notify(error.message, {category: 'error', persist: true});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
setReadOnly: function() {
|
||||||
|
this.el.addClass('read-only');
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
var tmplData = this.model.toTemplateJSON();
|
||||||
|
tmplData.displayCount = this.config.displayCount;
|
||||||
|
tmplData.views = this.pageViews;
|
||||||
|
var template = $.mustache(this.template, tmplData);
|
||||||
|
$(this.el).html(template);
|
||||||
|
var $dataViewContainer = this.el.find('.data-view-container');
|
||||||
|
_.each(this.pageViews, function(view, pageName) {
|
||||||
|
$dataViewContainer.append(view.view.el)
|
||||||
|
});
|
||||||
|
var queryEditor = new my.QueryEditor({
|
||||||
|
model: this.model.queryState
|
||||||
|
});
|
||||||
|
this.el.find('.header').append(queryEditor.el);
|
||||||
|
},
|
||||||
|
|
||||||
|
setupRouting: function() {
|
||||||
|
var self = this;
|
||||||
|
// Default route
|
||||||
|
this.router.route('', this.pageViews[0].id, function() {
|
||||||
|
self.updateNav(self.pageViews[0].id);
|
||||||
|
});
|
||||||
|
$.each(this.pageViews, function(idx, view) {
|
||||||
|
self.router.route(/^([^?]+)(\?.*)?/, 'view', function(viewId, queryString) {
|
||||||
|
self.updateNav(viewId, queryString);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
updateNav: function(pageName, queryString) {
|
||||||
|
this.el.find('.navigation li').removeClass('active');
|
||||||
|
this.el.find('.navigation li a').removeClass('disabled');
|
||||||
|
var $el = this.el.find('.navigation li a[href=#' + pageName + ']');
|
||||||
|
$el.parent().addClass('active');
|
||||||
|
$el.addClass('disabled');
|
||||||
|
// show the specific page
|
||||||
|
_.each(this.pageViews, function(view, idx) {
|
||||||
|
if (view.id === pageName) {
|
||||||
|
view.view.el.show();
|
||||||
|
} else {
|
||||||
|
view.view.el.hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
my.QueryEditor = Backbone.View.extend({
|
||||||
|
className: 'recline-query-editor',
|
||||||
|
template: ' \
|
||||||
|
<form action="" method="GET" class="form-inline"> \
|
||||||
|
<div class="input-prepend text-query"> \
|
||||||
|
<span class="add-on"><i class="icon-search"></i></span> \
|
||||||
|
<input type="text" name="q" value="{{q}}" class="span2" placeholder="Search data ..." class="search-query" /> \
|
||||||
|
</div> \
|
||||||
|
<div class="pagination"> \
|
||||||
|
<ul> \
|
||||||
|
<li class="prev action-pagination-update"><a>«</a></li> \
|
||||||
|
<li class="active"><a><input name="from" type="text" value="{{from}}" /> – <input name="to" type="text" value="{{to}}" /> </a></li> \
|
||||||
|
<li class="next action-pagination-update"><a>»</a></li> \
|
||||||
|
</ul> \
|
||||||
|
</div> \
|
||||||
|
<button type="submit" class="btn" style="">Update »</button> \
|
||||||
|
</form> \
|
||||||
|
',
|
||||||
|
|
||||||
|
events: {
|
||||||
|
'submit form': 'onFormSubmit',
|
||||||
|
'click .action-pagination-update': 'onPaginationUpdate'
|
||||||
|
},
|
||||||
|
|
||||||
|
initialize: function() {
|
||||||
|
_.bindAll(this, 'render');
|
||||||
|
this.el = $(this.el);
|
||||||
|
this.model.bind('change', this.render);
|
||||||
|
this.render();
|
||||||
|
},
|
||||||
|
onFormSubmit: function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var newFrom = parseInt(this.el.find('input[name="from"]').val());
|
||||||
|
var newSize = parseInt(this.el.find('input[name="to"]').val()) - newFrom;
|
||||||
|
var query = this.el.find('.text-query input').val();
|
||||||
|
this.model.set({size: newSize, from: newFrom, q: query});
|
||||||
|
},
|
||||||
|
onPaginationUpdate: function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var $el = $(e.target);
|
||||||
|
if ($el.parent().hasClass('prev')) {
|
||||||
|
var newFrom = this.model.get('from') - Math.max(0, this.model.get('size'));
|
||||||
|
} else {
|
||||||
|
var newFrom = this.model.get('from') + this.model.get('size');
|
||||||
|
}
|
||||||
|
this.model.set({from: newFrom});
|
||||||
|
},
|
||||||
|
render: function() {
|
||||||
|
var tmplData = this.model.toJSON();
|
||||||
|
tmplData.to = this.model.get('from') + this.model.get('size');
|
||||||
|
var templated = $.mustache(this.template, tmplData);
|
||||||
|
this.el.html(templated);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/* ========================================================== */
|
||||||
|
// ## Miscellaneous Utilities
|
||||||
|
|
||||||
|
var urlPathRegex = /^([^?]+)(\?.*)?/;
|
||||||
|
|
||||||
|
// Parse the Hash section of a URL into path and query string
|
||||||
|
my.parseHashUrl = function(hashUrl) {
|
||||||
|
var parsed = urlPathRegex.exec(hashUrl);
|
||||||
|
if (parsed == null) {
|
||||||
|
return {};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
path: parsed[1],
|
||||||
|
query: parsed[2] || ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse a URL query string (?xyz=abc...) into a dictionary.
|
||||||
|
my.parseQueryString = function(q) {
|
||||||
|
var urlParams = {},
|
||||||
|
e, d = function (s) {
|
||||||
|
return unescape(s.replace(/\+/g, " "));
|
||||||
|
},
|
||||||
|
r = /([^&=]+)=?([^&]*)/g;
|
||||||
|
|
||||||
|
if (q && q.length && q[0] === '?') {
|
||||||
|
q = q.slice(1);
|
||||||
|
}
|
||||||
|
while (e = r.exec(q)) {
|
||||||
|
// TODO: have values be array as query string allow repetition of keys
|
||||||
|
urlParams[d(e[1])] = d(e[2]);
|
||||||
|
}
|
||||||
|
return urlParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the query string out of the URL hash
|
||||||
|
my.parseHashQueryString = function() {
|
||||||
|
q = my.parseHashUrl(window.location.hash).query;
|
||||||
|
return my.parseQueryString(q);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compse a Query String
|
||||||
|
my.composeQueryString = function(queryParams) {
|
||||||
|
var queryString = '?';
|
||||||
|
var items = [];
|
||||||
|
$.each(queryParams, function(key, value) {
|
||||||
|
items.push(key + '=' + JSON.stringify(value));
|
||||||
|
});
|
||||||
|
queryString += items.join('&');
|
||||||
|
return queryString;
|
||||||
|
}
|
||||||
|
|
||||||
|
my.setHashQueryString = function(queryParams) {
|
||||||
|
window.location.hash = window.location.hash.split('?')[0] + my.composeQueryString(queryParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ## notify
|
||||||
|
//
|
||||||
|
// Create a notification (a div.alert in div.alert-messsages) using provide messages and options. Options are:
|
||||||
|
//
|
||||||
|
// * category: warning (default), success, error
|
||||||
|
// * persist: if true alert is persistent, o/w hidden after 3s (default = false)
|
||||||
|
// * loader: if true show loading spinner
|
||||||
|
my.notify = function(message, options) {
|
||||||
|
if (!options) var options = {};
|
||||||
|
var tmplData = _.extend({
|
||||||
|
msg: message,
|
||||||
|
category: 'warning'
|
||||||
|
},
|
||||||
|
options);
|
||||||
|
var _template = ' \
|
||||||
|
<div class="alert alert-{{category}} fade in" data-alert="alert"><a class="close" data-dismiss="alert" href="#">×</a> \
|
||||||
|
{{msg}} \
|
||||||
|
{{#loader}} \
|
||||||
|
<span class="notification-loader"> </span> \
|
||||||
|
{{/loader}} \
|
||||||
|
</div>';
|
||||||
|
var _templated = $.mustache(_template, tmplData);
|
||||||
|
_templated = $(_templated).appendTo($('.data-explorer .alert-messages'));
|
||||||
|
if (!options.persist) {
|
||||||
|
setTimeout(function() {
|
||||||
|
$(_templated).fadeOut(1000, function() {
|
||||||
|
$(this).remove();
|
||||||
|
});
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ## clearNotifications
|
||||||
|
//
|
||||||
|
// Clear all existing notifications
|
||||||
|
my.clearNotifications = function() {
|
||||||
|
var $notifications = $('.data-explorer .alert-messages .alert');
|
||||||
|
$notifications.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
})(jQuery, recline.View);
|
||||||
|
|
||||||
// # Recline Backends
|
// # Recline Backends
|
||||||
//
|
//
|
||||||
// Backends are connectors to backend data sources and stores
|
// Backends are connectors to backend data sources and stores
|
||||||
@@ -1580,29 +1610,10 @@ this.recline.Backend = this.recline.Backend || {};
|
|||||||
var self = this;
|
var self = this;
|
||||||
if (method === "read") {
|
if (method === "read") {
|
||||||
if (model.__type__ == 'Dataset') {
|
if (model.__type__ == 'Dataset') {
|
||||||
var base = self.get('dataproxy_url');
|
// Do nothing as we will get fields in query step (and no metadata to
|
||||||
// TODO: should we cache for extra efficiency
|
// retrieve)
|
||||||
var data = {
|
|
||||||
url: model.get('url')
|
|
||||||
, 'max-results': 1
|
|
||||||
, type: model.get('format') || 'csv'
|
|
||||||
};
|
|
||||||
var jqxhr = $.ajax({
|
|
||||||
url: base
|
|
||||||
, data: data
|
|
||||||
, dataType: 'jsonp'
|
|
||||||
});
|
|
||||||
var dfd = $.Deferred();
|
var dfd = $.Deferred();
|
||||||
my.wrapInTimeout(jqxhr).done(function(results) {
|
dfd.resolve(model);
|
||||||
model.fields.reset(_.map(results.fields, function(fieldId) {
|
|
||||||
return {id: fieldId};
|
|
||||||
})
|
|
||||||
);
|
|
||||||
dfd.resolve(model, jqxhr);
|
|
||||||
})
|
|
||||||
.fail(function(arguments) {
|
|
||||||
dfd.reject(arguments);
|
|
||||||
});
|
|
||||||
return dfd.promise();
|
return dfd.promise();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -1622,7 +1633,14 @@ this.recline.Backend = this.recline.Backend || {};
|
|||||||
, dataType: 'jsonp'
|
, dataType: 'jsonp'
|
||||||
});
|
});
|
||||||
var dfd = $.Deferred();
|
var dfd = $.Deferred();
|
||||||
jqxhr.done(function(results) {
|
my.wrapInTimeout(jqxhr).done(function(results) {
|
||||||
|
if (results.error) {
|
||||||
|
dfd.reject(results.error);
|
||||||
|
}
|
||||||
|
dataset.fields.reset(_.map(results.fields, function(fieldId) {
|
||||||
|
return {id: fieldId};
|
||||||
|
})
|
||||||
|
);
|
||||||
var _out = _.map(results.data, function(doc) {
|
var _out = _.map(results.data, function(doc) {
|
||||||
var tmp = {};
|
var tmp = {};
|
||||||
_.each(results.fields, function(key, idx) {
|
_.each(results.fields, function(key, idx) {
|
||||||
@@ -1631,6 +1649,9 @@ this.recline.Backend = this.recline.Backend || {};
|
|||||||
return tmp;
|
return tmp;
|
||||||
});
|
});
|
||||||
dfd.resolve(_out);
|
dfd.resolve(_out);
|
||||||
|
})
|
||||||
|
.fail(function(arguments) {
|
||||||
|
dfd.reject(arguments);
|
||||||
});
|
});
|
||||||
return dfd.promise();
|
return dfd.promise();
|
||||||
}
|
}
|
||||||
@@ -1645,10 +1666,21 @@ this.recline.Backend = this.recline.Backend || {};
|
|||||||
(function($, my) {
|
(function($, my) {
|
||||||
// ## ElasticSearch Backend
|
// ## ElasticSearch Backend
|
||||||
//
|
//
|
||||||
// Connecting to [ElasticSearch](http://www.elasticsearch.org/)
|
// Connecting to [ElasticSearch](http://www.elasticsearch.org/).
|
||||||
//
|
//
|
||||||
// To use this backend ensure your Dataset has a elasticsearch_url,
|
// To use this backend ensure your Dataset has one of the following
|
||||||
// webstore_url or url attribute (used in that order)
|
// attributes (first one found is used):
|
||||||
|
//
|
||||||
|
// <pre>
|
||||||
|
// elasticsearch_url
|
||||||
|
// webstore_url
|
||||||
|
// url
|
||||||
|
// </pre>
|
||||||
|
//
|
||||||
|
// This should point to the ES type url. E.G. for ES running on
|
||||||
|
// localhost:9200 with index twitter and type tweet it would be
|
||||||
|
//
|
||||||
|
// <pre>http://localhost:9200/twitter/tweet</pre>
|
||||||
my.ElasticSearch = Backbone.Model.extend({
|
my.ElasticSearch = Backbone.Model.extend({
|
||||||
_getESUrl: function(dataset) {
|
_getESUrl: function(dataset) {
|
||||||
var out = dataset.get('elasticsearch_url');
|
var out = dataset.get('elasticsearch_url');
|
||||||
@@ -1861,15 +1893,12 @@ this.recline.Backend = this.recline.Backend || {};
|
|||||||
(function($, my) {
|
(function($, my) {
|
||||||
// ## Memory Backend - uses in-memory data
|
// ## Memory Backend - uses in-memory data
|
||||||
//
|
//
|
||||||
// This is very artificial and is really only designed for testing
|
|
||||||
// purposes.
|
|
||||||
//
|
|
||||||
// To use it you should provide in your constructor data:
|
// To use it you should provide in your constructor data:
|
||||||
//
|
//
|
||||||
// * metadata (including fields array)
|
// * metadata (including fields array)
|
||||||
// * documents: list of hashes, each hash being one doc. A doc *must* have an id attribute which is unique.
|
// * documents: list of hashes, each hash being one doc. A doc *must* have an id attribute which is unique.
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
//
|
//
|
||||||
// <pre>
|
// <pre>
|
||||||
// // Backend setup
|
// // Backend setup
|
||||||
@@ -1886,7 +1915,7 @@ this.recline.Backend = this.recline.Backend || {};
|
|||||||
// ]
|
// ]
|
||||||
// });
|
// });
|
||||||
// // later ...
|
// // later ...
|
||||||
// var dataset = Dataset({id: 'my-id'});
|
// var dataset = Dataset({id: 'my-id'}, 'memory');
|
||||||
// dataset.fetch();
|
// dataset.fetch();
|
||||||
// etc ...
|
// etc ...
|
||||||
// </pre>
|
// </pre>
|
||||||
|
|||||||
@@ -24,29 +24,10 @@ this.recline.Backend = this.recline.Backend || {};
|
|||||||
var self = this;
|
var self = this;
|
||||||
if (method === "read") {
|
if (method === "read") {
|
||||||
if (model.__type__ == 'Dataset') {
|
if (model.__type__ == 'Dataset') {
|
||||||
var base = self.get('dataproxy_url');
|
// Do nothing as we will get fields in query step (and no metadata to
|
||||||
// TODO: should we cache for extra efficiency
|
// retrieve)
|
||||||
var data = {
|
|
||||||
url: model.get('url')
|
|
||||||
, 'max-results': 1
|
|
||||||
, type: model.get('format') || 'csv'
|
|
||||||
};
|
|
||||||
var jqxhr = $.ajax({
|
|
||||||
url: base
|
|
||||||
, data: data
|
|
||||||
, dataType: 'jsonp'
|
|
||||||
});
|
|
||||||
var dfd = $.Deferred();
|
var dfd = $.Deferred();
|
||||||
my.wrapInTimeout(jqxhr).done(function(results) {
|
dfd.resolve(model);
|
||||||
model.fields.reset(_.map(results.fields, function(fieldId) {
|
|
||||||
return {id: fieldId};
|
|
||||||
})
|
|
||||||
);
|
|
||||||
dfd.resolve(model, jqxhr);
|
|
||||||
})
|
|
||||||
.fail(function(arguments) {
|
|
||||||
dfd.reject(arguments);
|
|
||||||
});
|
|
||||||
return dfd.promise();
|
return dfd.promise();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -66,7 +47,14 @@ this.recline.Backend = this.recline.Backend || {};
|
|||||||
, dataType: 'jsonp'
|
, dataType: 'jsonp'
|
||||||
});
|
});
|
||||||
var dfd = $.Deferred();
|
var dfd = $.Deferred();
|
||||||
jqxhr.done(function(results) {
|
my.wrapInTimeout(jqxhr).done(function(results) {
|
||||||
|
if (results.error) {
|
||||||
|
dfd.reject(results.error);
|
||||||
|
}
|
||||||
|
dataset.fields.reset(_.map(results.fields, function(fieldId) {
|
||||||
|
return {id: fieldId};
|
||||||
|
})
|
||||||
|
);
|
||||||
var _out = _.map(results.data, function(doc) {
|
var _out = _.map(results.data, function(doc) {
|
||||||
var tmp = {};
|
var tmp = {};
|
||||||
_.each(results.fields, function(key, idx) {
|
_.each(results.fields, function(key, idx) {
|
||||||
@@ -75,6 +63,9 @@ this.recline.Backend = this.recline.Backend || {};
|
|||||||
return tmp;
|
return tmp;
|
||||||
});
|
});
|
||||||
dfd.resolve(_out);
|
dfd.resolve(_out);
|
||||||
|
})
|
||||||
|
.fail(function(arguments) {
|
||||||
|
dfd.reject(arguments);
|
||||||
});
|
});
|
||||||
return dfd.promise();
|
return dfd.promise();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ my.DataGrid = Backbone.View.extend({
|
|||||||
template: ' \
|
template: ' \
|
||||||
<div class="data-table-menu-overlay" style="display: none; z-index: 101; "> </div> \
|
<div class="data-table-menu-overlay" style="display: none; z-index: 101; "> </div> \
|
||||||
<ul class="data-table-menu"></ul> \
|
<ul class="data-table-menu"></ul> \
|
||||||
<table class="data-table" cellspacing="0"> \
|
<table class="data-table table-striped" cellspacing="0"> \
|
||||||
<thead> \
|
<thead> \
|
||||||
<tr> \
|
<tr> \
|
||||||
{{#notEmpty}} \
|
{{#notEmpty}} \
|
||||||
|
|||||||
47
src/view.js
47
src/view.js
@@ -104,17 +104,30 @@ my.DataExplorer = Backbone.View.extend({
|
|||||||
this.router = new Backbone.Router();
|
this.router = new Backbone.Router();
|
||||||
this.setupRouting();
|
this.setupRouting();
|
||||||
|
|
||||||
this.model.bind('query:start', function(eventName) {
|
this.model.bind('query:start', function() {
|
||||||
my.notify('Loading data', {loader: true});
|
my.notify('Loading data', {loader: true});
|
||||||
});
|
});
|
||||||
this.model.bind('query:done', function(eventName) {
|
this.model.bind('query:done', function() {
|
||||||
my.clearNotifications();
|
my.clearNotifications();
|
||||||
self.el.find('.doc-count').text(self.model.docCount || 'Unknown');
|
self.el.find('.doc-count').text(self.model.docCount || 'Unknown');
|
||||||
my.notify('Data loaded', {category: 'success'});
|
my.notify('Data loaded', {category: 'success'});
|
||||||
});
|
});
|
||||||
this.model.bind('query:fail', function(eventName, error) {
|
this.model.bind('query:fail', function(error) {
|
||||||
my.clearNotifications();
|
my.clearNotifications();
|
||||||
my.notify(error.message, {category: 'error', persist: true});
|
var msg = '';
|
||||||
|
if (typeof(error) == 'string') {
|
||||||
|
msg = error;
|
||||||
|
} else if (typeof(error) == 'object') {
|
||||||
|
if (error.title) {
|
||||||
|
msg = error.title + ': ';
|
||||||
|
}
|
||||||
|
if (error.message) {
|
||||||
|
msg += error.message;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
msg = 'There was an error querying the backend';
|
||||||
|
}
|
||||||
|
my.notify(msg, {category: 'error', persist: true});
|
||||||
});
|
});
|
||||||
|
|
||||||
// retrieve basic data like fields etc
|
// retrieve basic data like fields etc
|
||||||
@@ -164,8 +177,10 @@ my.DataExplorer = Backbone.View.extend({
|
|||||||
|
|
||||||
updateNav: function(pageName, queryString) {
|
updateNav: function(pageName, queryString) {
|
||||||
this.el.find('.navigation li').removeClass('active');
|
this.el.find('.navigation li').removeClass('active');
|
||||||
|
this.el.find('.navigation li a').removeClass('disabled');
|
||||||
var $el = this.el.find('.navigation li a[href=#' + pageName + ']');
|
var $el = this.el.find('.navigation li a[href=#' + pageName + ']');
|
||||||
$el.parent().addClass('active');
|
$el.parent().addClass('active');
|
||||||
|
$el.addClass('disabled');
|
||||||
// show the specific page
|
// show the specific page
|
||||||
_.each(this.pageViews, function(view, idx) {
|
_.each(this.pageViews, function(view, idx) {
|
||||||
if (view.id === pageName) {
|
if (view.id === pageName) {
|
||||||
@@ -181,13 +196,16 @@ my.DataExplorer = Backbone.View.extend({
|
|||||||
my.QueryEditor = Backbone.View.extend({
|
my.QueryEditor = Backbone.View.extend({
|
||||||
className: 'recline-query-editor',
|
className: 'recline-query-editor',
|
||||||
template: ' \
|
template: ' \
|
||||||
<form action="" method="GET"> \
|
<form action="" method="GET" class="form-inline"> \
|
||||||
<input type="text" name="q" value="{{q}}" class="text-query" /> \
|
<div class="input-prepend text-query"> \
|
||||||
|
<span class="add-on"><i class="icon-search"></i></span> \
|
||||||
|
<input type="text" name="q" value="{{q}}" class="span2" placeholder="Search data ..." class="search-query" /> \
|
||||||
|
</div> \
|
||||||
<div class="pagination"> \
|
<div class="pagination"> \
|
||||||
<ul> \
|
<ul> \
|
||||||
<li class="prev action-pagination-update"><a>« back</a></li> \
|
<li class="prev action-pagination-update"><a>«</a></li> \
|
||||||
<li class="active"><a><input name="from" type="text" value="{{from}}" /> – <input name="to" type="text" value="{{to}}" /> </a></li> \
|
<li class="active"><a><input name="from" type="text" value="{{from}}" /> – <input name="to" type="text" value="{{to}}" /> </a></li> \
|
||||||
<li class="next action-pagination-update"><a>next »</a></li> \
|
<li class="next action-pagination-update"><a>»</a></li> \
|
||||||
</ul> \
|
</ul> \
|
||||||
</div> \
|
</div> \
|
||||||
<button type="submit" class="btn" style="">Update »</button> \
|
<button type="submit" class="btn" style="">Update »</button> \
|
||||||
@@ -209,7 +227,7 @@ my.QueryEditor = Backbone.View.extend({
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var newFrom = parseInt(this.el.find('input[name="from"]').val());
|
var newFrom = parseInt(this.el.find('input[name="from"]').val());
|
||||||
var newSize = parseInt(this.el.find('input[name="to"]').val()) - newFrom;
|
var newSize = parseInt(this.el.find('input[name="to"]').val()) - newFrom;
|
||||||
var query = this.el.find('.text-query').val();
|
var query = this.el.find('.text-query input').val();
|
||||||
this.model.set({size: newSize, from: newFrom, q: query});
|
this.model.set({size: newSize, from: newFrom, q: query});
|
||||||
},
|
},
|
||||||
onPaginationUpdate: function(e) {
|
onPaginationUpdate: function(e) {
|
||||||
@@ -290,7 +308,7 @@ my.setHashQueryString = function(queryParams) {
|
|||||||
|
|
||||||
// ## notify
|
// ## notify
|
||||||
//
|
//
|
||||||
// Create a notification (a div.alert-message in div.alert-messsages) using provide messages and options. Options are:
|
// Create a notification (a div.alert in div.alert-messsages) using provide messages and options. Options are:
|
||||||
//
|
//
|
||||||
// * category: warning (default), success, error
|
// * category: warning (default), success, error
|
||||||
// * persist: if true alert is persistent, o/w hidden after 3s (default = false)
|
// * persist: if true alert is persistent, o/w hidden after 3s (default = false)
|
||||||
@@ -303,12 +321,11 @@ my.notify = function(message, options) {
|
|||||||
},
|
},
|
||||||
options);
|
options);
|
||||||
var _template = ' \
|
var _template = ' \
|
||||||
<div class="alert-message {{category}} fade in" data-alert="alert"><a class="close" href="#">×</a> \
|
<div class="alert alert-{{category}} fade in" data-alert="alert"><a class="close" data-dismiss="alert" href="#">×</a> \
|
||||||
<p>{{msg}} \
|
{{msg}} \
|
||||||
{{#loader}} \
|
{{#loader}} \
|
||||||
<img src="images/small-spinner.gif" class="notification-loader"> \
|
<span class="notification-loader"> </span> \
|
||||||
{{/loader}} \
|
{{/loader}} \
|
||||||
</p> \
|
|
||||||
</div>';
|
</div>';
|
||||||
var _templated = $.mustache(_template, tmplData);
|
var _templated = $.mustache(_template, tmplData);
|
||||||
_templated = $(_templated).appendTo($('.data-explorer .alert-messages'));
|
_templated = $(_templated).appendTo($('.data-explorer .alert-messages'));
|
||||||
@@ -325,7 +342,7 @@ my.notify = function(message, options) {
|
|||||||
//
|
//
|
||||||
// Clear all existing notifications
|
// Clear all existing notifications
|
||||||
my.clearNotifications = function() {
|
my.clearNotifications = function() {
|
||||||
var $notifications = $('.data-explorer .alert-message');
|
var $notifications = $('.data-explorer .alert-messages .alert');
|
||||||
$notifications.remove();
|
$notifications.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
18
vendor/000-jquery-1.6.1.min.js
vendored
18
vendor/000-jquery-1.6.1.min.js
vendored
File diff suppressed because one or more lines are too long
113
vendor/bootstrap/1.4.0/bootstrap-alerts.js
vendored
113
vendor/bootstrap/1.4.0/bootstrap-alerts.js
vendored
@@ -1,113 +0,0 @@
|
|||||||
/* ==========================================================
|
|
||||||
* bootstrap-alerts.js v1.4.0
|
|
||||||
* http://twitter.github.com/bootstrap/javascript.html#alerts
|
|
||||||
* ==========================================================
|
|
||||||
* Copyright 2011 Twitter, Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
* ========================================================== */
|
|
||||||
|
|
||||||
|
|
||||||
!function( $ ){
|
|
||||||
|
|
||||||
"use strict"
|
|
||||||
|
|
||||||
/* CSS TRANSITION SUPPORT (https://gist.github.com/373874)
|
|
||||||
* ======================================================= */
|
|
||||||
|
|
||||||
var transitionEnd
|
|
||||||
|
|
||||||
$(document).ready(function () {
|
|
||||||
|
|
||||||
$.support.transition = (function () {
|
|
||||||
var thisBody = document.body || document.documentElement
|
|
||||||
, thisStyle = thisBody.style
|
|
||||||
, support = thisStyle.transition !== undefined || thisStyle.WebkitTransition !== undefined || thisStyle.MozTransition !== undefined || thisStyle.MsTransition !== undefined || thisStyle.OTransition !== undefined
|
|
||||||
return support
|
|
||||||
})()
|
|
||||||
|
|
||||||
// set CSS transition event type
|
|
||||||
if ( $.support.transition ) {
|
|
||||||
transitionEnd = "TransitionEnd"
|
|
||||||
if ( $.browser.webkit ) {
|
|
||||||
transitionEnd = "webkitTransitionEnd"
|
|
||||||
} else if ( $.browser.mozilla ) {
|
|
||||||
transitionEnd = "transitionend"
|
|
||||||
} else if ( $.browser.opera ) {
|
|
||||||
transitionEnd = "oTransitionEnd"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
/* ALERT CLASS DEFINITION
|
|
||||||
* ====================== */
|
|
||||||
|
|
||||||
var Alert = function ( content, options ) {
|
|
||||||
this.settings = $.extend({}, $.fn.alert.defaults, options)
|
|
||||||
this.$element = $(content)
|
|
||||||
.delegate(this.settings.selector, 'click', this.close)
|
|
||||||
}
|
|
||||||
|
|
||||||
Alert.prototype = {
|
|
||||||
|
|
||||||
close: function (e) {
|
|
||||||
var $element = $(this).parent('.alert-message')
|
|
||||||
|
|
||||||
e && e.preventDefault()
|
|
||||||
$element.removeClass('in')
|
|
||||||
|
|
||||||
function removeElement () {
|
|
||||||
$element.remove()
|
|
||||||
}
|
|
||||||
|
|
||||||
$.support.transition && $element.hasClass('fade') ?
|
|
||||||
$element.bind(transitionEnd, removeElement) :
|
|
||||||
removeElement()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ALERT PLUGIN DEFINITION
|
|
||||||
* ======================= */
|
|
||||||
|
|
||||||
$.fn.alert = function ( options ) {
|
|
||||||
|
|
||||||
if ( options === true ) {
|
|
||||||
return this.data('alert')
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.each(function () {
|
|
||||||
var $this = $(this)
|
|
||||||
|
|
||||||
if ( typeof options == 'string' ) {
|
|
||||||
return $this.data('alert')[options]()
|
|
||||||
}
|
|
||||||
|
|
||||||
$(this).data('alert', new Alert( this, options ))
|
|
||||||
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
$.fn.alert.defaults = {
|
|
||||||
selector: '.close'
|
|
||||||
}
|
|
||||||
|
|
||||||
$(document).ready(function () {
|
|
||||||
new Alert($('body'), {
|
|
||||||
selector: '.alert-message[data-alert] .close'
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
}( window.jQuery || window.ender );
|
|
||||||
2467
vendor/bootstrap/1.4.0/bootstrap.css
vendored
2467
vendor/bootstrap/1.4.0/bootstrap.css
vendored
File diff suppressed because it is too large
Load Diff
1722
vendor/bootstrap/2.0.0/bootstrap.js
vendored
Normal file
1722
vendor/bootstrap/2.0.0/bootstrap.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
567
vendor/bootstrap/2.0.0/css/bootstrap-responsive.css
vendored
Normal file
567
vendor/bootstrap/2.0.0/css/bootstrap-responsive.css
vendored
Normal file
@@ -0,0 +1,567 @@
|
|||||||
|
/*!
|
||||||
|
* Bootstrap Responsive 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.
|
||||||
|
*/
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.nav-collapse {
|
||||||
|
-webkit-transform: translate3d(0, 0, 0);
|
||||||
|
}
|
||||||
|
.page-header h1 small {
|
||||||
|
display: block;
|
||||||
|
line-height: 18px;
|
||||||
|
}
|
||||||
|
input[class*="span"],
|
||||||
|
select[class*="span"],
|
||||||
|
textarea[class*="span"],
|
||||||
|
.uneditable-input {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: 28px;
|
||||||
|
/* Make inputs at least the height of their button counterpart */
|
||||||
|
|
||||||
|
/* Makes inputs behave like true block-level elements */
|
||||||
|
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
/* Older Webkit */
|
||||||
|
|
||||||
|
-moz-box-sizing: border-box;
|
||||||
|
/* Older FF */
|
||||||
|
|
||||||
|
-ms-box-sizing: border-box;
|
||||||
|
/* IE8 */
|
||||||
|
|
||||||
|
box-sizing: border-box;
|
||||||
|
/* CSS3 spec*/
|
||||||
|
|
||||||
|
}
|
||||||
|
.input-prepend input[class*="span"], .input-append input[class*="span"] {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
input[type="checkbox"], input[type="radio"] {
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
.form-horizontal .control-group > label {
|
||||||
|
float: none;
|
||||||
|
width: auto;
|
||||||
|
padding-top: 0;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
.form-horizontal .controls {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
.form-horizontal .control-list {
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
.form-horizontal .form-actions {
|
||||||
|
padding-left: 10px;
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
||||||
|
.modal {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
left: 10px;
|
||||||
|
right: 10px;
|
||||||
|
width: auto;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.modal.fade.in {
|
||||||
|
top: auto;
|
||||||
|
}
|
||||||
|
.modal-header .close {
|
||||||
|
padding: 10px;
|
||||||
|
margin: -10px;
|
||||||
|
}
|
||||||
|
.carousel-caption {
|
||||||
|
position: static;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.container {
|
||||||
|
width: auto;
|
||||||
|
padding: 0 20px;
|
||||||
|
}
|
||||||
|
.row-fluid {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.row {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
.row > [class*="span"], .row-fluid > [class*="span"] {
|
||||||
|
float: none;
|
||||||
|
display: block;
|
||||||
|
width: auto;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (min-width: 768px) and (max-width: 980px) {
|
||||||
|
.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: 42px;
|
||||||
|
}
|
||||||
|
.span2 {
|
||||||
|
width: 104px;
|
||||||
|
}
|
||||||
|
.span3 {
|
||||||
|
width: 166px;
|
||||||
|
}
|
||||||
|
.span4 {
|
||||||
|
width: 228px;
|
||||||
|
}
|
||||||
|
.span5 {
|
||||||
|
width: 290px;
|
||||||
|
}
|
||||||
|
.span6 {
|
||||||
|
width: 352px;
|
||||||
|
}
|
||||||
|
.span7 {
|
||||||
|
width: 414px;
|
||||||
|
}
|
||||||
|
.span8 {
|
||||||
|
width: 476px;
|
||||||
|
}
|
||||||
|
.span9 {
|
||||||
|
width: 538px;
|
||||||
|
}
|
||||||
|
.span10 {
|
||||||
|
width: 600px;
|
||||||
|
}
|
||||||
|
.span11 {
|
||||||
|
width: 662px;
|
||||||
|
}
|
||||||
|
.span12, .container {
|
||||||
|
width: 724px;
|
||||||
|
}
|
||||||
|
.offset1 {
|
||||||
|
margin-left: 82px;
|
||||||
|
}
|
||||||
|
.offset2 {
|
||||||
|
margin-left: 144px;
|
||||||
|
}
|
||||||
|
.offset3 {
|
||||||
|
margin-left: 206px;
|
||||||
|
}
|
||||||
|
.offset4 {
|
||||||
|
margin-left: 268px;
|
||||||
|
}
|
||||||
|
.offset5 {
|
||||||
|
margin-left: 330px;
|
||||||
|
}
|
||||||
|
.offset6 {
|
||||||
|
margin-left: 392px;
|
||||||
|
}
|
||||||
|
.offset7 {
|
||||||
|
margin-left: 454px;
|
||||||
|
}
|
||||||
|
.offset8 {
|
||||||
|
margin-left: 516px;
|
||||||
|
}
|
||||||
|
.offset9 {
|
||||||
|
margin-left: 578px;
|
||||||
|
}
|
||||||
|
.offset10 {
|
||||||
|
margin-left: 640px;
|
||||||
|
}
|
||||||
|
.offset11 {
|
||||||
|
margin-left: 702px;
|
||||||
|
}
|
||||||
|
.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.762430939%;
|
||||||
|
}
|
||||||
|
.row-fluid > [class*="span"]:first-child {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
.row-fluid .span1 {
|
||||||
|
width: 5.801104972%;
|
||||||
|
}
|
||||||
|
.row-fluid .span2 {
|
||||||
|
width: 14.364640883%;
|
||||||
|
}
|
||||||
|
.row-fluid .span3 {
|
||||||
|
width: 22.928176794%;
|
||||||
|
}
|
||||||
|
.row-fluid .span4 {
|
||||||
|
width: 31.491712705%;
|
||||||
|
}
|
||||||
|
.row-fluid .span5 {
|
||||||
|
width: 40.055248616%;
|
||||||
|
}
|
||||||
|
.row-fluid .span6 {
|
||||||
|
width: 48.618784527%;
|
||||||
|
}
|
||||||
|
.row-fluid .span7 {
|
||||||
|
width: 57.182320438000005%;
|
||||||
|
}
|
||||||
|
.row-fluid .span8 {
|
||||||
|
width: 65.74585634900001%;
|
||||||
|
}
|
||||||
|
.row-fluid .span9 {
|
||||||
|
width: 74.30939226%;
|
||||||
|
}
|
||||||
|
.row-fluid .span10 {
|
||||||
|
width: 82.87292817100001%;
|
||||||
|
}
|
||||||
|
.row-fluid .span11 {
|
||||||
|
width: 91.436464082%;
|
||||||
|
}
|
||||||
|
.row-fluid .span12 {
|
||||||
|
width: 99.999999993%;
|
||||||
|
}
|
||||||
|
input.span1, textarea.span1, .uneditable-input.span1 {
|
||||||
|
width: 32px;
|
||||||
|
}
|
||||||
|
input.span2, textarea.span2, .uneditable-input.span2 {
|
||||||
|
width: 94px;
|
||||||
|
}
|
||||||
|
input.span3, textarea.span3, .uneditable-input.span3 {
|
||||||
|
width: 156px;
|
||||||
|
}
|
||||||
|
input.span4, textarea.span4, .uneditable-input.span4 {
|
||||||
|
width: 218px;
|
||||||
|
}
|
||||||
|
input.span5, textarea.span5, .uneditable-input.span5 {
|
||||||
|
width: 280px;
|
||||||
|
}
|
||||||
|
input.span6, textarea.span6, .uneditable-input.span6 {
|
||||||
|
width: 342px;
|
||||||
|
}
|
||||||
|
input.span7, textarea.span7, .uneditable-input.span7 {
|
||||||
|
width: 404px;
|
||||||
|
}
|
||||||
|
input.span8, textarea.span8, .uneditable-input.span8 {
|
||||||
|
width: 466px;
|
||||||
|
}
|
||||||
|
input.span9, textarea.span9, .uneditable-input.span9 {
|
||||||
|
width: 528px;
|
||||||
|
}
|
||||||
|
input.span10, textarea.span10, .uneditable-input.span10 {
|
||||||
|
width: 590px;
|
||||||
|
}
|
||||||
|
input.span11, textarea.span11, .uneditable-input.span11 {
|
||||||
|
width: 652px;
|
||||||
|
}
|
||||||
|
input.span12, textarea.span12, .uneditable-input.span12 {
|
||||||
|
width: 714px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (max-width: 980px) {
|
||||||
|
body {
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
.navbar-fixed-top {
|
||||||
|
position: static;
|
||||||
|
margin-bottom: 18px;
|
||||||
|
}
|
||||||
|
.navbar-fixed-top .navbar-inner {
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
.navbar .container {
|
||||||
|
width: auto;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.navbar .brand {
|
||||||
|
padding-left: 10px;
|
||||||
|
padding-right: 10px;
|
||||||
|
margin: 0 0 0 -5px;
|
||||||
|
}
|
||||||
|
.navbar .nav-collapse {
|
||||||
|
clear: left;
|
||||||
|
}
|
||||||
|
.navbar .nav {
|
||||||
|
float: none;
|
||||||
|
margin: 0 0 9px;
|
||||||
|
}
|
||||||
|
.navbar .nav > li {
|
||||||
|
float: none;
|
||||||
|
}
|
||||||
|
.navbar .nav > li > a {
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
.navbar .nav > .divider-vertical {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.navbar .nav > li > a, .navbar .dropdown-menu a {
|
||||||
|
padding: 6px 15px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #999999;
|
||||||
|
-webkit-border-radius: 3px;
|
||||||
|
-moz-border-radius: 3px;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
.navbar .dropdown-menu li + li a {
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
.navbar .nav > li > a:hover, .navbar .dropdown-menu a:hover {
|
||||||
|
background-color: #222222;
|
||||||
|
}
|
||||||
|
.navbar .dropdown-menu {
|
||||||
|
position: static;
|
||||||
|
top: auto;
|
||||||
|
left: auto;
|
||||||
|
float: none;
|
||||||
|
display: block;
|
||||||
|
max-width: none;
|
||||||
|
margin: 0 15px;
|
||||||
|
padding: 0;
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
-webkit-border-radius: 0;
|
||||||
|
-moz-border-radius: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
-webkit-box-shadow: none;
|
||||||
|
-moz-box-shadow: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
.navbar .dropdown-menu:before, .navbar .dropdown-menu:after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.navbar .dropdown-menu .divider {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.navbar-form, .navbar-search {
|
||||||
|
float: none;
|
||||||
|
padding: 9px 15px;
|
||||||
|
margin: 9px 0;
|
||||||
|
border-top: 1px solid #222222;
|
||||||
|
border-bottom: 1px solid #222222;
|
||||||
|
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
|
||||||
|
-moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
|
||||||
|
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
|
.navbar .nav.pull-right {
|
||||||
|
float: none;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
.navbar-static .navbar-inner {
|
||||||
|
padding-left: 10px;
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
||||||
|
.btn-navbar {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.nav-collapse {
|
||||||
|
overflow: hidden;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (min-width: 980px) {
|
||||||
|
.nav-collapse.collapse {
|
||||||
|
height: auto !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (min-width: 1200px) {
|
||||||
|
.row {
|
||||||
|
margin-left: -30px;
|
||||||
|
*zoom: 1;
|
||||||
|
}
|
||||||
|
.row:before, .row:after {
|
||||||
|
display: table;
|
||||||
|
content: "";
|
||||||
|
}
|
||||||
|
.row:after {
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
[class*="span"] {
|
||||||
|
float: left;
|
||||||
|
margin-left: 30px;
|
||||||
|
}
|
||||||
|
.span1 {
|
||||||
|
width: 70px;
|
||||||
|
}
|
||||||
|
.span2 {
|
||||||
|
width: 170px;
|
||||||
|
}
|
||||||
|
.span3 {
|
||||||
|
width: 270px;
|
||||||
|
}
|
||||||
|
.span4 {
|
||||||
|
width: 370px;
|
||||||
|
}
|
||||||
|
.span5 {
|
||||||
|
width: 470px;
|
||||||
|
}
|
||||||
|
.span6 {
|
||||||
|
width: 570px;
|
||||||
|
}
|
||||||
|
.span7 {
|
||||||
|
width: 670px;
|
||||||
|
}
|
||||||
|
.span8 {
|
||||||
|
width: 770px;
|
||||||
|
}
|
||||||
|
.span9 {
|
||||||
|
width: 870px;
|
||||||
|
}
|
||||||
|
.span10 {
|
||||||
|
width: 970px;
|
||||||
|
}
|
||||||
|
.span11 {
|
||||||
|
width: 1070px;
|
||||||
|
}
|
||||||
|
.span12, .container {
|
||||||
|
width: 1170px;
|
||||||
|
}
|
||||||
|
.offset1 {
|
||||||
|
margin-left: 130px;
|
||||||
|
}
|
||||||
|
.offset2 {
|
||||||
|
margin-left: 230px;
|
||||||
|
}
|
||||||
|
.offset3 {
|
||||||
|
margin-left: 330px;
|
||||||
|
}
|
||||||
|
.offset4 {
|
||||||
|
margin-left: 430px;
|
||||||
|
}
|
||||||
|
.offset5 {
|
||||||
|
margin-left: 530px;
|
||||||
|
}
|
||||||
|
.offset6 {
|
||||||
|
margin-left: 630px;
|
||||||
|
}
|
||||||
|
.offset7 {
|
||||||
|
margin-left: 730px;
|
||||||
|
}
|
||||||
|
.offset8 {
|
||||||
|
margin-left: 830px;
|
||||||
|
}
|
||||||
|
.offset9 {
|
||||||
|
margin-left: 930px;
|
||||||
|
}
|
||||||
|
.offset10 {
|
||||||
|
margin-left: 1030px;
|
||||||
|
}
|
||||||
|
.offset11 {
|
||||||
|
margin-left: 1130px;
|
||||||
|
}
|
||||||
|
.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.564102564%;
|
||||||
|
}
|
||||||
|
.row-fluid > [class*="span"]:first-child {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
.row-fluid .span1 {
|
||||||
|
width: 5.982905983%;
|
||||||
|
}
|
||||||
|
.row-fluid .span2 {
|
||||||
|
width: 14.529914530000001%;
|
||||||
|
}
|
||||||
|
.row-fluid .span3 {
|
||||||
|
width: 23.076923077%;
|
||||||
|
}
|
||||||
|
.row-fluid .span4 {
|
||||||
|
width: 31.623931624%;
|
||||||
|
}
|
||||||
|
.row-fluid .span5 {
|
||||||
|
width: 40.170940171000005%;
|
||||||
|
}
|
||||||
|
.row-fluid .span6 {
|
||||||
|
width: 48.717948718%;
|
||||||
|
}
|
||||||
|
.row-fluid .span7 {
|
||||||
|
width: 57.264957265%;
|
||||||
|
}
|
||||||
|
.row-fluid .span8 {
|
||||||
|
width: 65.81196581200001%;
|
||||||
|
}
|
||||||
|
.row-fluid .span9 {
|
||||||
|
width: 74.358974359%;
|
||||||
|
}
|
||||||
|
.row-fluid .span10 {
|
||||||
|
width: 82.905982906%;
|
||||||
|
}
|
||||||
|
.row-fluid .span11 {
|
||||||
|
width: 91.45299145300001%;
|
||||||
|
}
|
||||||
|
.row-fluid .span12 {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
input.span1, textarea.span1, .uneditable-input.span1 {
|
||||||
|
width: 60px;
|
||||||
|
}
|
||||||
|
input.span2, textarea.span2, .uneditable-input.span2 {
|
||||||
|
width: 160px;
|
||||||
|
}
|
||||||
|
input.span3, textarea.span3, .uneditable-input.span3 {
|
||||||
|
width: 260px;
|
||||||
|
}
|
||||||
|
input.span4, textarea.span4, .uneditable-input.span4 {
|
||||||
|
width: 360px;
|
||||||
|
}
|
||||||
|
input.span5, textarea.span5, .uneditable-input.span5 {
|
||||||
|
width: 460px;
|
||||||
|
}
|
||||||
|
input.span6, textarea.span6, .uneditable-input.span6 {
|
||||||
|
width: 560px;
|
||||||
|
}
|
||||||
|
input.span7, textarea.span7, .uneditable-input.span7 {
|
||||||
|
width: 660px;
|
||||||
|
}
|
||||||
|
input.span8, textarea.span8, .uneditable-input.span8 {
|
||||||
|
width: 760px;
|
||||||
|
}
|
||||||
|
input.span9, textarea.span9, .uneditable-input.span9 {
|
||||||
|
width: 860px;
|
||||||
|
}
|
||||||
|
input.span10, textarea.span10, .uneditable-input.span10 {
|
||||||
|
width: 960px;
|
||||||
|
}
|
||||||
|
input.span11, textarea.span11, .uneditable-input.span11 {
|
||||||
|
width: 1060px;
|
||||||
|
}
|
||||||
|
input.span12, textarea.span12, .uneditable-input.span12 {
|
||||||
|
width: 1160px;
|
||||||
|
}
|
||||||
|
.thumbnails {
|
||||||
|
margin-left: -30px;
|
||||||
|
}
|
||||||
|
.thumbnails > li {
|
||||||
|
margin-left: 30px;
|
||||||
|
}
|
||||||
|
}
|
||||||
3365
vendor/bootstrap/2.0.0/css/bootstrap.css
vendored
Normal file
3365
vendor/bootstrap/2.0.0/css/bootstrap.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
BIN
vendor/bootstrap/2.0.0/img/glyphicons-halflings-white.png
vendored
Normal file
BIN
vendor/bootstrap/2.0.0/img/glyphicons-halflings-white.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.3 KiB |
BIN
vendor/bootstrap/2.0.0/img/glyphicons-halflings.png
vendored
Normal file
BIN
vendor/bootstrap/2.0.0/img/glyphicons-halflings.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.3 KiB |
9266
vendor/jquery-1.7.1.js
vendored
Normal file
9266
vendor/jquery-1.7.1.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user