diff --git a/css/bootstrap.css b/css/bootstrap.css deleted file mode 100644 index f12b390c..00000000 --- a/css/bootstrap.css +++ /dev/null @@ -1,39 +0,0 @@ -body { - padding-top: 60px; -} - -/* we do not have a LH sidebar */ -.container-fluid > .content { - margin-left: 0; -} - -/* direct borrowing from twitter buttons */ -.data-table th, -.transform-column-view .expression-preview-table-wrapper th -{ - 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); - text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); - color: #333; - 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; -} - diff --git a/css/data-explorer.css b/css/data-explorer.css index 7f410fe8..b2df878d 100644 --- a/css/data-explorer.css +++ b/css/data-explorer.css @@ -29,24 +29,28 @@ .header .recline-query-editor .text-query input { float: left; - margin-right: 5px; } -.header .recline-query-editor .pagination input { - width: 30px; - height: 18px; - padding: 2px 4px; - margin-top: -4px; +.recline-query-editor .text-query .btn-group { + display: inline; + float:left; + margin-left:-2px; +} + +.recline-query-editor .text-query .btn-group .dropdown-toggle { + -moz-border-radius:0px 3px 3px 0px; + -webkit-border-radius:0px 3px 3px 0px; + border-radius:0px 3px 3px 0px; +} + +.recline-query-editor .text-query .btn-group ul { + margin-left:-110px; } .header .recline-query-editor .pagination a { line-height: 26px; } -.header .recline-query-editor form .btn { - vertical-align: top; -} - .data-view-container { display: block; clear: both; @@ -68,6 +72,11 @@ * Data Table *********************************************************/ +.data-table .btn-group .dropdown-toggle { + padding: 1px 3px; + line-height: auto; +} + .data-table-container { overflow: auto; height: 550px; @@ -75,7 +84,6 @@ .data-table { border: 1px solid #ccc; - font-size: 12px; width: 100%; } @@ -89,44 +97,49 @@ width: 20px; } +/* direct borrowing from twitter buttons */ +.data-table th, +.transform-column-view .expression-preview-table-wrapper th +{ + 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); + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + color: #333; + 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; +} + + /********************************************************** * Data Table Menus *********************************************************/ -a.column-header-menu, a.root-header-menu { +.column-header-menu, a.root-header-menu { float: right; - display: block; - margin: 0 4px 0 0; - width: 17px; - height: 19px; - background-image: url(images/menu-dropdown.png); - background-repeat: no-repeat; -} - -a.row-header-menu:hover, a.root-header-menu:hover { - background-position: -17px 0px; - text-decoration: none; -} - -a.row-header-menu { - float: left; - display: block; - margin: -2px 0 -4px 0; - width: 17px; - height: 18px; - background-image: url(images/menu-dropdown.png); - background-repeat: no-repeat; } .read-only a.row-header-menu { display: none; } -a.column-header-menu:hover { - background-position: -17px 0px; - text-decoration: none; -} - .column-header-recon-stats-bar { margin-top: 10px; height: 4px; @@ -192,45 +205,6 @@ div.data-table-cell-content-numeric > a.data-table-cell-edit { color: red; } -.data-table-menu-overlay { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; -} - -ul.data-table-menu { - display: none; - outline-style: none; - background: white; - color: black; - font-size: 12px; - height: auto; - list-style: none; - overflow: hidden; - position: absolute; - text-align: left; - width: 120px; - z-index: 666; - border: 1px solid #CCC; - border-right: 1px solid #666; - border-bottom: 1px solid #666; - margin: 0; padding: 0; } - ul.data-table-menu * { - margin: 0; - padding: 0; } - ul.data-table-menu a { - line-height: 14px; - color: black; - display: block; - padding: 5px 7px; - text-decoration: none; } - ul.data-table-menu li { - height: 24px; } - ul.data-table-menu li:hover { - background-color: #DBE8F8 } - /* TODO: not sure the rest of this is needed */ .data-table-cell-editor, .data-table-topic-popup { overflow: auto; diff --git a/css/images/menu-dropdown.png b/css/images/menu-dropdown.png deleted file mode 100755 index c733fef7..00000000 Binary files a/css/images/menu-dropdown.png and /dev/null differ diff --git a/demo/built.html b/demo/built.html index 1e8aa11b..4772e032 100644 --- a/demo/built.html +++ b/demo/built.html @@ -13,7 +13,7 @@ - + @@ -39,7 +39,7 @@ diff --git a/demo/index.html b/demo/index.html index 84fed08f..a99181de 100644 --- a/demo/index.html +++ b/demo/index.html @@ -13,7 +13,7 @@ - + @@ -33,9 +33,9 @@ - + @@ -57,7 +57,7 @@ diff --git a/demo/js/app.js b/demo/js/app.js index d0bdc03a..1cbab287 100755 --- a/demo/js/app.js +++ b/demo/js/app.js @@ -1,7 +1,54 @@ $(function() { + var qs = recline.View.parseQueryString(window.location.search); + if (qs.url) { + var dataset = new recline.Model.Dataset({ + id: 'my-dataset', + url: qs.url, + webstore_url: qs.url + }, + qs.backend || 'elasticsearch' + ); + } else { + dataset = localDataset(); + } + + createExplorer(dataset); + Backbone.history.start(); + + // setup the loader menu in top bar + setupLoader(createExplorer); + + // set up readonly enabling in top bar + $('a.set-read-only').click(function() { + window.dataExplorer.setReadOnly(); + alert('Read-only mode set'); + }); +}); + +// make Explorer creation / initialization in a function so we can call it +// again and again +function createExplorer(dataset) { + // remove existing data explorer view + if (window.dataExplorer) { + window.dataExplorer.remove(); + } + window.dataExplorer = null; var $el = $('
'); $el.appendTo($('.data-explorer-here')); - var dataset = demoDataset(); + var views = standardViews(dataset); + window.dataExplorer = new recline.View.DataExplorer({ + el: $el + , model: dataset + , views: views + }); + // HACK (a bit). Issue is that Backbone will not trigger the route + // if you are already at that location so we have to make sure we genuinely switch + window.dataExplorer.router.navigate('graph'); + window.dataExplorer.router.navigate('', true); +} + +// convenience function +function standardViews(dataset) { var views = [ { id: 'grid', @@ -18,33 +65,11 @@ $(function() { }) } ]; - window.dataExplorer = new recline.View.DataExplorer({ - el: $el - , model: dataset - , views: views - }); - Backbone.history.start(); - setupLoadFromWebstore(function(dataset) { - window.dataExplorer.remove(); - var $el = $('
'); - $el.appendTo($('.data-explorer-here')); - window.dataExplorer = null; - window.dataExplorer = new recline.View.DataExplorer({ - el: $el - , model: dataset - }); - // HACK (a bit). Issue is that Backbone will not trigger the route - // if you are already at that location so we have to make sure we genuinely switch - window.dataExplorer.router.navigate('graph'); - window.dataExplorer.router.navigate('', true); - }); - $('a.set-read-only').click(function() { - window.dataExplorer.setReadOnly(); - alert('Read-only mode set'); - }); -}) + return views; +} -function demoDataset() { +// provide a demonstration in memory dataset +function localDataset() { var datasetId = 'test-dataset'; var inData = { metadata: { @@ -68,7 +93,8 @@ function demoDataset() { return dataset; } -function setupLoadFromWebstore(callback) { +// setup the loader menu in top bar +function setupLoader(callback) { // pre-populate webstore load form with an example url var demoUrl = 'http://thedatahub.org/api/data/b9aae52b-b082-4159-b46f-7bb9c158d013'; $('form.webstore-load input[name="source"]').val(demoUrl); diff --git a/demo/original.html b/demo/original.html deleted file mode 100755 index 5768e297..00000000 --- a/demo/original.html +++ /dev/null @@ -1,248 +0,0 @@ - - - - - Data Explorer - - - - - - - - - - - - - - - - - - - - -
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/demo/style/data-table.css b/demo/style/data-table.css deleted file mode 100755 index c455ce8b..00000000 --- a/demo/style/data-table.css +++ /dev/null @@ -1,1184 +0,0 @@ -/* - -Copyright 2010, Google Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -*/ - -html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, abbr, address, cite, code, del, dfn, em, img, ins, kbd, q, samp, small, strong, sub, sup, var, b, i, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, figure, footer, header, hgroup, menu, nav, section, menu, time, mark, audio, video { - margin: 0; - padding: 0; - border: 0; - outline: 0; - font-size: 100%; - vertical-align: baseline; - background: transparent; -} - -article, aside, figure, footer, header, hgroup, nav, section { - display: block; -} - -ul { - list-style-position: inside; -} - -a { - margin: 0; - padding: 0; - font-size: 100%; - vertical-align: baseline; - background: transparent; -} - -table { - border-collapse: collapse; - border-spacing: 0; -} - -input, select { -} - -body { - font-size: 62.5%; - font-family: Arial, sans-serif; - background: #fff; -} - -h1 { - font-size: 1.8em; -} - -h2 { - font-size: 1.3em; - font-weight: bold; -} - -input[type=text], input[type=password]{ - padding: 3px; - font-size: 1em; - font-family: inherit; - border: #ccc 1px solid; - border-top: #888 1px solid; - vertical-align: baseline; -} - -a { - color: #11c; - text-decoration: none; -} - -a:hover { - text-decoration: underline; -} - -a.secondary { - color: #4272db; -} - -a.action, a.selected, a.inaction { - margin: 0 3px; -} - -a.selected { - color: #000; - font-weight: bold; - cursor: default; -} - -a.inaction { - color: #999; -} - -a.selected:hover, a.inaction:hover { - cursor: default; - text-decoration: none; -} - -a img { - border: 0; -} - -.form-table th, .form-table td { - vertical-align: top; - font-size: 1.3em; - padding: 2px; -} - -.form-table th { - text-align: left; - padding-top: 8px; - font-weight: bold; -} - -.list-table { - width: 100%; -} - -.list-table th, .list-table td { - padding-top: 5px; - text-align: left; - vertical-align: baseline; - padding: 3px 5px; - font-size: 1.1em; - color: #777; - border-bottom: dotted 1px #ddd; -} - -.list-table th { - font-weight: bold; - color: #444; - background: #f2f2f2; -} - -.list-table-itemname { - font-size: 1.2em; -} - -#loading-message { - text-align: center; - font-size: 300%; - color: #999; - padding: 3em .5em; -} - -#loading-message img { - position: relative; - top: -4px; -} - -.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 { - padding: 0 3px 0 0; - opacity: 0.3; -} - -#header { - max-height: 40px; - padding: 6px; - position: relative; - overflow: hidden; -} - -#app-home-button { - position: absolute; - top: 0; - left: 0; -} - -#body-info { - margin: 0 40px; -} - -#body-info p { - font-size: 1.3em; - margin: 1.3em; - width: 50em; - line-height: 1.3; -} - -#body-info h1 { - font-size: 3.0em; - font-weight: normal; - color: #777; -} - -#body-info h2 { - margin: 1.6em 0 .5em 0; -} - -#body-info .license, #body-info .errorstack { - font-family: monospace; - font-size: 1.3em; - white-space: pre; - border: 1px solid #ddd; - background: #eee; - padding: 15px; - width: 60em; - overflow: auto; -} - -#body-info ul { - font-size: 1.3em; - margin: .5em 0 2em; -} - -#body-info li { - margin: 0.4em; -} - -input[type="checkbox"], input[type="radio"], select { - vertical-align: baseline; -} - -input.inline { - vertical-align: middle; -} - -div.grid-layout > table { - border-collapse: separate; -} - -div.grid-layout.layout-full > table { - width: 100%; - max-width: 100% !important; -} - -div.grid-layout > table > tbody > tr > th, div.grid-layout > table > tbody > tr > td { - padding: 0px; - text-align: left; - vertical-align: baseline; -} - -div.grid-layout.grid-layout-for-text > table > tbody > tr > th, div.grid-layout.grid-layout-for-text > table > tbody > tr > td { - vertical-align: middle; -} - -div.grid-layout.grid-layout-for-ui > table > tbody > tr > th, div.grid-layout.grid-layout-for-ui > table > tbody > tr > td { - vertical-align: top; -} - -div.grid-layout.layout-normal { - margin: -10px; -} - -div.grid-layout.layout-normal > table { - border-spacing: 10px; -} - -div.grid-layout.layout-tight { - margin: -7px; -} - -div.grid-layout.layout-tight > table { - border-spacing: 7px; -} - -div.grid-layout.layout-tighter { - margin: -5px; -} - -div.grid-layout.layout-tighter > table { - border-spacing: 5px; -} - -div.grid-layout.layout-tightest { - margin: -3px; -} - -div.grid-layout.layout-tightest > table { - border-spacing: 3px; -} - -div.grid-layout.layout-loose { - margin: -15px; -} - -div.grid-layout.layout-loose > table { - border-spacing: 15px; -} - -div.grid-layout.layout-looser { - margin: -20px; -} - -div.grid-layout.layout-looser > table { - border-spacing: 20px; -} - -div.input-container { - padding: 3px; -} - -div.input-container > input, div.input-container > textarea { - display: block; - width: 100%; - padding: 2px; - border: 1px inset; - margin-left: -3px; - margin-top: -3px; - vertical-align: top; -} - -input.code, textarea.code { - font-family: monospace; -} - -img { - vertical-align: middle; -} - -.hidden { - display: none; - visibility: hidden !important; -} - -.fbs-pane, .fbs-flyout-pane { - z-index: 2000; -} - -.ui-widget { - font-family: inherit; - font-size: inherit; -} - -.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { - font-family: inherit; - font-size: inherit; -} - -p.body-text { - margin-bottom: 1em; -} - -/* - -Copyright 2010, Google Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -*/ - -#body { - display: none; -} - -.project-title { - float: left; - padding: 2px 0 0 0; - font-size: 1.6em; -} - -.project-controls, .project-actions { - margin: 0px 2px 0px 0px; - display: block; - float: right; - font-size: 1.3em; -} - -#project-name-button { - padding: 3px; - border: 1px solid transparent; -} - -#project-name-button:hover { - background: #ffffd6; - border: 1px solid #ccc; - border-top: 1px solid #aaa; -} - -#logged-in-status { - padding: 0 4px; - font-size: 11px; -} - -.left-panel { - position: fixed; - overflow: hidden; - padding: 0px; - padding-top: 5px; - font-size: 1.3em; - background: #e3e9ff; -} - -.left-panel .ui-tabs .ui-tabs-panel { - border-left: none; - border-right: none; - border-bottom: none; - padding: 0; -} - -.right-panel { - position: fixed; - top: 40px; - left: 0px; - bottom: 0px; - right: 0px; - overflow: auto; - padding: 0px; - padding-left: 5px; - background: #BCF; -} - -#tool-panel { - position: relative; - height: 32px; -} - -#summary-bar { - position: absolute; - top: 7px; - left: 7px; - font-size: 1.8em; - font-weight: bold; -} - -#summary-total { - font-size: 0.8em; - font-weight: normal; -} - -#extension-bar { - position: absolute; - top: 0px; - right: 10px; - white-space: nowrap; - font-size: 1.3em; - padding: 5px 0; -} - -#extension-bar .secondary { - font-size: 0.85em; -} - -#view-panel { - background: white; - overflow: hidden; -} - -#facet-panel, #history-panel { - overflow: auto; -} - - -/* - -Copyright 2010, Google Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -*/ - -.viewpanel-header { - position: relative; - background: #e3e9ff; - font-size: 1.3em; - padding: 7px; - overflow: hidden; - text-align: right; -} - -.viewpanel-rowrecord, .viewpanel-pagesize, .viewpanel-sorting { - position: absolute; - top: 7px; - background: #e3e9ff; - padding: 0 10px 0 0; -} - -.viewpanel-pagingcount { - font-weight: bold - -} - -.data-table { - margin: 0; - padding: 0; - font-size: 1.1em; - border-collapse: collapse; -} - -.data-table td { - padding: 2px 5px; - border-bottom: 1px dotted #ddd; - border-right: 1px solid #ddd; -} - -.data-table td:hover .data-table-cell-edit { - visibility: visible; -} - -table.data-table > tbody > tr.even > td { - background: #f2f2f2; -} - -table.data-table > tbody > tr.contextual > td > div { - opacity: 0.3; -} - -table.data-table td.column-header { - vertical-align: top; - white-space: nowrap; - background: #f2f2f2; - cursor: pointer; - padding: 4px 6px 4px 4px; - border-right: 1px solid #ddd; - font-weight: bold; -} - -.column-header-name { - margin: 0 0 0 21px; - padding: 4px 0 0 0; - display: block; -} - -a.column-header-menu { - float: left; - display: block; - margin: 0 4px 0 0; - width: 17px; - height: 19px; - background-image: url(images/menu-dropdown.png); - background-repeat: no-repeat; -} - -a.row-header-menu:hover { - background-position: -17px 0px; - text-decoration: none; -} - -a.row-header-menu { - float: left; - display: block; - margin: -2px 0 -4px 0; - width: 17px; - height: 18px; - background-image: url(images/menu-dropdown.png); - background-repeat: no-repeat; -} - -a.column-header-menu:hover { - background-position: -17px 0px; - text-decoration: none; -} - -.column-header-recon-stats-bar { - margin-top: 10px; - height: 4px; - background: #ddd; - border: 1px solid #ccc; - position: relative; - width: 100%; -} - -.column-header-recon-stats-matched { - position: absolute; - height: 100%; - background: #282; -} - -.column-header-recon-stats-blanks { - position: absolute; - height: 100%; - background: #3d3; -} - -div.data-table-cell-content { - line-height: 1.2; - color: #222; - position: relative; -} - -div.data-table-cell-content-numeric { - text-align: right; -} - -a.data-table-cell-edit { - position: absolute; - top: 0; - right: 0; - display: block; - width: 25px; - height: 16px; - text-decoration: none; - background-image: url(images/edit-map.png); - background-repeat: no-repeat; - visibility: hidden; -} - -a.data-table-cell-edit:hover { - background-position: -25px 0px; -} - -div.data-table-cell-content-numeric > a.data-table-cell-edit { - left: 0px; - right: auto; -} - -.data-table-value-nonstring { - color: #282; -} - -.data-table-error { - color: red; -} - -div.data-table-recon-candidates { - padding: 1px 0; - min-width: 15em; - color: #777; -} - -div.data-table-recon-candidate { - padding: 1px 35px 1px; - position: relative; -} - -a.data-table-recon-topic { - color: #4272db; -} - -.data-table-recon-score, .data-table-recon-new { - color: #aaa; - margin: 0 0.5em; -} - -a.data-table-recon-action, .data-table-recon-extra > a { - text-decoration: none; - color: #4272db; -} - -a.data-table-recon-action, .data-table-recon-extra { - font-size: 0.8em; - display: block; - margin: 3px 0 0; -} - -a.data-table-recon-match, a.data-table-recon-match-similar { - position: absolute; - top: 0; - left: 0; - display: block; - width: 16px; - height: 16px; - background-image: url(images/checks-map.png); - background-repeat: no-repeat; - background-position: -16px 0; - text-decoration: none; -} - -a.data-table-recon-match:hover { - background-position: 0 0; -} - -a.data-table-recon-match-similar { - background-position: -16px -16px; - left: 16px; -} - -a.data-table-recon-match-similar:hover { - background-position: 0 -16px; -} - -a.data-table-star-on, a.data-table-star-off, a.data-table-flag-on, a.data-table-flag-off { - display: block; - width: 16px; - height: 16px; - background-image: url(images/star-flag-map.png); - background-repeat: no-repeat; - text-decoration: none; -} - -a.data-table-star-on { - background-position: 0 0; -} - -a.data-table-star-off { - background-position: -17px 0; -} - -a.data-table-flag-on { - background-position: 0 -17px; -} - -a.data-table-flag-off { - background-position: -17px -17px; -} - -.data-table-cell-editor, .data-table-topic-popup { - overflow: auto; - border: 1px solid #bcf; - background: #e3e9ff; - padding: 5px; - -moz-border-radius: 5px; - -webkit-border-radius: 5px; - border-radius: 5px; -} - -.data-table-topic-popup-header { - padding: 0 0 5px; -} - -.data-table-cell-editor-editor { - overflow: hidden; - display: block; - width: 98%; - height: 3em; - font-family: monospace; - margin: 3px 0; -} - -.data-table-cell-copypaste-editor { - overflow: hidden; - display: block; - width: 98%; - height: 10em; - font-family: monospace; - margin: 3px 0; -} - -.data-table-cell-editor-action { - float: left; - vertical-align: bottom; - text-align: center; -} - -.data-table-cell-editor-key { - font-size: 0.8em; - color: #999; -} - -ul.sorting-dialog-blank-error-positions { - margin: 0; - padding: 5px; - height: 10em; - border: 1px solid #ccc; - -moz-border-radius: 3px; - -webkit-border-radius: 3px; - border-radius: 3px; -} - -ul.sorting-dialog-blank-error-positions > li { - display: block; - border: 1px solid #ccc; - background: #eee; - padding: 5px; - margin: 2px; - cursor: move; - -moz-border-radius: 3px; - -webkit-border-radius: 3px; - border-radius: 3px; -} - -/* - -Copyright 2010, Google Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -*/ - -.dialog-overlay { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - background: #666; - opacity: 0.5; -} - -.dialog { - position: fixed; - left: 0; - width: 100%; - text-align: center; -} - -.dialog-frame { - margin: 0 auto; - text-align: left; - background: white; - border: 1px solid #3a5774; -} - -.dialog-border { - border: 4px solid #c1d9ff; -} - -.dialog-header { - background: #e0edfe; - padding: 10px; - font-weight: bold; - font-size: 1.6em; - color: #000; - cursor: move; -} - -.dialog-body { - overflow: auto; - font-size: 1.3em; - padding: 15px; -} - -.dialog-instruction { - padding: 0 0 7px; -} - -.dialog-footer { - font-size: 1.3em; - background: #eee; - padding: 10px; -} - -.dialog-busy { - width: 400px; - border: none; - -moz-border-radius: 5px; - -webkit-border-radius: 5px; - border-radius: 5px; -} - -/* - -Copyright 2010, Google Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -*/ - -#expression-preview-tabs .ui-tabs-nav li a { - padding: 0.15em 1em; -} - -textarea.expression-preview-code { - font-family: monospace; - height: 5em; - vertical-align: top; -} - -.expression-preview-parsing-status { - color: #999; -} - -.expression-preview-parsing-status.error { - color: red; -} - -#expression-preview-tabs-preview, -#expression-preview-tabs-help, -#expression-preview-tabs-history, -#expression-preview-tabs-starred { - padding: 5px; - overflow: hidden; -} - -#expression-preview-tabs-preview > div, -#expression-preview-tabs-help > div, -#expression-preview-tabs-history > div, -#expression-preview-tabs-starred { - height: 200px; - overflow: auto; -} - -#expression-preview-tabs-preview td, #expression-preview-tabs-preview th, -#expression-preview-tabs-help td, #expression-preview-tabs-help th, -#expression-preview-tabs-history td, #expression-preview-tabs-history th, -#expression-preview-tabs-starred td, #expression-preview-tabs-starred th { - padding: 5px; -} - -.expression-preview-table-wrapper { - padding: 7px; -} - -.expression-preview-container td { - padding: 2px 5px; - border-top: 1px solid #ccc; -} - -td.expression-preview-heading { - border-top: none; - background: #ddd; - font-weight: bold; -} - -td.expression-preview-value { - max-width: 250px !important; - overflow-x: hidden; -} - -.expression-preview-special-value { - color: #aaa; -} - -.expression-preview-help-container h3 { - margin-top: 15px; - margin-bottom: 7px; - border-bottom: 1px solid #999; -} - -.expression-preview-doc-item-title { - font-weight: bold; - text-align: right; -} - -.expression-preview-doc-item-params { -} - -.expression-preview-doc-item-returns { -} - -.expression-preview-doc-item-desc { - color: #666; -} - -/* - -Copyright 2010, Google Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -*/ - -.button:hover, a.button:hover { - border: 1px solid #666; -} - -.button:active, a.button:active { - border: 1px solid #000; -} - -.button-primary, a.button-primary { - font-weight: bold; - padding: 1px 15px; -} - -.button-pill-left, a.button-pill-left { - border-right: 1px solid #bbb; - -webkit-border-top-right-radius: 0; - -webkit-border-bottom-right-radius: 0; - -moz-border-radius-topright: 0; - -moz-border-radius-bottomright: 0; - border-top-right-radius: 0; - border-bottom-right-radius: 0; -} - -.button-pill-right, a.button-pill-right { - border-left: 1px solid #fff; - -moz-border-radius-topleft: 0; - -moz-border-radius-bottomleft: 0; - -webkit-border-top-left-radius: 0; - -webkit-border-bottom-left-radius: 0; - border-top-left-radius: 0; - border-bottom-left-radius: 0; -} - -.button-disabled, a.button-disabled, .button.button-disabled, a.button.button-disabled { - color: #666; - border: 1px solid #ddd; - background: #f3f3f3; - cursor: default; -} - -.button-disabled:hover, a.button-disabled:hover { - color: #666; - border: 1px solid #ddd; - background: #f3f3f3; - cursor: default; -} - -.button img, a.button img { - padding-left: 3px; -} - -.button-menu, a.button-menu { - background: url(images/down-arrow.png) no-repeat right 6px; - padding-right: 12px; -} - -.button, a.button { - display: inline-block; - overflow: visible; - font-size: 1em; - line-height: 1.4; - color: #000; - text-decoration: none; - padding: 1px 6px; - border: 1px solid #bbb; - cursor: pointer; - background: #eee; - white-space: nowrap; - font-family: Arial, Helvetica, sans-serif; - -moz-border-radius: 3px; - -webkit-border-radius: 3px; - border-radius: 3px; -} - -.button, a.button { - background: -webkit-gradient(linear, left top, left bottom, from(#f9f9f9), to(#e3e3e3)); - background: -moz-linear-gradient(top, #f9f9f9, #e3e3e3); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f9f9f9', endColorstr='#e3e3e3'); -} - -.button:active, a.button:active { - background: -webkit-gradient(linear, left top, left bottom, from(#e3e3e3), to(#f9f9f9)); - background: -moz-linear-gradient(top, #e3e3e3, #f9f9f9); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#e3e3e3', endColorstr='#f9f9f9'); -} diff --git a/demo/style/demo.css b/demo/style/demo.css new file mode 100644 index 00000000..aad87eca --- /dev/null +++ b/demo/style/demo.css @@ -0,0 +1,9 @@ +body { + padding-top: 60px; +} + +/* we do not have a LH sidebar */ +.container-fluid > .content { + margin-left: 0; +} + diff --git a/demo/style/flot-graph.css b/demo/style/flot-graph.css deleted file mode 100644 index 64d9c35a..00000000 --- a/demo/style/flot-graph.css +++ /dev/null @@ -1,116 +0,0 @@ -.data-graph-container .graph { - position: absolute; - left: 0; - right: 220px; - bottom: 0; - height: 100%; -} - -.data-graph-container .editor { - background-color: #efefef; - position: absolute; - right: 0; - left: auto; - width: 198px; - padding: 5px 10px; - border: 1px solid #ccc; - overflow: auto; - overflow-x: hidden; -} - -.data-graph-container .editor ul { - list-style-type: none; - margin: 0; - padding: 0; - overflow: hidden; -} - -.data-graph-container .editor li { - margin-bottom: 10px; -} - -.data-graph-container .editor .data-graph-container .editor-group { - padding-bottom: 10px; - margin-bottom: 10px; - border-bottom: 1px solid #ddd; -} - -.data-graph-container .editor label { - display: block; - font-weight: bold; - color: #555; - line-height: 1.4; -} - -.data-graph-container .editor label a { - float: right; - font-size: 11px; - color: #999; - font-weight: normal; -} - -.data-graph-container .editor select { - width: 100%; -} - -.data-graph-container .editor button { - float: right; -} - -.data-graph-container .editor-buttons { - clear: right; - overflow: hidden; -} - -.data-graph-container .editor-submit { - margin-top: 10px; - padding-top: 10px; - border-top: 1px solid #ddd; -} - -.data-graph-container .editor-info { - border-bottom: 1px solid #ddd; - margin-bottom: 10px; -} - -.data-graph-container .editor-info h1, -.data-graph-container .editor-info p { - font-size: 12px; - margin: 0 0 10px; - color: #555; -} - -.data-graph-container .editor-info h1 { - line-height: 16px; - cursor: pointer; - font-family: sans-serif; - font-size: 13px; - font-weight: bold; - margin: 0 0 4px; -} - -.data-graph-container .editor-info h1 span { - position: relative; - top: 1px; - display: inline-block; - width: 12px; - height: 12px; - background: url(jquery-ui/css/ckan/images/ui-icons_444444_256x240.png) no-repeat -68px -17px; -} - -.data-graph-container .editor-hide-info h1 span { - background-position: -36px -18px; -} - -.data-graph-container .editor-hide-info p { - display: none; -} - -.dataexplorer-tableview-hide-editor .data-graph-container .editor { - display: none; -} - -.dataexplorer-tableview-hide-editor .dataexplorer-tableview-panel { - right: 0; -} - diff --git a/demo/style/reset.css b/demo/style/reset.css deleted file mode 100755 index 1417c4c6..00000000 --- a/demo/style/reset.css +++ /dev/null @@ -1,67 +0,0 @@ -/* -------------------------------------------------------------- - - reset.css - * Resets default browser CSS. - --------------------------------------------------------------- */ - -html { - margin:0; - padding:0; - border:0; -} - -body, div, span, object, iframe, -h1, h2, h3, h4, h5, h6, p, blockquote, pre, -a, abbr, acronym, address, code, -del, dfn, em, img, q, dl, dt, dd, ol, ul, li, -fieldset, form, label, legend, -table, caption, tbody, tfoot, thead, tr, th, td, -article, aside, dialog, figure, footer, header, -hgroup, nav, section { - margin: 0; - padding: 0; - border: 0; - font-weight: inherit; - font-style: inherit; - font-size: 100%; - font-family: inherit; - vertical-align: baseline; -} - -/* This helps to make newer HTML5 elements behave like DIVs in older browers */ -article, aside, dialog, figure, footer, header, -hgroup, nav, section { - display:block; -} - -/* Line-height should always be unitless! */ -body { - line-height: 1.5; - background: white; -} - -/* Tables still need 'cellspacing="0"' in the markup. */ -table { - border-collapse: separate; - border-spacing: 0; -} -/* float:none prevents the span-x classes from breaking table-cell display */ -caption, th, td { - text-align: left; - font-weight: normal; - float:none !important; -} -table, th, td { - vertical-align: middle; -} - -/* Remove possible quote marks (") from ,
. */ -blockquote:before, blockquote:after, q:before, q:after { content: ''; } -blockquote, q { quotes: "" ""; } - -/* Remove annoying border on linked images. */ -a img { border: none; } - -/* Remember to define your own focus styles! */ -:focus { outline: 0; } \ No newline at end of file diff --git a/demo/style/style.css b/demo/style/style.css deleted file mode 100755 index 5b725b9d..00000000 --- a/demo/style/style.css +++ /dev/null @@ -1,262 +0,0 @@ -section { margin-bottom: 20px; padding: 10px; } -section.even { background-color: #EEE; -webkit-border-radius: 6px; -moz-border-radius: 6px; border-radius: 6px; } -article.example { margin: 20px 0px 20px 0px; padding: 10px 0px 10px 0px; border-top: 1px dotted #CCCCCC; border-bottom: 1px dotted #CCCCCC; } -footer { font-size: 11px; color: #666; text-align: center; margin-top: 20px; } -footer a { color: #666 } -.container { margin: 0px auto; } -#main { background-color: #FFFFFF; -webkit-border-radius: 6px; -moz-border-radius: 6px; border-radius: 6px; } -code, -blockquote, -.code { font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, serif } -.code { color: #d1d1d1; background-color: #3F3F3F; margin: 0px 0px 20px 0px; padding: 5px; font-size: 13px; -webkit-border-radius: 6px; -moz-border-radius: 6px; border-radius: 6px; } -.notice { background-color: #FFF9D8; margin-top: 20px; padding: 10px; -webkit-border-radius: 6px; -moz-border-radius: 6px; border-radius: 6px; } -.ribbon { position: absolute; top: 0; right: 0; border: 0; } -#download {float: right; position: relative; top: 3px; right: 5px;} -#database{overflow:hidden;} -#database h2{margin:0;} -#database .group{border-top:1px solid #bedce7;} -#database .separator{padding-top:1em;} -#database .envelope{border-bottom:1px solid #bedce7;border-left:1px solid #bedce7;border-right:1px solid #bedce7;padding:0 .7em .7em .7em;background:#eaf2f5 url(images/bg_gradient.gif) 0 100% repeat-x;overflow:hidden;} -#database .envelope.selected{background:#fffeeb!important;} -#database .envelope.selected .machine span{border-bottom:1px dotted #4183c4;} -#database.single_database .envelope .machine span{border-bottom:1px dotted #4183c4;} -#database .machine{float:right;width:18em;padding:.8em 0 .8em 1.2em;border-left:1px solid #bedce7;color:#808080;font-family:Monaco,"Courier New","DejaVu Sans Mono","Bitstream Vera Sans Mono",monospace;font-size:.85em;line-height:1.5em;} -#database .dbInfo {background:#fff url(images/bg_gradient.gif) 0 100% repeat-x;} -#database .action {background:#eaf2f5 url(images/bg_gradient.gif) 0 100% repeat-x;} -#database .database_oneline td{border-bottom:1px solid #bedce7;} -#database .database_oneline .date{color:#888;width:1%;padding:0 1em 0 .5em;border-left:1px solid #bedce7;} -#database .database_oneline .author{width:15%;} -#database .database_oneline .gravatar{width:1%;} -#database .database_oneline .gravatar img{border:1px solid #d0d0d0;padding:1px;background-color:white;float:left;margin-right:.4em;} -#database .database_oneline .author a{font-weight:bold;color:black;} -#database .database_oneline .message a{color:black;} -#database .database_oneline .database,#database .database_oneline .tree{width:1%;font-family:Monaco,"Courier New","DejaVu Sans Mono","Bitstream Vera Sans Mono",monospace;font-size:90%;color:#808080;border-left:1px solid #bedce7;padding:.6em .5em;} -#database .database_oneline .tree{border-right:1px solid #bedce7;} -a{color:#4183c4;} -a {text-decoration: none;} -a:hover{text-decoration:underline;} -.usingMouse a{outline:none;} -a.button span.icon.loading { background-image: url(images/loader.gif); } -.loading { background-image: url(images/loader.gif); background-repeat: no-repeat; padding-left: 15px; background-position: 0px 3px;} -a.button:hover span.icon.loading { background-image: url(images/loader-blue.gif); } -#couchLogo {float: left; margin-right: 5px; margin-top: 3px} -.chosen {border: 1px solid green} -.info { padding: 0px 0px 10px 0px} -.large-loader { position: relative; } -.data-table-menu-overlay { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; -} - -ul.data-table-menu { - display: none; - outline-style: none; - background: white; - color: black; - font-size: 12px; - height: auto; - list-style: none; - overflow: hidden; - position: absolute; - text-align: left; - width: 120px; - z-index: 666; - border: 1px solid #CCC; - border-right: 1px solid #666; - border-bottom: 1px solid #666; - margin: 0; padding: 0; } - ul.data-table-menu * { - margin: 0; - padding: 0; } - ul.data-table-menu a { - line-height: 14px; - color: black; - display: block; - padding: 5px 7px; - text-decoration: none; } - ul.data-table-menu li { - height: 24px; } - ul.data-table-menu li:hover { - background-color: #DBE8F8 } - - -/* Document Editor from CouchDB SammyFuton */ - -div#document-container span#expand-all { - cursor:pointer; color:#FF0000; -} - -div#document-editor { background: #fff; font-size:14px; overflow: auto; max-height: 500px;} -div#document-editor span.expand {cursor:pointer; color:#FF0000;} -div#document-editor div.id-space { - border: none; float: left; margin: 3px 3px 0 3px; padding: 0; - width: 15px; height: 15px; -} -div#document-editor div.doc-field {width:99%; padding-bottom:2px;} -div#document-editor div.doc-field, div.doc-value, div.doc-key {float:left; cursor:pointer; cursor: hand;} -div#document-editor div.doc-key {padding-right:5px;font-weight:bold;} - -div#document-editor div.string-type { white-space: pre-wrap; color:#393;} -div#document-editor div.string-type:before { color: #ccc; content: "“"; - left: -4px; -} -div#document-editor div.string-type:after { color: #ccc; content: "”"; } - -div#document-editor span.number-type { white-space: pre-wrap; color:#339; padding-left:6px;} - -div#document-editor span.array-type { color: #BD101D; float:left;} -div#document-editor span.object-type { color: #BD101D; float:left;} -div#document-editor span.null-type { color: #BD101D; float:left; color: #666666; padding-left:6px;} - -div#document-editor div.array-key {float:left; padding-right:15px; color:#666666;} -div#document-editor div.object-key {float:left; padding-right:15px; font-weight:bold; } -div#document-editor div.doc-key-base {float:left; padding-right:15px; font-weight:bold; } - -div#document-editor .doc-value.object { - max-width: 400px; -} - -div#document-editor .array-type { - max-width: 500px; -} - -div#document-editor div.empty { - float:left; -} - -div#document-editor input { - font: normal 90% arial, sans-serif; -} - -div#document-editor span#save-button { - cursor:pointer; background-color:#ddd; - padding: 2px 5px 2px 5px; - -moz-border-radius: 15px; - -webkit-border-radius: 15px; - border-radius: 15px; -} -span#restore { - cursor:pointer; background-color:#ddd; - padding: 2px 5px 2px 5px; - -moz-border-radius: 15px; - -webkit-border-radius: 15px; - border-radius: 15px; -} - -div#autosave { - float:right; -} - -span.revision { - padding-right:10px; - cursor:pointer; - float:left; - margin-bottom:10px; -} -div#document-revisions { - padding-top:20px; -} -span#document-revisions-title { - padding-right:10px; - font-weight:bold; - float:left; - margin-bottom:80px; -} -span.current-revision { - font-weight:bold; - padding-right:10px; - float:left; - margin-bottom:10px; -} -span.revision { - padding-right:10px; - cursor:default; - float:left; - margin-bottom:10px; -} -span.revision-status-missing { - color:#8C8C8C; -} -span.revision-status-disk { - cursor:pointer; -} -span.revision-status-available { - cursor:pointer; -} -span.revision-status-deleted { - color:#8C8C8C; -} - -.tooltip { - position:absolute; - font-size:12px; - padding:2px; - background-color:#B3B3B3; - border:checked; - color:black; - -moz-border-radius: 5px; - -webkit-border-radius: 5px; -} -span.tooltip-status-title { - color:black; - font-weight:normal; - text-align:center; -} -span.tooltip-status { - font-weight:bold; - color:red; - text-align:center; -} - -/* rgrp added mods */ - -.data-explorer .header { - border-top: 15px solid #BCF; - border-left: 5px solid #BCF; - display: block; - overflow: auto; - position: absolute; - top: 35px; - bottom: 0px; - left: 0px; - right: 0px; - background: white; - padding-top: 3px; -} - -.header .navigation, -.header .navigation li, -.header .pagination, -.header .pagination form -{ - display: inline; -} - -.header .pagination { - float: right; -} - -.header .pagination input { - width: 40px; -} - -.doc-count { - font-weight: bold; - font-size: 120%; -} - -.data-view-container { - display: block; - border-top: 1px solid #BCF; - border-left: 5px solid #BCF; - overflow: auto; - position: absolute; - top: 83px; - bottom: 0px; - left: 0px; - right: 0px; - background: white; -} diff --git a/docs/backend/base.html b/docs/backend/base.html index 92c0ca53..b4da1482 100644 --- a/docs/backend/base.html +++ b/docs/backend/base.html @@ -1,4 +1,4 @@ - base.js

base.js

Recline Backends

+ base.js

base.js

Recline Backends

Backends are connectors to backend data sources and stores

diff --git a/docs/backend/dataproxy.html b/docs/backend/dataproxy.html index 83405602..d232ef91 100644 --- a/docs/backend/dataproxy.html +++ b/docs/backend/dataproxy.html @@ -1,4 +1,4 @@ - dataproxy.js

dataproxy.js

this.recline = this.recline || {};
+      dataproxy.js           

dataproxy.js

this.recline = this.recline || {};
 this.recline.Backend = this.recline.Backend || {};
 
 (function($, my) {

DataProxy Backend

@@ -25,28 +25,9 @@ sync: function(method, model, options) { var self = this; if (method === "read") { - if (model.__type__ == 'Dataset') { - var base = self.get('dataproxy_url');

TODO: should we cache for extra efficiency

          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();
-          my.wrapInTimeout(jqxhr).done(function(results) {
-            model.fields.reset(_.map(results.fields, function(fieldId) {
-              return {id: fieldId};
-              })
-            );
-            dfd.resolve(model, jqxhr);
-          })
-          .fail(function(arguments) {
-            dfd.reject(arguments);
-          });
+        if (model.__type__ == 'Dataset') {

Do nothing as we will get fields in query step (and no metadata to +retrieve)

          var dfd = $.Deferred();
+          dfd.resolve(model);
           return dfd.promise();
         }
       } else {
@@ -66,7 +47,14 @@
         , dataType: 'jsonp'
       });
       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 tmp = {};
           _.each(results.fields, function(key, idx) {
@@ -75,6 +63,9 @@
           return tmp;
         });
         dfd.resolve(_out);
+      })
+      .fail(function(arguments) {
+        dfd.reject(arguments);
       });
       return dfd.promise();
     }
diff --git a/docs/backend/elasticsearch.html b/docs/backend/elasticsearch.html
index d576b1cf..0b91fa81 100644
--- a/docs/backend/elasticsearch.html
+++ b/docs/backend/elasticsearch.html
@@ -1,4 +1,4 @@
-      elasticsearch.js           

elasticsearch.js

this.recline = this.recline || {};
+      elasticsearch.js           

elasticsearch.js

this.recline = this.recline || {};
 this.recline.Backend = this.recline.Backend || {};
 
 (function($, my) {

ElasticSearch Backend

diff --git a/docs/backend/gdocs.html b/docs/backend/gdocs.html index d503f679..c058c6f5 100644 --- a/docs/backend/gdocs.html +++ b/docs/backend/gdocs.html @@ -1,4 +1,4 @@ - gdocs.js

gdocs.js

this.recline = this.recline || {};
+      gdocs.js           

gdocs.js

this.recline = this.recline || {};
 this.recline.Backend = this.recline.Backend || {};
 
 (function($, my) {

Google spreadsheet backend

@@ -15,18 +15,36 @@ var dataset = new recline.Model.Dataset({ 'gdocs' );
  my.GDoc = Backbone.Model.extend({
+    getUrl: function(dataset) {
+      var url = dataset.get('url');
+      if (url.indexOf('feeds/list') != -1) {
+        return url;
+      } else {

https://docs.google.com/spreadsheet/ccc?key=XXXX#gid=0

        var regex = /.*spreadsheet\/ccc?.*key=([^#?&+]+).*/
+        var matches = url.match(regex);
+        if (matches) {
+          var key = matches[1];
+          var worksheet = 1;
+          var out = 'https://spreadsheets.google.com/feeds/list/' + key + '/' + worksheet + '/public/values?alt=json'
+          return out;
+        } else {
+          alert('Failed to extract gdocs key from ' + url);
+        }
+      }
+    },
     sync: function(method, model, options) {
       var self = this;
       if (method === "read") { 
         var dfd = $.Deferred(); 
         var dataset = model;
 
-        $.getJSON(model.get('url'), function(d) {
+        var url = this.getUrl(model);
+
+        $.getJSON(url, function(d) {
           result = self.gdocsToJavascript(d);
           model.fields.reset(_.map(result.field, function(fieldId) {
               return {id: fieldId};
             })
-          );

cache data onto dataset (we have loaded whole gdoc it seems!)

          model._dataCache = result.data;
+          );

cache data onto dataset (we have loaded whole gdoc it seems!)

          model._dataCache = result.data;
           dfd.resolve(model);
         })
         return dfd.promise(); }
@@ -34,7 +52,7 @@ var dataset = new recline.Model.Dataset({
 
     query: function(dataset, queryObj) { 
       var dfd = $.Deferred();
-      var fields = _.pluck(dataset.fields.toJSON(), 'id');

zip the fields with the data rows to produce js objs + var fields = _.pluck(dataset.fields.toJSON(), 'id');

zip the fields with the data rows to produce js objs TODO: factor this out as a common method with other backends

      var objs = _.map(dataset._dataCache, function (d) { 
         var obj = {};
         _.each(_.zip(fields, d), function (x) { obj[x[0]] = x[1]; })
@@ -59,11 +77,11 @@ TODO: factor this out as a common method with other backends

var results = { 'field': [], 'data': [] - };

default is no special info on type of columns

      var colTypes = {};
+      };

default is no special info on type of columns

      var colTypes = {};
       if (options.colTypes) {
         colTypes = options.colTypes;
-      }

either extract column headings from spreadsheet directly, or used supplied ones

      if (options.columnsToUse) {

columns set to subset supplied

        results.field = options.columnsToUse;
-      } else {

set columns to use to be all available

        if (gdocsSpreadsheet.feed.entry.length > 0) {
+      }

either extract column headings from spreadsheet directly, or used supplied ones

      if (options.columnsToUse) {

columns set to subset supplied

        results.field = options.columnsToUse;
+      } else {

set columns to use to be all available

        if (gdocsSpreadsheet.feed.entry.length > 0) {
           for (var k in gdocsSpreadsheet.feed.entry[0]) {
             if (k.substr(0, 3) == 'gsx') {
               var col = k.substr(4)
@@ -71,13 +89,13 @@ TODO: factor this out as a common method with other backends

} } } - }

converts non numberical values that should be numerical (22.3%[string] -> 0.223[float])

      var rep = /^([\d\.\-]+)\%$/;
+      }

converts non numberical values that should be numerical (22.3%[string] -> 0.223[float])

      var rep = /^([\d\.\-]+)\%$/;
       $.each(gdocsSpreadsheet.feed.entry, function (i, entry) {
         var row = [];
         for (var k in results.field) {
           var col = results.field[k];
           var _keyname = 'gsx$' + col;
-          var value = entry[_keyname]['$t'];

if labelled as % and value contains %, convert

          if (colTypes[col] == 'percent') {
+          var value = entry[_keyname]['$t'];

if labelled as % and value contains %, convert

          if (colTypes[col] == 'percent') {
             if (rep.test(value)) {
               var value2 = rep.exec(value);
               var value3 = parseFloat(value2);
diff --git a/docs/backend/memory.html b/docs/backend/memory.html
index 982be977..8b9fe834 100644
--- a/docs/backend/memory.html
+++ b/docs/backend/memory.html
@@ -1,4 +1,4 @@
-      memory.js           

memory.js

this.recline = this.recline || {};
+      memory.js           
onEditorSubmit:function(e){varselect=this.el.find('.editor-group select'); - this._getEditorData();},setupRouting:function(){ - varself=this;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');className:'recline-query-editor',template:' \ <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 class="btn-group menu"> \ + <a class="btn dropdown-toggle" data-toggle="dropdown"><i class="icon-cog"></i><span class="caret"></span></a> \ + <ul class="dropdown-menu"> \ + <li><a data-action="size" href="">Number of items to show ({{size}})</a></li> \ + <li><a data-action="from" href="">Show from ({{from}})</a></li> \ + </ul> \ + </div> \ + </div> \ <div class="pagination"> \ <ul> \ - <li class="prev action-pagination-update"><a>&laquo; back</a></li> \ - <li class="active"><a><input name="from" type="text" value="{{from}}" /> &ndash; <input name="to" type="text" value="{{to}}" /> </a></li> \ - <li class="next action-pagination-update"><a>next &raquo;</a></li> \ + <li class="prev action-pagination-update"><a href="">&laquo;</a></li> \ + <li class="active"><a>{{from}} &ndash; {{to}}</a></li> \ + <li class="next action-pagination-update"><a href="">&raquo;</a></li> \ </ul> \ </div> \ - <button type="submit" class="btn" style="">Update &raquo;</button> \ </form> \ ',events:{ - 'submit form':'onFormSubmit', - 'click .action-pagination-update':'onPaginationUpdate' + 'submit form':'onFormSubmit' + ,'click .action-pagination-update':'onPaginationUpdate' + ,'click .menu li a':'onMenuItemClick'},initialize:function(){ @@ -196,10 +226,8 @@ note this.model and dataset returned are the same

},onFormSubmit:function(e){e.preventDefault(); - varnewFrom=parseInt(this.el.find('input[name="from"]').val()); - varnewSize=parseInt(this.el.find('input[name="to"]').val())-newFrom; - varquery=this.el.find('.text-query').val(); - this.model.set({size:newSize,from:newFrom,q:query}); + varquery=this.el.find('.text-query input').val(); + this.model.set({q:query});},onPaginationUpdate:function(e){e.preventDefault(); @@ -211,6 +239,20 @@ note this.model and dataset returned are the same

}this.model.set({from:newFrom});}, + onMenuItemClick:function(e){ + e.preventDefault(); + varattrName=$(e.target).attr('data-action'); + varmsg=_.template('New value (<%= value %>)', + {value:this.model.get(attrName)} + ); + varnewValue=prompt(msg); + if(newValue){ + newValue=parseInt(newValue); + varupdate={}; + update[attrName]=newValue; + this.model.set(update); + } + },render:function(){vartmplData=this.model.toJSON();tmplData.to=this.model.get('from')+this.model.get('size'); @@ -220,7 +262,7 @@ note this.model and dataset returned are the same

}); -/* ========================================================== */query:parsed[2]||''}} -}if(q&&q.length&&q[0]==='?'){q=q.slice(1);} - while(e=r.exec(q)){my.setHashQueryString=function(queryParams){window.location.hash=window.location.hash.split('?')[0]+my.composeQueryString(queryParams); -} <div class="alert alert-{{category}} fade in" data-alert="alert"><a class="close" data-dismiss="alert" href="#">×</a> \ {{msg}} \ {{#loader}} \ - <img src="images/small-spinner.gif" class="notification-loader"> \ + <span class="notification-loader">&nbsp;</span> \ {{/loader}} \ </div>';var_templated=$.mustache(_template,tmplData); @@ -289,7 +334,7 @@ note this.model and dataset returned are the same

});},1000);} -}

memory.js

this.recline = this.recline || {};
 this.recline.Backend = this.recline.Backend || {};
 
 (function($, my) {

Memory Backend - uses in-memory data

diff --git a/docs/backend/webstore.html b/docs/backend/webstore.html deleted file mode 100644 index aae1bbc5..00000000 --- a/docs/backend/webstore.html +++ /dev/null @@ -1,61 +0,0 @@ - webstore.js

webstore.js

this.recline = this.recline || {};
-this.recline.Backend = this.recline.Backend || {};
-
-(function($, my) {

Webstore Backend

- -

Connecting to Webstores

- -

To use this backend ensure your Dataset has a webstore_url in its attributes.

  my.Webstore = Backbone.Model.extend({
-    sync: function(method, model, options) {
-      if (method === "read") {
-        if (model.__type__ == 'Dataset') {
-          var base = model.get('webstore_url');
-          var schemaUrl = base + '/schema.json';
-          var jqxhr = $.ajax({
-            url: schemaUrl,
-              dataType: 'jsonp',
-              jsonp: '_callback'
-          });
-          var dfd = $.Deferred();
-          my.wrapInTimeout(jqxhr).done(function(schema) {
-            var fieldData = _.map(schema.data, function(item) {
-              item.id = item.name;
-              delete item.name;
-              return item;
-            });
-            model.fields.reset(fieldData);
-            model.docCount = schema.count;
-            dfd.resolve(model, jqxhr);
-          })
-          .fail(function(arguments) {
-            dfd.reject(arguments);
-          });
-          return dfd.promise();
-        }
-      }
-    },
-    query: function(model, queryObj) {
-      var base = model.get('webstore_url');
-      var data = {
-        _limit:  queryObj.size
-        , _offset: queryObj.from
-      };
-      var jqxhr = $.ajax({
-        url: base + '.json',
-        data: data,
-        dataType: 'jsonp',
-        jsonp: '_callback',
-        cache: true
-      });
-      var dfd = $.Deferred();
-      jqxhr.done(function(results) {
-        dfd.resolve(results.data);
-      });
-      return dfd.promise();
-    }
-  });
-  recline.Model.backends['webstore'] = new my.Webstore();
-
-}(jQuery, this.recline.Backend));
-
-
\ No newline at end of file diff --git a/docs/model.html b/docs/model.html index 053d7577..ae7bcb5c 100644 --- a/docs/model.html +++ b/docs/model.html @@ -36,7 +36,7 @@ updated by queryObj (if provided).

also returned.

  query: function(queryObj) {
     this.trigger('query:start');
     var self = this;
-    this.queryState.set(queryObj, {silent: true});
+    this.queryState.set(queryObj);
     var dfd = $.Deferred();
     this.backend.query(this, this.queryState.toJSON()).done(function(rows) {
       var docs = _.map(rows, function(row) {
diff --git a/docs/view-flot-graph.html b/docs/view-flot-graph.html
index dac85e8a..cd3d6080 100644
--- a/docs/view-flot-graph.html
+++ b/docs/view-flot-graph.html
@@ -36,7 +36,10 @@ generate the element itself (you can then append view.el to the DOM.

<label>Graph Type</label> \ <div class="input editor-type"> \ <select> \ - <option value="line">Line</option> \ + <option value="lines-and-points">Lines and Points</option> \ + <option value="lines">Lines</option> \ + <option value="points">Points</option> \ + <option value="bars">Bars</option> \ </select> \ </div> \ <label>Group Column (x-axis)</label> \ @@ -95,7 +98,7 @@ generate the element itself (you can then append view.el to the DOM.

this.chartConfig = _.extend({ group: null, series: [], - graphType: 'line' + graphType: 'lines-and-points' }, configFromHash, config @@ -113,9 +116,14 @@ could be simpler just to have a common template!

update navigation -TODO: make this less invasive (e.g. preserve other keys in query string)

    var qs = my.parseHashQueryString();
-    qs['graph'] = this.chartConfig;
+    $editor = this;
+    var series = this.$series.map(function () {
+      return $(this).val();
+    });
+    this.chartConfig.series = $.makeArray(series)
+    this.chartConfig.group = this.el.find('.editor-group select').val();
+    this.chartConfig.graphType = this.el.find('.editor-type select').val();

update navigation

    var qs = my.parseHashQueryString();
+    qs['graph'] = JSON.stringify(this.chartConfig);
     my.setHashQueryString(qs);
     this.redraw();
   },
@@ -128,25 +136,98 @@ TODO: make this less invasive (e.g. preserve other keys in query string)

    var areWeVisible = !jQuery.expr.filters.hidden(this.el[0]);
     if ((!areWeVisible || this.model.currentDocuments.length == 0)) {
       return
-    }

create this.plot and cache it

    if (!this.plot) {

only lines for the present

      options = {
-        id: 'line',
-        name: 'Line Chart'
-      };
-      this.plot = $.plot(this.$graph, this.createSeries(), options);
-    } 
-    this.plot.setData(this.createSeries());
-    this.plot.resize();
-    this.plot.setupGrid();
-    this.plot.draw();
+    }
+    var series = this.createSeries();
+    var options = this.graphOptions[this.chartConfig.graphType];
+    this.plot = $.plot(this.$graph, series, options);
+    if (this.chartConfig.graphType in { 'points': '', 'lines-and-points': '' }) {
+      this.setupTooltips();
+    }

create this.plot and cache it + if (!this.plot) { + this.plot = $.plot(this.$graph, series, options); + } else { + this.plot.parseOptions(options); + this.plot.setData(this.createSeries()); + this.plot.resize(); + this.plot.setupGrid(); + this.plot.draw(); + }

  },
+
+  graphOptions: { 
+    lines: {
+       series: { 
+         lines: { show: true }
+       }
+    }
+    , points: {
+      series: {
+        points: { show: true }
+      },
+      grid: { hoverable: true, clickable: true }
+    }
+    , 'lines-and-points': {
+      series: {
+        points: { show: true },
+        lines: { show: true }
+      },
+      grid: { hoverable: true, clickable: true }
+    }
+    , bars: {
+      series: {
+        lines: {show: false},
+        bars: {
+          show: true,
+          barWidth: 1,
+          align: "left",
+          fill: true
+        }
+      },
+      xaxis: {
+        tickSize: 1,
+        tickLength: 1,
+      }
+    }
   },
 
-  _getEditorData: function() {
-    $editor = this
-    var series = this.$series.map(function () {
-      return $(this).val();
+  setupTooltips: function() {
+    var self = this;
+    function showTooltip(x, y, contents) {
+      $('<div id="flot-tooltip">' + contents + '</div>').css( {
+        position: 'absolute',
+        display: 'none',
+        top: y + 5,
+        left: x + 5,
+        border: '1px solid #fdd',
+        padding: '2px',
+        'background-color': '#fee',
+        opacity: 0.80
+      }).appendTo("body").fadeIn(200);
+    }
+
+    var previousPoint = null;
+    this.$graph.bind("plothover", function (event, pos, item) {
+      if (item) {
+        if (previousPoint != item.dataIndex) {
+          previousPoint = item.dataIndex;
+          
+          $("#flot-tooltip").remove();
+          var x = item.datapoint[0].toFixed(2),
+              y = item.datapoint[1].toFixed(2);
+          
+          var content = _.template('<%= group %> = <%= x %>, <%= series %> = <%= y %>', {
+            group: self.chartConfig.group,
+            x: x,
+            series: item.series.label,
+            y: y
+          });
+          showTooltip(item.pageX, item.pageY, content);
+        }
+      }
+      else {
+        $("#flot-tooltip").remove();
+        previousPoint = null;            
+      }
     });
-    this.chartConfig.series = $.makeArray(series)
-    this.chartConfig.group = this.el.find('.editor-group select').val();
   },
 
   createSeries: function () {
@@ -167,7 +248,7 @@ TODO: make this less invasive (e.g. preserve other keys in query string)

}); } return series; - },

Public: Adds a new empty series select box to the editor.

+ },

Public: Adds a new empty series select box to the editor.

All but the first select box will have a remove button that allows them to be removed.

@@ -183,7 +264,7 @@ to be removed.

label.append(' [<a href="#remove" class="action-remove-series">Remove</a>]'); label.find('span').text(String.fromCharCode(this.$series.length + 64)); return this; - },

Public: Removes a series list item from the editor.

+ },

Public: Removes a series list item from the editor.

Also updates the labels of the remaining series elements.

  removeSeries: function (e) {
     e.preventDefault();
@@ -201,7 +282,7 @@ to be removed.

toggleHelp: function() { this.el.find('.editor-info').toggleClass('editor-hide-info'); - },

Private: Resets the series property to reference the select elements.

+ },

Private: Resets the series property to reference the select elements.

Returns itself.

  _updateSeries: function () {
     this.$series  = this.el.find('.editor-series select');
diff --git a/docs/view-grid.html b/docs/view-grid.html
index c4c935d5..f5472749 100644
--- a/docs/view-grid.html
+++ b/docs/view-grid.html
@@ -44,19 +44,19 @@ showDialog: function(template, data) {
 },

====================================================== Column and row menus

  onColumnHeaderClick: function(e) {
     this.state.currentColumn = $(e.target).closest('.column-header').attr('data-field');
-    util.position('data-table-menu', e);
-    util.render('columnActions', 'data-table-menu');
   },
 
   onRowHeaderClick: function(e) {
     this.state.currentRow = $(e.target).parents('tr:first').attr('data-id');
-    util.position('data-table-menu', e);
-    util.render('rowActions', 'data-table-menu');
   },
   
   onRootHeaderClick: function(e) {
-    util.position('data-table-menu', e);
-    util.render('rootActions', 'data-table-menu', {'columns': this.hiddenFields});
+    var tmpl = ' \
+        {{#columns}} \
+        <li><a data-action="showColumn" data-column="{{.}}" href="JavaScript:void(0);">Show column: {{.}}</a></li> \
+        {{/columns}}';
+    var tmp = $.mustache(tmpl, {'columns': this.hiddenFields});
+    this.el.find('.root-header-menu .dropdown-menu').html(tmp);
   },
 
   onMenuClick: function(e) {
@@ -90,7 +90,6 @@ from DOM) while id may be int

}) } } - util.hide('data-table-menu'); actions[$(e.target).attr('data-action')](); }, @@ -141,26 +140,32 @@ from DOM) while id may be int

},

======================================================

Templating

  template: ' \
-    <div class="data-table-menu-overlay" style="display: none; z-index: 101; ">&nbsp;</div> \
-    <ul class="data-table-menu"></ul> \
-    <table class="data-table" cellspacing="0"> \
+    <table class="data-table table-striped table-condensed" cellspacing="0"> \
       <thead> \
         <tr> \
           {{#notEmpty}} \
             <th class="column-header"> \
-              <div class="column-header-title"> \
-                <a class="root-header-menu"></a> \
-                <span class="column-header-name"></span> \
+              <div class="btn-group root-header-menu"> \
+                <a class="btn dropdown-toggle" data-toggle="dropdown"><span class="caret"></span></a> \
+                <ul class="dropdown-menu data-table-menu"> \
+                </ul> \
               </div> \
+              <span class="column-header-name"></span> \
             </th> \
           {{/notEmpty}} \
           {{#fields}} \
             <th class="column-header {{#hidden}}hidden{{/hidden}}" data-field="{{id}}"> \
-              <div class="column-header-title"> \
-                <a class="column-header-menu"></a> \
-                <span class="column-header-name">{{label}}</span> \
-              </div> \
+              <div class="btn-group column-header-menu"> \
+                <a class="btn dropdown-toggle" data-toggle="dropdown"><i class="icon-cog"></i><span class="caret"></span></a> \
+                <ul class="dropdown-menu data-table-menu"> \
+                  <li class="write-op"><a data-action="bulkEdit" href="JavaScript:void(0);">Transform...</a></li> \
+                  <li class="write-op"><a data-action="deleteColumn" href="JavaScript:void(0);">Delete this column</a></li> \
+                  <li><a data-action="sortAsc" href="JavaScript:void(0);">Sort ascending</a></li> \
+                  <li><a data-action="sortDesc" href="JavaScript:void(0);">Sort descending</a></li> \
+                  <li><a data-action="hideColumn" href="JavaScript:void(0);">Hide this column</a></li> \
+                </ul> \
               </div> \
+              <span class="column-header-name">{{label}}</span> \
             </th> \
           {{/fields}} \
         </tr> \
@@ -239,7 +244,14 @@ var row = new DataGridRow({
   },
 
   template: ' \
-      <td><a class="row-header-menu"></a></td> \
+      <td> \
+        <div class="btn-group row-header-menu"> \
+          <a class="btn dropdown-toggle" data-toggle="dropdown"><span class="caret"></span></a> \
+          <ul class="dropdown-menu data-table-menu"> \
+            <li class="write-op"><a data-action="deleteRow" href="JavaScript:void(0);">Delete this row</a></li> \
+          </ul> \
+        </div> \
+      </td> \
       {{#cells}} \
       <td data-field="{{field}}"> \
         <div class="data-table-cell-content"> \
diff --git a/docs/view.html b/docs/view.html
index 28474dd2..8e0c77f3 100644
--- a/docs/view.html
+++ b/docs/view.html
@@ -100,22 +100,40 @@ FlotGraph subview.

this.router = new Backbone.Router(); this.setupRouting(); - this.model.bind('query:start', function(eventName) { + this.model.bind('query:start', function() { my.notify('Loading data', {loader: true}); }); - this.model.bind('query:done', function(eventName) { + this.model.bind('query:done', function() { my.clearNotifications(); self.el.find('.doc-count').text(self.model.docCount || 'Unknown'); - my.notify('Data loaded', {category: 'success'}); + my.notify('Data loaded', {category: 'success'});

update navigation

        var qs = my.parseHashQueryString();
+        qs['reclineQuery'] = JSON.stringify(self.model.queryState.toJSON());
+        my.setHashQueryString(qs);
       });
-    this.model.bind('query:fail', function(eventName, error) {
+    this.model.bind('query:fail', function(error) {
         my.clearNotifications();
-        my.notify(error.message, {category: 'error', persist: true});
-      });

retrieve basic data like fields etc + 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();
+        var queryState = my.parseHashQueryString().reclineQuery;
+        if (queryState) {
+          queryState = JSON.parse(queryState);
+        }
+        self.model.query(queryState);
       })
       .fail(function(error) {
         my.notify(error.message, {category: 'error', persist: true});
@@ -143,7 +161,7 @@ note this.model and dataset returned are the same

Default route

    this.router.route('', this.pageViews[0].id, 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) {
@@ -155,8 +173,10 @@ note this.model and dataset returned are the same

show the specific page

    _.each(this.pageViews, function(view, idx) {
+    $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 {
@@ -171,21 +191,31 @@ note this.model and dataset returned are the same

Miscellaneous Utilities

var urlPathRegex = /^([^?]+)(\?.*)?/;

Parse the Hash section of a URL into path and query string

my.parseHashUrl = function(hashUrl) {
+/* ========================================================== */

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 {};
@@ -230,7 +272,10 @@ note this.model and dataset returned are the same

Parse a URL query string (?xyz=abc...) into a dictionary.

my.parseQueryString = function(q) {
+}

Parse a URL query string (?xyz=abc...) into a dictionary.

my.parseQueryString = function(q) {
+  if (!q) {
+    return {};
+  }
   var urlParams = {},
     e, d = function (s) {
       return unescape(s.replace(/\+/g, " "));
@@ -240,17 +285,17 @@ note this.model and dataset returned are the same

TODO: have values be array as query string allow repetition of keys

    urlParams[d(e[1])] = d(e[2]);
+  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() {
+}

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) {
+}

Compse a Query String

my.composeQueryString = function(queryParams) {
   var queryString = '?';
   var items = [];
   $.each(queryParams, function(key, value) {
-    items.push(key + '=' + JSON.stringify(value));
+    items.push(key + '=' + value);
   });
   queryString += items.join('&');
   return queryString;
@@ -258,7 +303,7 @@ note this.model and dataset returned are the same

notify

+}

notify

Create a notification (a div.alert in div.alert-messsages) using provide messages and options. Options are:

@@ -277,7 +322,7 @@ note this.model and dataset returned are the same

clearNotifications

+}

clearNotifications

Clear all existing notifications

my.clearNotifications = function() {
   var $notifications = $('.data-explorer .alert-messages .alert');
diff --git a/index.html b/index.html
index 17ed7698..699c9540 100644
--- a/index.html
+++ b/index.html
@@ -69,14 +69,14 @@
   

Recline combines a data grid, Google Refine-style data transforms and visualizations all in lightweight javascript and html.

Designed for standalone use or as a library to integrate into your own - app. Recline utilizes the lightweight but powerful Backbone framework, and - so is a cinch to extend or adapt.

+ app. Recline builds on the powerful but lightweight Backbone framework + making it extremely easy to extend and adapt.

Main Features

    @@ -113,27 +113,7 @@

    CSS: the demo utilizes bootstrap but you can integrate with your own HTML and CSS. Data Explorer specific CSS can be found here in the repo: https://github.com/okfn/recline/tree/master/css.

    Documentation

    -

    Recline has a simple structure layered on top of the basic Model/View - distinction inherent in Backbone. There are the following two main domain objects (all Backbone Models):

    -
      -
    • Dataset: represents the dataset. Holds dataset info and a pointer to list of data items (Documents in our terminology) which it can load from the relevant Backend.
    • -
    • Document: an individual data item (e.g. a row from a relational database or a spreadsheet, a document from from a document DB like CouchDB or MongoDB).
    • -
    -

    More on the models in the Model source docs.

    - -

    Backends (more info below) connect Dataset and Documents to data - from a specific 'Backend' data source. They provide methods for loading and - saving Datasets and individuals Documents as well as for bulk loading via a - query API and doing bulk transforms on the backend.

    - -

    Complementing the model are various Views (you can easily write your own). Each view holds a pointer to a Dataset:

    -
      -
    • DataExplorer: the parent view which manages the overall app and sets up sub views.
    • -
    • DataGrid: the data grid view.
    • -
    • FlotGraph: a simple graphing view using Flot.
    • -
    - -

    Using It

    +

    Quickstart

     // Note: you should have included the relevant JS libraries (and CSS)
     // See above for dependencies
    @@ -158,6 +138,29 @@ Backbone.history.start();
           href="demo/">Demo -- just hit view source (NB: the javascript for the
         demo is in: app.js).

    +

    Architecture and Model

    +

    Recline has a simple structure layered on top of the basic Model/View + distinction inherent in Backbone. There are the following two main domain objects (both Backbone Models):

    +
      +
    • Dataset: represents the dataset. Holds dataset info and a pointer to list of data items (Documents in our terminology) which it can load from the relevant Backend.
    • +
    • Document: an individual data item (e.g. a row from a relational database or a spreadsheet, a document from from a document DB like CouchDB or MongoDB).
    • +
    +

    More detail of how these work can be found in the Model source docs.

    + +

    Backends connect Dataset and Documents to data + from a specific 'Backend' data source. They provide methods for loading and + saving Datasets and individuals Documents as well as for bulk loading via a + query API and doing bulk transforms on the backend. More info on backends can be found below.

    + +

    Complementing the model are various Views (you can easily write your own). Each view holds a pointer to a Dataset:

    +
      +
    • DataExplorer: the parent view which manages the overall app and sets up sub views.
    • +
    • DataGrid: the data grid view.
    • +
    • FlotGraph: a simple graphing view using Flot.
    • +
    + +

    Backends

    Backends are connectors to backend data sources from which data can be retrieved.

    @@ -197,10 +200,11 @@ used by the Dataset.query method to search the backend for documents, retrieving the results in bulk. This method should also set the docCount attribute on the dataset.

    -

    queryObj should be either a recline.Model.Query object or a +

    queryObj should be either a recline.Model.Query object or a Hash. The structure of data in the Query object or Hash should follow that -defined in issue 34. (That said, if you are writing your own backend and have -control over the query object you can obviously use whatever structure you +defined in issue 34. (Of +course, if you are writing your own backend, and hence have control over the +interpretation of the query object, you can use whatever structure you like).

    Source Docs (via Docco)

    @@ -211,6 +215,7 @@ like).

  • Graph View (based on Flot)
  • Backend: Memory (local data)
  • Backend: ElasticSearch
  • +
  • Backend: DataProxy
  • Backend: Google Docs (Spreadsheet)
diff --git a/make b/make index 02a3d5b9..4d60070a 100755 --- a/make +++ b/make @@ -1,5 +1,6 @@ #!/usr/bin/env python import sys +import shutil import os def cat(): @@ -12,6 +13,8 @@ def docs(): print("** Building docs") cmd = 'docco src/model.js src/view.js src/view-grid.js src/view-flot-graph.js' os.system(cmd) + if os.path.exists('/tmp/recline-docs'): + shutil.rmtree('/tmp/recline-docs') os.makedirs('/tmp/recline-docs') os.system('mkdir -p docs/backend') files = '%s/src/backend/*.js' % os.getcwd() diff --git a/recline.js b/recline.js index 0add56e4..b52cb93e 100644 --- a/recline.js +++ b/recline.js @@ -166,7 +166,7 @@ my.Dataset = Backbone.Model.extend({ query: function(queryObj) { this.trigger('query:start'); var self = this; - this.queryState.set(queryObj, {silent: true}); + this.queryState.set(queryObj); var dfd = $.Deferred(); this.backend.query(this, this.queryState.toJSON()).done(function(rows) { var docs = _.map(rows, function(row) { @@ -255,18 +255,6 @@ my.backends = {}; var util = function() { var templates = { transformActions: '
  • Global transform...
  • ' - , columnActions: ' \ -
  • Transform...
  • \ -
  • Delete this column
  • \ -
  • Sort ascending
  • \ -
  • Sort descending
  • \ -
  • Hide this column
  • \ - ' - , rowActions: '
  • Delete this row
  • ' - , rootActions: ' \ - {{#columns}} \ -
  • Show column: {{.}}
  • \ - {{/columns}}' , cellEditor: ' \