return (obj.textContent.replace(/\[[0-9]+\]/g, "") || obj.innerText.replace(/\[[0-9]+\]/g, "") || jQuery(obj).text().replace(/\[[0-9]+\]/g, "") || '').toLowerCase().indexOf(meta[3].toLowerCase()) >= 0;\r
};\r
\r
+/*\r
+ * Quick Search global vars\r
+ */\r
+ \r
+// Current search results preview table\r
+var currentTable = null;\r
+\r
+//Hightlighted index in search result preview table\r
+var currentIndex = -1;\r
+\r
\r
/*\r
* Add folding and filtering facilities to class description page.\r
$(this).nextAll().toggle();\r
})
- // Instert search field
- $("nav.main ul")
- .append(
- $(document.createElement("li"))
- .append(
- $(document.createElement("form"))
- .append(
- $(document.createElement("input"))\r
- .attr({
- id: "search",\r
- type: "text",\r
- value: "quick search..."\r
- })\r
- .addClass("notUsed")\r
- .keyup(function() {\r
- $(this).parent().parent().find("ul li:not(:icontains('" + $(this).val() + "'))").addClass("hide");\r
- $(this).parent().parent().find("ul li:icontains('" + $(this).val() + "')").removeClass("hide");\r
- })\r
- .focusout(function() {\r
- if($(this).val() == "") {\r
- $(this).addClass("notUsed");\r
- $(this).val("quick search...");\r
- }\r
- })\r
- .focusin(function() {\r
- if($(this).val() == "quick search...") {\r
- $(this).removeClass("notUsed");\r
- $(this).val("");\r
- }\r
- })
- )
- .submit( function() {
- if($("#search").val().length == 0)
- return false
-
- window.location = "full-index.html#q=" + $("#search").val();
- if(window.location.href.indexOf("full-index.html") > -1) {
- location.reload();
- }
- return false;
- })
- )
+ // Insert search field\r
+ $("nav.main ul")\r
+ .append(\r
+ $(document.createElement("li"))\r
+ .append(\r
+ $(document.createElement("form"))\r
+ .append(\r
+ $(document.createElement("input"))\r
+ .attr({\r
+ id: "search",\r
+ type: "text",\r
+ autocomplete: "off",\r
+ value: "quick search..."\r
+ })\r
+ .addClass("notUsed")\r
+\r
+ // Key management\r
+ .keyup(function(e) {\r
+ switch(e.keyCode) {\r
+\r
+ // Select previous result on "Up"\r
+ case 38:\r
+ // If already on first result, focus search input\r
+ if(currentIndex == 0) {\r
+ $("#search").val($(currentTable.find("tr")[currentIndex]).data("searchDetails").name);\r
+ $("#search").focus();\r
+ // Else select previous result\r
+ } else if(currentIndex > 0) {\r
+ $(currentTable.find("tr")[currentIndex]).removeClass("activeSearchResult");\r
+ currentIndex--;\r
+ $(currentTable.find("tr")[currentIndex]).addClass("activeSearchResult");\r
+ $("#search").val($(currentTable.find("tr")[currentIndex]).data("searchDetails").name);\r
+ $("#search").focus();\r
+ }\r
+ break;\r
+\r
+ // Select next result on "Down"\r
+ case 40:\r
+ if(currentIndex < currentTable.find("tr").length - 1) {\r
+ $(currentTable.find("tr")[currentIndex]).removeClass("activeSearchResult");\r
+ currentIndex++;\r
+ $(currentTable.find("tr")[currentIndex]).addClass("activeSearchResult");\r
+ $("#search").val($(currentTable.find("tr")[currentIndex]).data("searchDetails").name);\r
+ $("#search").focus();\r
+ }\r
+ break;\r
+ // Go to url on "Enter"\r
+ case 13:\r
+ if(currentIndex > -1) {\r
+ window.location = $(currentTable.find("tr")[currentIndex]).data("searchDetails").url;\r
+ return false;\r
+ }\r
+ if($("#search").val().length == 0)\r
+ return false\r
+ \r
+ window.location = "full-index.html#q=" + $("#search").val();\r
+ if(window.location.href.indexOf("full-index.html") > -1) {\r
+ location.reload();\r
+ } \r
+ return false;\r
+ break;\r
+\r
+ // Hide results preview on "Escape"\r
+ case 27:\r
+ $(this).blur();\r
+ if(currentTable != null) {\r
+ currentTable.remove();\r
+ currentTable = null;\r
+ }\r
+ break;\r
+\r
+ default:\r
+ if($("#search").val().length == 0) {\r
+ return false;\r
+ }\r
+ \r
+ // Remove previous table\r
+ if(currentTable != null) {\r
+ currentTable.remove();\r
+ }\r
+\r
+ // Build results table\r
+ currentIndex = -1;\r
+ currentTable = $(document.createElement("table"));\r
+\r
+ // Escape regexp related characters in query\r
+ var query = $("#search").val();\r
+ query = query.replace(/\[/gi, "\\[");\r
+ query = query.replace(/\|/gi, "\\|");\r
+ query = query.replace(/\*/gi, "\\*");\r
+ query = query.replace(/\+/gi, "\\+");\r
+ query = query.replace(/\\/gi, "\\\\");\r
+ query = query.replace(/\?/gi, "\\?");\r
+ query = query.replace(/\(/gi, "\\(");\r
+ query = query.replace(/\)/gi, "\\)");\r
+\r
+ var index = 0;\r
+ var regexp = new RegExp("^" + query, "i");\r
+ for(var entry in entries) {\r
+ if(index > 10) {\r
+ break;\r
+ }\r
+ var result = entry.match(regexp);\r
+ if(result != null && result.toString().toUpperCase() == $("#search").val().toUpperCase()) {\r
+ for(var i = 0; i < entries[entry].length; i++) {\r
+ if(index > 10) {\r
+ break;\r
+ }\r
+ currentTable.append(\r
+ $(document.createElement("tr"))\r
+ .data("searchDetails", {name: entry, url: entries[entry][i]["url"]})\r
+ .data("index", index)\r
+ .append($(document.createElement("td")).html(entry))\r
+ .append(\r
+ $(document.createElement("td"))\r
+ .addClass("entryInfo")\r
+ .html(entries[entry][i]["txt"] + " »"))\r
+ .mouseover( function() {\r
+ $(currentTable.find("tr")[currentIndex]).removeClass("activeSearchResult");\r
+ $(this).addClass("activeSearchResult");\r
+ currentIndex = $(this).data("index");\r
+ })\r
+ .mouseout( function() {\r
+ $(this).removeClass("activeSearchResult");\r
+ })\r
+ .click( function() {\r
+ window.location = $(this).data("searchDetails")["url"];\r
+ })\r
+ );\r
+ index++;\r
+ }\r
+ }\r
+ }\r
+ \r
+ // Initialize table properties\r
+ currentTable.attr("id", "searchTable");\r
+ currentTable.css("position", "absolute");\r
+ currentTable.width($("#search").outerWidth());\r
+ $("header").append(currentTable);\r
+ currentTable.offset({left: $("#search").offset().left + ($("#search").outerWidth() - currentTable.outerWidth()), top: $("#search").offset().top + $("#search").outerHeight()});\r
+ break;\r
+ }\r
+ })\r
+ .focusout(function() {\r
+ if($(this).val() == "") {\r
+ $(this).addClass("notUsed");\r
+ $(this).val("quick search...");\r
+ }\r
+ })\r
+ .focusin(function() {\r
+ if($(this).val() == "quick search...") {\r
+ $(this).removeClass("notUsed");\r
+ $(this).val("");\r
+ }\r
+ })\r
+ )\r
+ .submit( function() {\r
+ return false;\r
+ })\r
+ )\r
);\r
\r
/*\r
end
var head = "<meta charset=\"utf-8\">" +
- "<script type=\"text/javascript\" src=\"scripts/jquery-1.7.1.min.js\"></script>\n" +
+ "<script type=\"text/javascript\" src=\"scripts/jquery-1.7.1.min.js\"></script>\n" +
+ "<script type=\"text/javascript\" src=\"quicksearch-list.js\"></script>\n" +
"<script type=\"text/javascript\" src=\"scripts/js-facilities.js\"></script>\n" +
"<link rel=\"stylesheet\" href=\"styles/main.css\" type=\"text/css\" media=\"screen\" />"
add("<footer>{footer_text}</footer>")
add("</body></html>\n")
write_to("{dir}/full-index.html")
+
+ self.filename = "quicksearch-list"
+ clear
+ mainmod.file_quicksearch_list_doc(self)
+ write_to("{dir}/quicksearch-list.js")
end
# The doc node from the AST
# Return null is none
fun doc: nullable ADoc do return null
+
+ # Return a jason entry for quicksearch list JSON Object
+ fun json_entry(dctx: DocContext): String is abstract
+
+ # Return the qualified name as string
+ fun qualified_name: String is abstract
+
end
redef class MMModule
return "<a href=\"{html_name}.html\" title=\"{short_doc}\">{self}</a>"
end
+ redef fun json_entry(dctx) do
+ return "\{txt:\"{self.qualified_name}\",url:\"{html_name}.html\"\},"
+ end
+
+ redef fun qualified_name do
+ var buffer = new Buffer
+ for m in mnhe.smallers do
+ buffer.append("{m.html_name}::")
+ end
+ buffer.append("{self.name}")
+ return buffer.to_s
+ end
+
fun require_doc(dctx: DocContext): Bool
do
if dctx.public_only and not is_toplevel then return false
dctx.stage("</ul></article>\n")
dctx.close_stage
end
+
+ # Fill the quicksearch list JSON object
+ fun file_quicksearch_list_doc(dctx: DocContext)
+ do
+ var entities = new HashMap[String, Array[MMEntity]]
+ var props = new HashMap[MMGlobalProperty, Array[MMLocalProperty]]
+ for m in mhe.greaters_and_self do
+ if not m.require_doc(dctx) then continue
+ var a = new Array[MMEntity]
+ a.add(m)
+ entities[m.html_name] = a
+ end
+ for g in global_classes do
+ var lc = self[g]
+ if not lc.require_doc(dctx) then continue
+ var a = new Array[MMEntity]
+ a.add(lc)
+ entities[lc.html_name] = a
+ for gp in lc.global_properties do
+ var lp = lc[gp]
+ if not lp.require_doc(dctx) then continue
+ if props.has_key(lp.global) then
+ if not props[lp.global].has(lp) then
+ props[lp.global].add(lp)
+ end
+ else
+ props[lp.global] = [lp]
+ end
+ end
+ end
+
+ for k, v in props do
+ entities[k.short_name] = v
+ end
+
+ var keys = entities.keys.to_a
+ var sorter = new AlphaSorter[String]
+ sorter.sort(keys)
+
+ dctx.open_stage
+ dctx.stage("var entries = \{")
+ for key in keys do
+ dctx.add("\"{key}\": [")
+ for entity in entities[key] do
+ dctx.add(entity.json_entry(dctx))
+ end
+ dctx.add("],")
+ end
+ dctx.stage("\};")
+ dctx.close_stage
+ end
end
+redef class MMGlobalProperty
+ # Return the short name of the property
+ fun short_name: String do
+ return self.intro.html_name
+ end
+end
+
redef class MMLocalProperty
super MMEntity
# Anchor of the property description in the module html file
return "PROP_{local_class}_{cmangle(name)}"
end
+ redef fun json_entry(dctx) do
+ return "\{txt:\"{qualified_name}\",url:\"{local_class.html_name}.html#{html_anchor}\"\},"
+ end
+
+ redef fun qualified_name do
+ return "{intro_module.qualified_name}::{local_class.html_name}::{html_name}"
+ end
+
fun html_open_link(dctx: DocContext): String
do
if not require_doc(dctx) then print "not required {self}"
return "<a href=\"{html_name}.html\" title=\"{short_doc}\">{self}</a>"
end
+ redef fun json_entry(dctx) do
+ return "\{txt:\"{qualified_name}\",url:\"{html_name}.html\"\},"
+ end
+
+ redef fun qualified_name do
+ return "{intro_module.qualified_name}::{html_name}"
+ end
+
redef fun short_doc do return global.intro.short_doc
redef fun doc do return global.intro.doc