all repos — litestore @ 48c0a0127ccdb261b77d1bc137c5208a93c8dd19

A minimalist nosql document store.

Implemented search.
* Closes #16;
h3rald h3rald@h3rald.com
Sat, 21 Mar 2015 21:59:29 +0100
commit

48c0a0127ccdb261b77d1bc137c5208a93c8dd19

parent

62b7d01b1c14644d771cab35732f9f99ea83e50b

M app/index.htmlapp/index.html

@@ -38,6 +38,7 @@ <script src="js/modules/info.js"> </script>

<script src="js/modules/tags.js"> </script> <script src="js/modules/guide.js"> </script> <script src="js/modules/document.js"> </script> + <script src="js/modules/search.js"> </script> <script src="js/app.js"> </script> </body> </html>
M app/js/app.jsapp/js/app.js

@@ -11,6 +11,7 @@ '/info': app.info,

"/tags/:id": app.tags, "/document/:action/:id...": app.document, "/guide/:id": app.guide, - "/new": app.create + "/new": app.create, + "/search": app.search }); }());
M app/js/models.jsapp/js/models.js

@@ -29,6 +29,16 @@ url: "/v1/docs?contents=false&tags="+tag

}).then(docs); }; + Doc.search = function(search, offset, limit){ + offset = offset || 0; + limit = limit || 10; + var docs = m.prop(""); + return m.request({ + method: "GET", + url: "/v1/docs?contents=false&search="+search+"&limit="+limit+"&offset="+offset, + }).then(docs); + }; + Doc.get = function(id) { var doc = m.prop(""); return m.request({
A app/js/modules/search.js

@@ -0,0 +1,50 @@

+(function(){ + 'use strict'; + var app = window.LS || (window.LS = {}); + var u = LS.utils; + + // Search Module + app.search = {vm: {}}; + app.search.vm.init = function(){ + var vm = this; + vm.query = m.route.param("q"); + vm.offset = m.route.param("offset") || 0; + vm.limit = m.route.param("limit") || 10; + vm.result = m.prop({total: 0, results: []}); + vm.total = 0; + Doc.search(vm.query, vm.offset, vm.limit).then(function(result){ + vm.result(result); + vm.total = result.total; + }, vm.flashError); + }; + app.search.main = function(){ + var vm = app.search.vm; + var result = vm.result(); + var title = m("h2.col-md-12", ["You searched for: ", m("em", vm.query)]); + var total = m("p.col-md-12", [m("strong", result.total), " hits"]); + var resultPanel = function(res){ + var obj = {}; + obj.title = res.id; + obj.content = m("div", [ + m("p", ["Created on: ", u.date(res.created)]), + m("p", res.tags.map(function(tag){ + return u.taglink(tag); + })) + ] + ); + return m(".row.search-result", m(".col-md-12", [u.panel(obj)])); + }; + var results = m(".row", [m(".col-md-12", result.results.map(resultPanel))]); + + return m("section", [ + m(".row", title), + m(".row", total), + m(".row.text-center", [u.paginator(vm)]), + results, + m(".row.text-center", [u.paginator(vm)]) + ]); + }; + + u.layout(app.search); + +}());
M app/js/navbar.jsapp/js/navbar.js

@@ -9,18 +9,19 @@ app.navlinks.vm.init();

}, vm: { init: function(){ - this.info = Info.get(); + var vm = this; + vm.info = Info.get(); this.activelink = function(url){ return (m.route().match(new RegExp("^\/"+url))) ? "active" : ""; }; - this.guidelinks = [ + vm.guidelinks = [ {path: "/guide/overview", title: "Overview"}, {path: "/guide/getting-started", title: "Getting Started"}, {path: "/guide/usage", title: "Usage"}, {path: "/guide/api", title: "API"}, {path: "/guide/credits", title: "Credits"} ]; - this.taglinks = function(info){ + vm.taglinks = function(info){ return info.tags.map(function(tag){ var key = Object.keys(tag)[0]; return {path: "/tags/"+key, title: key+" ("+tag[key]+")"};

@@ -44,6 +45,7 @@

app.navheader = { controller: function() {}, view: function(ctrl) { + var vm = app.navlinks.vm; return m(".navbar-header", [ m("button.navbar-toggle.collapsed[data-toggle='collapse'][data-target='#nav-collapse'][type='button']", [ m("span.sr-only", "Toggle navigation"),

@@ -57,13 +59,45 @@ }

}; app.searchbox = { - controller: function() {}, + controller: function() { + app.searchbox.vm.init(); + }, + vm: { + init: function(){ + var vm = this; + vm.query = m.prop(""); + vm.keySearch = function(el, isInitialized, context){ + $(el).keyup(function(event){ + m.redraw.strategy("none"); + vm.query($(el).val()); + if (event.which == 13){ + vm.search(); + } + }); + }; + vm.search = function(){ + m.route("/search?q="+vm.query()); + }; + } + }, view: function(ctrl) { + var vm = app.searchbox.vm; return m("form.navbar-form.navbar-right[role='search']", [ m(".input-group", [ - m("input.form-control[type='text'i][placeholder='Search...']"), + m("input.form-control", { + type:"text", + placeholder:"Search...", + onchange: m.withAttr("value", vm.query), + config: vm.keySearch, + value: vm.query() + }), m("span.input-group-btn", - m("button.btn.btn-default[type='button']", [m("i.fa.fa-search")])) + m("button.btn.btn-default", + { + type: "button", + onclick: vm.search + }, + [m("i.fa.fa-search")])) ]) ] );

@@ -83,6 +117,19 @@ app.navheader.view(ctrl.navheader),

m("#nav-collapse.collapse.navbar-collapse", [ app.navlinks.view(ctrl.navlinks), app.searchbox.view(ctrl.searchbox) + ]) + ]) + ]); + } + }; +}()); ]) + ]); + } + }; +}()); ]); + } + }; +}()););());;);());x) ]) ]) ]);
M app/js/utils.jsapp/js/utils.js

@@ -39,15 +39,79 @@ };

}; u.panel = function(obj){ + var title = ""; + var footer = ""; + if (obj.title){ + title = m(".panel-heading", [ + m("h2.panel-title", [obj.title]) + ]); + } + if (obj.footer){ + footer = m(".panel-footer", obj.footer); + } return m(".panel.panel-default", [ - m(".panel-heading", [ - m("h2.panel-title", [obj.title]) - ]), + title, m(".panel-body", [ obj.content - ]) + ]), + footer ]); }; + + /** + * - total + * - limit + * - offset + * - query + */ + u.paginator = function(obj) { + var max_page = Math.ceil(obj.total/obj.limit)-1; + var c_page = Math.ceil(obj.offset/obj.limit); + var page = function(n, sign, disabled){ + var klass; + if (disabled) { + klass = "disabled"; + } else { + klass = (n === c_page) ? "active" : "inactive"; + } + var first = (n === 0); + var last = (n == max_page); + var offset = obj.limit * n; + sign = sign || n+1; + return m("li", {class: klass}, + [m("a", { + href: "/search?q="+obj.query+"&offset="+offset+"&limit="+obj.limit, + config: m.route + }, [m.trust(sign)] + )] + ); + }; + var pages = []; + var prev; + var next; + for (var i=0; i<=max_page; i++){ + var p; + switch(i){ + case c_page-1: + prev = page(i, "&laquo;"); + break; + case c_page+1: + next = page(i, "&raquo;"); + break; + } + if (c_page === 0){ + prev = page(0, "&laquo;", true); + } + if (c_page === max_page){ + next = page(max_page, "&raquo;", true); + } + pages.push(page(i)); + } + pages.unshift(prev); + pages.push(next); + return m("nav", [m("ul.pagination", pages)]); + }; + u.dropdown = function(obj) { var el = "li.dropdown"; var icon = (obj.icon) ? m("i.fa."+obj.icon) : "";

@@ -113,4 +177,5 @@ return function(xhr) {

xhr.setRequestHeader("Content-Type", contentType); }; }; +}());}; }());
M app/styles/elements.lessapp/styles/elements.less

@@ -141,5 +141,8 @@ }

} .toolbar { - margin: 4px 0; + margin: 5px 0; } +.search-result { + margin: 5px 0; +}
M app/styles/litestore.cssapp/styles/litestore.css

@@ -1882,7 +1882,10 @@ color: #fff;

text-decoration: none; } .toolbar { - margin: 4px 0; + margin: 5px 0; +} +.search-result { + margin: 5px 0; } .note { -moz-background-clip: padding;

@@ -2682,4 +2685,4 @@ font-weight: normal;

font-size: 100%; color: #00cc33; content: "\f058" " "; -} +}