Update site search chinese input issue, add pagination, user feed back and performance
This commit is contained in:
parent
47d9eeea6c
commit
d98faba129
|
@ -125,8 +125,8 @@
|
|||
top: 14px;
|
||||
}
|
||||
#orbit-bar #search .icon-search {
|
||||
left: 13px;
|
||||
top: 15px;
|
||||
left: 20px;
|
||||
top: 12px;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
#orbit-bar #search .search-clear {
|
||||
|
@ -138,11 +138,114 @@
|
|||
cursor:pointer;
|
||||
}
|
||||
|
||||
/*Search Container*/
|
||||
#search_container{
|
||||
display: none;
|
||||
top: 40px;
|
||||
right: 20px;
|
||||
width: 40%;
|
||||
background: #FAFAFA;
|
||||
position: absolute;
|
||||
box-shadow: 0px 5px 20px #666;
|
||||
color: #666;
|
||||
font-family: "微軟正黑體", "Raleway";
|
||||
border-bottom-left-radius: 5px;
|
||||
border-bottom-right-radius: 5px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#search_head{
|
||||
text-align: right;
|
||||
padding: 5px 25px 5px 10px;
|
||||
/*border-bottom: 1px solid #CCC;*/
|
||||
color: #666;
|
||||
/*background: #EEE;*/
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
#search_loading{
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
#search_footer{
|
||||
min-height: 10px;
|
||||
padding: 5px 25px 5px 10px;
|
||||
border-top: 1px solid #DDD;
|
||||
border-bottom: 1px solid #CCC;
|
||||
color: #666;
|
||||
background: #EEE;
|
||||
}
|
||||
|
||||
#search_footer .pagination{
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#search_footer .pagination ul li a{
|
||||
padding: 4px 10px;
|
||||
color: #0053CF;
|
||||
}
|
||||
|
||||
#search_results{
|
||||
max-height: 500px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
#search_results img{
|
||||
margin: 20px auto;
|
||||
display: block;
|
||||
}
|
||||
#search_results::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
background: #CCC;
|
||||
}
|
||||
|
||||
#search_results::-webkit-scrollbar-track {
|
||||
}
|
||||
|
||||
#search_results::-webkit-scrollbar-thumb {
|
||||
background: #888;
|
||||
}
|
||||
|
||||
#search_results a:hover{
|
||||
text-decoration: none;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.seach_title{
|
||||
padding: 5px 0;
|
||||
color: #0053CF;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.search_result{
|
||||
padding: 15px 15px;
|
||||
/*border-bottom: 1px solid #DDD;
|
||||
border-top: 1px solid #FFF;*/
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.search_result:hover{
|
||||
background: #FFF;
|
||||
box-shadow: 0px 0px 20px #DDD;
|
||||
/*border-bottom: 1px solid #FFF;*/
|
||||
}
|
||||
|
||||
.search_result a{
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.search_result b{
|
||||
font-weight: normal;
|
||||
color: #B90000;
|
||||
}
|
||||
|
||||
/*User info*/
|
||||
#orbit-bar #orbit-user .user-pic {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin: -12px 10px -10px -15px;
|
||||
margin: -13px 10px -10px -15px;
|
||||
}
|
||||
|
||||
/*Language & flag*/
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
class SiteSearchController < ApplicationController
|
||||
include ActionView::Helpers::TextHelper
|
||||
def search
|
||||
startTime = Time.now
|
||||
if params[:keywords].present?
|
||||
modules = [
|
||||
{:key=>"announcement", :model=>"Bulletin", :fields=>["title","subtitle","text"], :url=>"/panel/announcement/front_end/bulletin/"}
|
||||
]
|
||||
|
||||
key_string = params[:keywords]
|
||||
key_string = key_string.strip.nil? ? key_string : key_string.strip
|
||||
keywords = key_string.split(/\s+(?=(?:[^"]*"[^"]*")*[^"]*$)/)
|
||||
regex = Regexp.union(keywords.map{|word| Regexp.new(".*"+word+".*", "i")})
|
||||
|
||||
result = []
|
||||
|
||||
# Search Pages
|
||||
Item.where(:app_frontend_url=>"page_contexts", :is_published=>true).each do |page|
|
||||
title = page.title
|
||||
context = PageContext.where(:page_id=>page.id).first.context rescue nil
|
||||
next if title.nil? and context.nil?
|
||||
|
||||
context = context.gsub(/<\/?[^>]*>/, "").gsub(/ /i,"") rescue ""
|
||||
title_matches = title.match(regex)
|
||||
context_matches = context.match(regex)
|
||||
if title_matches or context_matches
|
||||
tmp = {}
|
||||
tmp[:id] = page.id
|
||||
tmp[:module] = "page"
|
||||
tmp[:url] = "/"+page.path
|
||||
tmp[:title] = title
|
||||
tmp[:content] = context
|
||||
result.push(tmp)
|
||||
end
|
||||
end
|
||||
|
||||
# Search Modules
|
||||
modules.each do |mod|
|
||||
query = mod[:fields].map{|f| {f.to_sym => regex} }
|
||||
res = Kernel.const_get(mod[:model]).any_of(query)
|
||||
res.each do |r|
|
||||
tmp = {}
|
||||
tmp[:id] = r.id
|
||||
tmp[:module] = mod[:key]
|
||||
tmp[:url] = mod[:url]+r.id.to_s
|
||||
tmp[:content] = ""
|
||||
tmp[:matches] = 0
|
||||
mod[:fields].each do |f|
|
||||
value = ActionView::Base.full_sanitizer.sanitize(eval("r.#{f}")) rescue ""
|
||||
value = value.nil? ? "" : value
|
||||
|
||||
if f=="title" or f=="name"
|
||||
tmp[:title] = value
|
||||
else
|
||||
tmp[:content] << value
|
||||
end
|
||||
end
|
||||
|
||||
result.push(tmp)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
result.each do |res|
|
||||
res[:matches] = 0
|
||||
|
||||
res[:matches] += res[:title].match(/(#{key_string})/i) ? 500 : 0 rescue 0
|
||||
res[:matches] += res[:content].match(/(#{key_string})/i) ? 300 : 0 rescue 0
|
||||
|
||||
keywords.each do |k|
|
||||
res[:matches] += (res[:title].scan(/(#{k})/i).size)*100 + res[:content].scan(/(#{k})/i).size
|
||||
res[:title].gsub!(/(#{k})/i, '<b>\1</b>') rescue ""
|
||||
res[:content].gsub!(/(#{k})/i, '<b>\1</b>') rescue ""
|
||||
end
|
||||
|
||||
if res[:matches]==0
|
||||
result = result - [res]
|
||||
next
|
||||
end
|
||||
|
||||
res[:content] = truncate(res[:content], length: 120)
|
||||
end
|
||||
|
||||
result = result.sort_by { |k| k[:matches] }.reverse rescue []
|
||||
|
||||
render :json => { "results" => result, "time"=> ((Time.now-startTime)*1000).to_i , "keywords"=>keywords}
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,120 @@
|
|||
<div id="search_container">
|
||||
<div id='search_head'>
|
||||
<button type="button" id="search_close" class="close pull-left">×</button>
|
||||
<div id='search_time'></div>
|
||||
</div>
|
||||
<div id='search_results'>
|
||||
</div>
|
||||
<div id='search_footer'>
|
||||
<div class="pagination pagination-centered"><div class="pagination">
|
||||
<ul id="search_pagination">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
var interval = 0;
|
||||
var keyword;
|
||||
var searchLock=false;
|
||||
var results;
|
||||
|
||||
var Search = function(){
|
||||
var s = this;
|
||||
this.init = function(){
|
||||
$("#q").bind("input", function() {s.queueSearch();});
|
||||
|
||||
$("#search_form").submit(function(){s.queueSearch(); return false; });
|
||||
$("#search_close").click(function(){$("#search_container").fadeOut(300);});
|
||||
}
|
||||
|
||||
this.queueSearch = function(){
|
||||
if($("#q").val() != keyword && $("#q").val()!=""){
|
||||
keyword = $("#q").val();
|
||||
interval=500;
|
||||
if(!searchLock) s.processSearch();
|
||||
}else if($("#q").val()==""){
|
||||
keyword = "";
|
||||
$("#search_container").slideUp(300);
|
||||
}
|
||||
}
|
||||
this.processSearch = function(){
|
||||
keyword_tmp = keyword;
|
||||
searchLock = true;
|
||||
if(interval==0 && keyword!=""){
|
||||
$("#search_time").html("");
|
||||
$("#search_results").scrollTop(0);
|
||||
$("#search_results").html('<img src="http://ridepal.com/images/homeimg/preloader_transparent.gif" width="50">');
|
||||
$("#search_pagination").html("");
|
||||
$("#search_container").slideDown(300);
|
||||
|
||||
$.getJSON("/site_search", {"keywords" : keyword}, function(data){
|
||||
if(keyword_tmp != keyword) {
|
||||
searchLock = false;
|
||||
s.processSearch();
|
||||
return;
|
||||
}
|
||||
|
||||
results = data.results;
|
||||
|
||||
$("#search_time").html("Found "+results.length+" Results, Search Time: "+data.time+"ms");
|
||||
|
||||
renderResults(1);
|
||||
searchLock = false;
|
||||
});
|
||||
}else if(interval>0){
|
||||
interval -= 100;
|
||||
setTimeout(s.processSearch,100);
|
||||
}else if(keyword==""){
|
||||
searchLock = false;
|
||||
}
|
||||
}
|
||||
|
||||
s.init();
|
||||
}();
|
||||
|
||||
function renderResults(page){
|
||||
var rangeStart = ((page-1)==0) ? 0 : ((page-1)*5)-1;
|
||||
var tmpResults = results.slice(rangeStart, rangeStart+5);
|
||||
|
||||
$("#search_results").scrollTop(0);
|
||||
$("#search_results").html("");
|
||||
$.each(tmpResults,function(key,res){
|
||||
search_result = "<div class='search_result'>"+
|
||||
"<a href='"+res.url+"' target='_blank'>"+
|
||||
"<div class='seach_title'>"+res.title+"</div>"+
|
||||
"</a>"+
|
||||
"<span>"+res.content+"</span>"+
|
||||
"</div>";
|
||||
$("#search_results").append(search_result);
|
||||
});
|
||||
renderPagination(page);
|
||||
}
|
||||
|
||||
function renderPagination(page){
|
||||
var totalPages = Math.round(results.length/5);
|
||||
var startPage = ((page-5)<=0) ? 1 : page-5;
|
||||
var ednPage = ( (startPage+10)>totalPages ) ? totalPages : (startPage+10);
|
||||
|
||||
if( (ednPage-startPage)<10 && totalPages>10 ){
|
||||
startPage = ednPage-10;
|
||||
}
|
||||
|
||||
$("#search_pagination").html("");
|
||||
|
||||
for(var i=startPage;i<=ednPage;i++){
|
||||
var active = (i==page) ? "active" : "";
|
||||
$("#search_pagination").append('<li class="page '+active+'"><a href="#" onclick="renderResults('+i+');">'+i+'</a></li>');
|
||||
}
|
||||
|
||||
if(page<totalPages){
|
||||
$("#search_pagination").append('<li class="next"><a href="#" onclick="renderResults('+(page+1)+');"><span>Next</span></a></li>');
|
||||
$("#search_pagination").append('<li class="last"><a href="#" onclick="renderResults('+totalPages+');"><span>Last</span></a></li>');
|
||||
}
|
||||
if(page!=1){
|
||||
$("#search_pagination").prepend('<li class="first"><a href="#" onclick="renderResults('+1+');"><span>First</span></a></li>');
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
Loading…
Reference in New Issue