Add: static/js/index.advanced-search-form.js, static/sass/index.sass, static/css/lib/jqueryui.custom.min.css -Add `jQuery UI` autocompletion menu to the advanced-search form's language input field, to replace `twitter typeahead` (which was incompatible with the new form's style rules). static/js/index.advanced-search-form.js -Add regex field specifier to query string.tags/v1.0^2
@@ -10,25 +10,14 @@ var searchGroups = $("div#search-groups"); | |||
(function loadInputFieldWidgets(){ | |||
$(".search-group input#date-last-modified").datepicker(); | |||
$(".search-group input#date-created").datepicker(); | |||
var languages = new Bloodhound({ | |||
datumTokenizer: Bloodhound.tokenizers.obj.whitespace("value"), | |||
queryTokenizer: Bloodhound.tokenizers.whitespace, | |||
local: $.map(TYPEAHEAD_LANGUAGES, function(state){ | |||
return {value : state}; | |||
}) | |||
}); | |||
languages.initialize(); | |||
$("#language.typeahead").typeahead({ | |||
hint: true, | |||
highlight: true, | |||
minLength: 1 | |||
}, | |||
{ | |||
name: "languages", | |||
displayKey: "value", | |||
source: languages.ttAdapter() | |||
$("#autocomplete").autocomplete({ | |||
source: function(request, response){ | |||
var matcher = new RegExp( | |||
$.ui.autocomplete.escapeRegex(request.term), "i"); | |||
response($.grep(AUTOCOMPLETE_LANGUAGES, function(item){ | |||
return matcher.test(item); | |||
})); | |||
} | |||
}); | |||
}()); | |||
@@ -36,18 +25,19 @@ var searchGroups = $("div#search-groups"); | |||
* Set all advanced search form button callbacks. | |||
*/ | |||
(function setSearchFormCallbacks(){ | |||
// Create a new search group, and update the `#sidebar` checklist accordingly. | |||
// Create a new search group, and update the `#sidebar` checklist. | |||
$("button#add-group").click(function(){ | |||
$("div#sidebar input[type=checkbox]").prop("checked", false); | |||
searchGroups.children("#selected").removeAttr("id"); | |||
var searchGroup = $("<div/>", {class : "search-group", id : "selected"}); | |||
searchGroups.append(searchGroup.append(createSearchGroupInput("language"))); | |||
searchGroups.append( | |||
searchGroup.append(createSearchGroupInput("language"))); | |||
$("div#sidebar input[type=checkbox]#language").prop("checked", true); | |||
}); | |||
// Remove the currently selected group if it's not the only one, and mark one | |||
// of its siblings as selected. | |||
// Remove the currently selected group if it's not the only one, and mark | |||
// one of its siblings as selected. | |||
$("button#remove-group").click(function(){ | |||
var currentGroup = $("div.search-group#selected"); | |||
@@ -96,7 +86,7 @@ var searchGroups = $("div#search-groups"); | |||
function createSearchGroupInput(fieldId){ | |||
return [ | |||
"<div id='" + fieldId + "'>", | |||
"<div>" + fieldId.replace(/-/g, " ") + "</div>", | |||
"<div class='name'>" + fieldId.replace(/-/g, " ") + "</div>", | |||
"<input class='" + fieldId + "' name='" + fieldId + "'type='text'>", | |||
"<input type='checkbox' name='regex'><span>Regex</span>", | |||
"</div>" | |||
@@ -111,28 +101,35 @@ function assembleQuery(){ | |||
var groupQueries = []; | |||
for(var group = 0; group < groups.length; group++){ | |||
var inputs = groups[group].querySelectorAll("input[type=text]"); | |||
var groupQuery = [] | |||
for(var field = 0; field < inputs.length; field++) | |||
if(inputs[field].value.length > 0) | |||
groupQuery.push(genFieldQueryString(inputs[field])); | |||
var inputFields = groups[group].querySelectorAll("input[type=text]"); | |||
var regexCheckbox = groups[group].querySelectorAll("input[name=regex]"); | |||
var groupQuery = []; | |||
for(var field = 0; field < inputFields.length; field++) | |||
if(inputFields[field].value.length > 0) | |||
groupQuery.push(genFieldQueryString( | |||
inputFields[field], regexCheckbox[field].checked)); | |||
groupQueries.push(groupQuery.join(" AND ")); | |||
} | |||
// console.log(groupQueries.join(" OR ")); | |||
console.log(groupQueries.join(" OR ")); | |||
} | |||
/* | |||
* Generate a processed query string for an input field's value. | |||
* | |||
* @param field An `input[type=text]` DOM element. | |||
* @param field (DOM element) An `input[type=text]` element. | |||
* @param hasRegex (boolean) Whether or not the field's value has regex. | |||
*/ | |||
function genFieldQueryString(field){ | |||
function genFieldQueryString(field, hasRegex){ | |||
var terms = field.value.replace(/\\/g, "\\\\").replace(/\"/g, "\\\""); | |||
if(field.value.indexOf('"') >= 0) | |||
return '"' + field.getAttribute("name") + ":" + terms + '"'; | |||
return terms; | |||
var query = field.getAttribute("name") + ":" + ((hasRegex)?"re:":"") + terms; | |||
if(field.value.indexOf('"') >= 0){ | |||
// ['"', field.getAttribute("name"), ":", regex?"re:":"", terms, '"'] | |||
return '"' + query + '"'; | |||
} | |||
return query; | |||
} | |||
(function testQueryStringGeneration(){ | |||
@@ -1,42 +1,24 @@ | |||
/* | |||
Stylesheet for index.html. | |||
Stylesheet for `index.html`. | |||
*/ | |||
@import mixins | |||
@import variables | |||
$minSearchFieldsWidth: 490px | |||
.ui-datepicker | |||
font-size: 70% | |||
.twitter-typeahead | |||
// display: inline-block | |||
width: 60% | |||
.tt-hint | |||
color: $baseColor2 | |||
.tt-dropdown-menu | |||
width: 100% | |||
padding: 4px 0 | |||
background-color: white | |||
border: 1px solid $baseColor2 | |||
.tt-suggestion | |||
padding: 4px | |||
p | |||
margin: 0 | |||
strong | |||
color: $baseColor1 | |||
.ui-autocomplete | |||
max-height: 30% | |||
overflow-x: hidden | |||
overflow-y: scroll | |||
padding: 0px | |||
&.tt-cursor | |||
@extend .t1 | |||
>li.ui-menu-item a.ui-state-focus | |||
@include vendor(transition, background-color 0.3s ease-out) | |||
background-color: $baseColor1 | |||
* | |||
color: white | |||
div#search-field | |||
@extend .t2 | |||
@@ -70,8 +52,6 @@ div#search-field | |||
color: $baseColor2 | |||
font-style: italic | |||
$minSearchFieldsWidth: 490px | |||
form#search-bar | |||
min-width: $minSearchFieldsWidth | |||
@@ -114,178 +94,180 @@ div#search-field | |||
width: 26px | |||
height: 26px | |||
div#advanced-search | |||
background-color: white | |||
border: 1px solid $baseColor3 | |||
font-size: 96% | |||
height: 400px | |||
min-width: $minSearchFieldsWidth | |||
padding-top: 0px | |||
overflow-x: auto | |||
overflow-y: hidden | |||
#heading | |||
color: $baseColor2 | |||
display: block | |||
font-size: 120% | |||
padding-left: 1% | |||
padding-top: 1% | |||
width: 100% | |||
&.partly-visible | |||
margin-top: 0% | |||
padding-bottom: 3% | |||
position: absolute | |||
width: 100% | |||
div | |||
display: inline-block | |||
font-size: 110% | |||
#title | |||
position: absolute | |||
top: -1% | |||
left: 1% | |||
&#col1 | |||
width: 25% | |||
span | |||
font-size: 50% | |||
&#col2 | |||
width: 75% | |||
form#search-bar | |||
padding-top: 3% | |||
margin-left: auto | |||
margin-right: auto | |||
width: 60% | |||
>div | |||
@include vendor(box-sizing, border-box) | |||
div#advanced-search | |||
background-color: white | |||
border: 1px solid $baseColor3 | |||
display: none | |||
font-size: 96% | |||
height: 400px | |||
min-width: $minSearchFieldsWidth | |||
padding-top: 0px | |||
overflow-x: auto | |||
overflow-y: hidden | |||
#heading | |||
color: $baseColor2 | |||
display: block | |||
font-size: 120% | |||
padding-left: 1% | |||
padding-top: 1% | |||
width: 100% | |||
display: inline-block | |||
float: left | |||
div | |||
display: inline-block | |||
font-size: 110% | |||
#sidebar | |||
padding-left: 1% | |||
&#col1 | |||
width: 25% | |||
>ul | |||
list-style: none | |||
padding-left: 0 | |||
margin-bottom: 8% | |||
margin-top: 2% | |||
li | |||
margin-bottom: 2% | |||
label | |||
user-select: none | |||
div | |||
@extend .t3 | |||
background-color: $lightGray | |||
border: none | |||
padding: 3% | |||
width: 85% | |||
&:hover, &.selectedInputField | |||
@extend .t3 | |||
background-color: $baseColor2 | |||
color: white | |||
cursor: pointer | |||
width: 90% | |||
input[type="checkbox"] | |||
display: none | |||
&:checked + label > div | |||
@extend .selectedInputField | |||
background-color: $baseColor1 | |||
color: white | |||
width: 90% | |||
button#add-group | |||
background-color: $lightBlue | |||
border: none | |||
color: white | |||
display: block | |||
height: 40px | |||
margin-bottom: 2% | |||
overflow: hidden | |||
white-space: nowrap | |||
width: 40px | |||
span | |||
font-size: 150% | |||
font-weight: bold | |||
margin-left: 6px | |||
margin-right: 14px | |||
&#col2 | |||
width: 75% | |||
>div | |||
@include vendor(box-sizing, border-box) | |||
display: inline-block | |||
float: left | |||
&:hover | |||
#sidebar | |||
padding-left: 1% | |||
width: 25% | |||
>ul | |||
list-style: none | |||
padding-left: 0 | |||
margin-bottom: 8% | |||
margin-top: 2% | |||
li | |||
margin-bottom: 2% | |||
label | |||
user-select: none | |||
div | |||
@extend .t3 | |||
background-color: $blue | |||
cursor: pointer | |||
background-color: $lightGray | |||
border: none | |||
padding: 3% | |||
width: 85% | |||
&:hover, &.selectedInputField | |||
@extend .t3 | |||
background-color: $baseColor2 | |||
color: white | |||
cursor: pointer | |||
width: 90% | |||
input[type="checkbox"] | |||
display: none | |||
&:checked + label > div | |||
@extend .selectedInputField | |||
background-color: $baseColor1 | |||
color: white | |||
width: 90% | |||
button#remove-group | |||
@extend button#add-group | |||
button#add-group | |||
background-color: $lightBlue | |||
border: none | |||
color: white | |||
display: block | |||
height: 40px | |||
margin-bottom: 2% | |||
overflow: hidden | |||
white-space: nowrap | |||
width: 40px | |||
background-color: #D82D48 | |||
span | |||
font-size: 150% | |||
font-weight: bold | |||
margin-left: 6px | |||
margin-right: 14px | |||
span | |||
padding-left: 3px | |||
&:hover | |||
@extend .t3 | |||
&:hover | |||
@extend .t3 | |||
background-color: $blue | |||
cursor: pointer | |||
width: 90% | |||
background-color: #F11437 | |||
button#remove-group | |||
@extend button#add-group | |||
#search-groups | |||
margin-top: 1% | |||
max-height: 93% | |||
overflow-y: auto | |||
width: 75% | |||
background-color: #D82D48 | |||
.search-group | |||
@include vendor(transition, all 0.6s ease-out) | |||
span | |||
padding-left: 3px | |||
background-color: $lightGray | |||
padding: 1% | |||
margin-bottom: 2% | |||
width: 97% | |||
&:hover | |||
@extend .t3 | |||
>div | |||
margin-bottom: 0.7% | |||
background-color: #F11437 | |||
>div | |||
display: inline-block | |||
width: 18% | |||
#search-groups | |||
margin-top: 1% | |||
max-height: 93% | |||
overflow-y: auto | |||
width: 75% | |||
>input[type=text] | |||
padding: 2px | |||
width: 60% | |||
.search-group | |||
@include vendor(transition, all 0.6s ease-out) | |||
>input[type=checkbox] | |||
margin-left: 2% | |||
background-color: $lightGray | |||
padding: 1% | |||
margin-bottom: 2% | |||
width: 97% | |||
&:checked + span | |||
@extend .t2 | |||
>div | |||
margin-bottom: 0.7% | |||
color: green | |||
font-weight: bold | |||
>div.name | |||
display: inline-block | |||
width: 18% | |||
span.regex | |||
font-size: 80% | |||
>input[type=text] | |||
display: inline-block | |||
padding: 2px | |||
width: 60% | |||
&#selected | |||
background-color: #CACACA | |||
>input[type=checkbox] | |||
margin-left: 2% | |||
&.partly-visible | |||
margin-top: 0% | |||
padding-bottom: 3% | |||
position: absolute | |||
width: 100% | |||
&:checked + span | |||
@extend .t2 | |||
#title | |||
position: absolute | |||
top: -1% | |||
left: 1% | |||
color: green | |||
font-weight: bold | |||
span | |||
font-size: 50% | |||
span.regex | |||
font-size: 80% | |||
form#search-bar | |||
padding-top: 3% | |||
margin-left: auto | |||
margin-right: auto | |||
width: 60% | |||
&#selected | |||
background-color: #CACACA | |||
div#results | |||
margin: 3% auto 0 auto | |||
@@ -13,12 +13,12 @@ | |||
{{ assets.tag("index.css") }} | |||
<script> | |||
TYPEAHEAD_LANGUAGES = {{ typeahead_languages | safe }}; | |||
AUTOCOMPLETE_LANGUAGES = {{ autocomplete_languages | safe }}; | |||
</script> | |||
= endblock | |||
= block body | |||
<div id="search-field" class="partly-visible"> | |||
<div id="search-field"> | |||
<a id="title" href="/"> | |||
<div id="title"> | |||
<span id="title-bit">bit</span | |||
@@ -83,9 +83,10 @@ | |||
<div id="search-groups"> | |||
<div class="search-group" id="selected"> | |||
<div id="language"> | |||
<div>language</div> | |||
<input class="language" name="language" type="text"> | |||
<input type="checkbox" name="regex"><span class="regex">Regex</span> | |||
<div class="name">language</div> | |||
<input id="autocomplete" class="language" name="language" type="text"> | |||
<input type="checkbox" name="regex"> | |||
<span class="regex">Regex</span> | |||
</div> | |||
</div> | |||
</div> | |||
@@ -94,7 +95,6 @@ | |||
<button onclick="assembleQuery()"> | |||
Assemble | |||
</button> | |||
</div> | |||
</form> | |||
</div> | |||