Prototype of offline/backendless search functionality and generating/building website from activity bundles (NOTE: cannot add incrementally new activity bundles for now as it will overwrite search index rather than appending to it)
This commit is contained in:
@@ -0,0 +1,199 @@
|
||||
@font-face {
|
||||
font-family: "Quicksand-Regular";
|
||||
/* license: url("../fonts/Quicksand-Regular.txt"); */
|
||||
src: url("../fonts/Quicksand-Regular.ttf");
|
||||
}
|
||||
|
||||
body {
|
||||
/* background-color: #f4ffac4d; */
|
||||
background-color: #fcfcfc;
|
||||
color: #00386c;
|
||||
font-family: Quicksand-Regular, roboto, sans-serif, monospace;
|
||||
font-size: 1.2rem;
|
||||
line-height: 1.5;
|
||||
margin: 0 auto;
|
||||
max-width: 900px;
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
header {
|
||||
align-items: center;
|
||||
border-bottom: 0.15rem solid #470598;
|
||||
margin-bottom: 2rem;
|
||||
margin-top: 2rem;
|
||||
padding-bottom: 1rem
|
||||
}
|
||||
|
||||
#Heading {
|
||||
color: #099800; /*#00301fb3*/
|
||||
font-size: 250%;
|
||||
padding: 1rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#Heading a {
|
||||
color: #bfa800;
|
||||
text-decoration: underline ;
|
||||
}
|
||||
|
||||
#Heading a:hover {
|
||||
color: #057e53 ;
|
||||
}
|
||||
|
||||
h1 {
|
||||
clear: both;
|
||||
color: Crimson ;
|
||||
font-weight: normal;
|
||||
line-height: 1;
|
||||
margin-bottom: -0.25rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#color1 {
|
||||
color: #0c007e;
|
||||
}
|
||||
|
||||
#color1 a:hover {
|
||||
color: DarkGoldenRod;
|
||||
}
|
||||
|
||||
#color2 {
|
||||
color: Crimson;
|
||||
}
|
||||
|
||||
#color2 a:hover {
|
||||
color: #9fbd06;
|
||||
}
|
||||
|
||||
#color3 {
|
||||
color: ForestGreen;
|
||||
}
|
||||
|
||||
#color3 a:hover {
|
||||
color: Teal;
|
||||
}
|
||||
|
||||
#color4 {
|
||||
color: DarkGoldenRod;
|
||||
}
|
||||
|
||||
#color4 a:hover {
|
||||
color: #4f08a7;
|
||||
}
|
||||
|
||||
#color5 {
|
||||
color: #90006b;
|
||||
}
|
||||
|
||||
#color5 a:hover {
|
||||
color: #08966e;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: #0c007e;
|
||||
font-size: 175%;
|
||||
font-weight: normal;
|
||||
line-height: 1;
|
||||
margin-bottom: -0.25rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
color: DarkGoldenRod;
|
||||
font-size: 150%;
|
||||
font-weight: normal;
|
||||
line-height: 1;
|
||||
margin-bottom: -0.25rem;
|
||||
}
|
||||
|
||||
h4 {
|
||||
color: SeaGreen;
|
||||
font-size: 125%;
|
||||
font-weight: normal;
|
||||
line-height: 1;
|
||||
margin-bottom: -0.25rem;
|
||||
}
|
||||
|
||||
h5 {
|
||||
color: Teal;
|
||||
font-size: 100%;
|
||||
font-weight: bold;
|
||||
margin-bottom: -0.25rem;
|
||||
}
|
||||
|
||||
h6 {
|
||||
color: ForestGreen ;
|
||||
font-size: 100%;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
#Date {
|
||||
color: #0b8f73;
|
||||
margin-bottom: -1rem;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #260000;
|
||||
}
|
||||
|
||||
p a {
|
||||
color: #90006b;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #057e53 ;
|
||||
}
|
||||
|
||||
img {
|
||||
background-color: Teal;
|
||||
display: block; /*required for aligning image to center*/
|
||||
margin: auto; /*align image to center*/
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
hr {
|
||||
color: teal;
|
||||
}
|
||||
|
||||
|
||||
footer {
|
||||
border-top: 0.15rem solid #f60000;
|
||||
font-size: 85%;
|
||||
line-height: 1.5;
|
||||
margin-top: 2.5rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
footer a {
|
||||
color: #400090;
|
||||
}
|
||||
|
||||
#app_search {
|
||||
margin: auto;
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
/*=========================================*/
|
||||
|
||||
@media only screen and (min-width:10in) and (orientation:landscape) {
|
||||
body {
|
||||
/* margin: 0 5% 0 5%; */
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width:1000px) {
|
||||
body {
|
||||
margin: 0 2% 0 2%;
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (orientation:portrait) {
|
||||
body {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,93 @@
|
||||
Copyright 2011 The Quicksand Project Authors (https://github.com/andrew-paglinawan/QuicksandFamily), with Reserved Font Name “Quicksand”.
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
search.html
|
||||
Vendored
+10872
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,160 @@
|
||||
"use strict";
|
||||
|
||||
var similarString = function(a, b) {
|
||||
return !a.localeCompare(b, undefined, {sensitivity: 'base'});
|
||||
}
|
||||
|
||||
var countSimilarWordsInStrings = function(str1, str2) {
|
||||
var count = 0;
|
||||
var array1 = str1.split(' ');
|
||||
var array2 = str2.split(' ');
|
||||
for (var wordX of array1) {
|
||||
for (var wordY of array2) {
|
||||
if (similarString(wordX, wordY))
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// FIXME: function not yet tested
|
||||
var partialStrMatch = function(str1, str2) {
|
||||
var lengthDiff = str1.length - str2.length;
|
||||
|
||||
if (lengthDiff < 0) {
|
||||
[str1, str2] = [str2, str1];
|
||||
lengthDiff = -lengthDiff;
|
||||
}
|
||||
|
||||
for (var i=0; i <= lengthDiff; i++) {
|
||||
var str1Part = str1.substr(i, i+lengthDiff);
|
||||
if (similarString(str1Part, str2))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
var search = {
|
||||
|
||||
_index : null,
|
||||
_queuedQuery : null,
|
||||
|
||||
appObjToHtml : function(app) {
|
||||
var html = '<hr><h1><a href="./app/'+app.name+'.html">'+app.name+'</a></h1>\n<p><img src="./icons/'+app.name+'.svg" style="max-width: 250px"></img></p>\n<div id=summary><h2>Summary</h2>\n<p>'+app.summary+'</p>\n</div>\n<div id=description><h2>Description</h2>\n<p>'+app.description+'</p>\n</div>\n<div id=tags><h2>Tags</h2>\n<ul>\n';
|
||||
for (var tag of app.tags)
|
||||
html += '<li>'+ tag +'</li>\n';
|
||||
html += '</ul>\n</div>\n';
|
||||
return html;
|
||||
},
|
||||
|
||||
assignIndex : function(index) {
|
||||
this._index = index;
|
||||
if (this._queuedQuery !== null) {
|
||||
var queuedQuery = this._queuedQuery;
|
||||
this._queuedQuery = null;
|
||||
performSearch(queuedQuery);
|
||||
}
|
||||
},
|
||||
|
||||
displayResults : function(results) {
|
||||
$("#searchResults").show();
|
||||
|
||||
if (results[0][0] <= 0) {
|
||||
$(".sR:eq(1)").html("<h1>No search result found</h1>");
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i=0; i <= $(".sR").length; i++) {
|
||||
|
||||
// No more entries matching query
|
||||
if (results[i][0] <= 0)
|
||||
break
|
||||
|
||||
var app = this._index[results[i][1]];
|
||||
var html = this.appObjToHtml(app);
|
||||
$(".sR:eq("+i+")").html(html);
|
||||
}
|
||||
},
|
||||
|
||||
getQueryParameters : function (queryString) {
|
||||
var queryString = document.location.search;
|
||||
return this.parseQueryParameters(queryString);
|
||||
},
|
||||
|
||||
indexLoaded : function () {
|
||||
return (this._index !== null);
|
||||
},
|
||||
|
||||
init : function () {
|
||||
var params = this.getQueryParameters();
|
||||
if (params.q) {
|
||||
var query = params.q[0];
|
||||
query = query.replace("+", " ");
|
||||
$('input[name="q"]')[0].value = query;
|
||||
this.performSearch(query);
|
||||
}
|
||||
},
|
||||
|
||||
parseQueryParameters : function (queryString) {
|
||||
var parameters = {}
|
||||
var parts = queryString.substr(queryString.indexOf('?')+1).split('&');
|
||||
for (var pair of parts) {
|
||||
var spliter = pair.indexOf('=');
|
||||
var key = pair.substr(0, spliter);
|
||||
var value = pair.substr(spliter+1);
|
||||
if (key in parameters)
|
||||
parameters[key].push(value);
|
||||
else
|
||||
parameters[key] = [value];
|
||||
}
|
||||
return parameters;
|
||||
},
|
||||
|
||||
performSearch : function (query) {
|
||||
if (this.indexLoaded())
|
||||
this.processSearch(query);
|
||||
else
|
||||
this._queuedQuery = query;
|
||||
},
|
||||
|
||||
processSearch : function (query) {
|
||||
var results = this.rankApps(query);
|
||||
|
||||
results.sort(function(a, b) {
|
||||
// sort in descending rank order
|
||||
return b[0]-a[0];
|
||||
});
|
||||
|
||||
this.displayResults(results);
|
||||
},
|
||||
|
||||
rankApp : function(app, query) {
|
||||
var rank = 0;
|
||||
rank += 10*countSimilarWordsInStrings(app.name, query);
|
||||
// rank += partialStrMatch(app.name, query);
|
||||
rank += 3*countSimilarWordsInStrings(app.summary, query);
|
||||
// rank += partialStrMatch(app.summary, query);
|
||||
rank += 2*countSimilarWordsInStrings(app.description, query);
|
||||
// rank += partialStrMatch(app.description, query);
|
||||
for (var tag of app.tags)
|
||||
rank += 5*countSimilarWordsInStrings(tag, query);
|
||||
// below statement causes error: tag is undefined when empty?
|
||||
// rank += partialStrMatch(tag, query);
|
||||
return rank;
|
||||
},
|
||||
|
||||
rankApps : function(query) {
|
||||
var results = [];
|
||||
for (var i=0; i < this._index.length; i++) {
|
||||
var app = this._index[i];
|
||||
var rank = this.rankApp(app, query);
|
||||
results.push([rank, i]);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
$(document).ready( function() {
|
||||
search.init();
|
||||
});
|
||||
@@ -0,0 +1,75 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>Sugar Activites App Store Search Prototype</title>
|
||||
<meta charset="utf-8"/>
|
||||
<link rel="stylesheet" type="text/css" href="./css/main.css"/>
|
||||
<script type="application/javascript" src="./js/jquery.js"></script>
|
||||
<script type="application/javascript" src="./js/search.js"></script>
|
||||
<script type="application/javascript" src="./js/index.js" defer></script>
|
||||
<!-- <script type="application/json" src="./index.json" defer></script> -->
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id=searchBar>
|
||||
<form action="" method="GET" id=app_search>
|
||||
<input
|
||||
type=text
|
||||
placeholder="Search Activities"
|
||||
name="q"
|
||||
id="search_box"
|
||||
/>
|
||||
<input
|
||||
type="submit"
|
||||
value="Search"
|
||||
id="search_button"
|
||||
/>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id=searchResults style="display:none">
|
||||
<p class=sR>
|
||||
<div class=appName>
|
||||
</div>
|
||||
</p>
|
||||
<p class=sR>
|
||||
<div class=appName>
|
||||
</div>
|
||||
</p>
|
||||
<p class=sR>
|
||||
<div class=appName>
|
||||
</div>
|
||||
</p>
|
||||
<p class=sR>
|
||||
<div class=appName>
|
||||
</div>
|
||||
</p>
|
||||
<p class=sR>
|
||||
<div class=appName>
|
||||
</div>
|
||||
</p>
|
||||
<p class=sR>
|
||||
<div class=appName>
|
||||
</div>
|
||||
</p>
|
||||
<p class=sR>
|
||||
<div class=appName>
|
||||
</div>
|
||||
</p>
|
||||
<p class=sR>
|
||||
<div class=appName>
|
||||
</div>
|
||||
</p>
|
||||
<p class=sR>
|
||||
<div class=appName>
|
||||
</div>
|
||||
</p>
|
||||
<p class=sR>
|
||||
<div class=appName>
|
||||
</div>
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user