Conflicts: bitshift/crawler/crawl.py bitshift/languages.pytags/v1.0^2
@@ -1,5 +1,5 @@ | |||
static/css/* | |||
!static/css/lib/* | |||
!lib | |||
*.swp | |||
.sass-cache | |||
@@ -22,7 +22,7 @@ database = Database() | |||
@app.route("/") | |||
def index(): | |||
return render_template("index.html", typeahead_languages=LANGS) | |||
return render_template("index.html", autocomplete_languages=LANGS) | |||
@app.route("/search.json") | |||
def search(): | |||
@@ -39,6 +39,7 @@ def crawl(): | |||
indexer.GitIndexer(repo_clone_queue, run_event)] | |||
parse_servers = start_parse_servers() | |||
time.sleep(5) | |||
for thread in threads: | |||
thread.start() | |||
@@ -33,6 +33,7 @@ class GitRepository(object): | |||
repository belongs to (eg, GitHub, BitBucket). | |||
:ivar rank: (float) The rank of the repository, as assigned by | |||
:class:`crawler.GitHubCrawler`. | |||
:ivar dirname: (str) The repository's on-disk directory name. | |||
""" | |||
def __init__(self, url, name, framework_name, rank): | |||
@@ -54,6 +55,7 @@ class GitRepository(object): | |||
self.name = name | |||
self.framework_name = framework_name | |||
self.rank = rank | |||
self.dirname = name.replace("-", "--").replace("/", "-") | |||
class GitIndexer(threading.Thread): | |||
""" | |||
@@ -125,19 +127,14 @@ class GitIndexer(threading.Thread): | |||
:type repo_url: :class:`GitRepository` | |||
""" | |||
with _ChangeDir("%s/%s" % (GIT_CLONE_DIR, repo.name)): | |||
with _ChangeDir("%s/%s" % (GIT_CLONE_DIR, repo.dirname)): | |||
try: | |||
self._insert_repository_codelets(repo) | |||
except Exception: | |||
self._logger.exception("Exception raised while indexing:") | |||
finally: | |||
if os.path.isdir("%s/%s" % (GIT_CLONE_DIR, repo.name)): | |||
if len([obj for obj in os.listdir('.') if | |||
os.path.isdir(obj)]) <= 1: | |||
shutil.rmtree("%s/%s" % ( | |||
GIT_CLONE_DIR, repo.name.split("/")[0])) | |||
else: | |||
shutil.rmtree("%s/%s" % (GIT_CLONE_DIR, repo.name)) | |||
if os.path.isdir("%s/%s" % (GIT_CLONE_DIR, repo.dirname)): | |||
shutil.rmtree("%s/%s" % (GIT_CLONE_DIR, repo.dirname)) | |||
def _insert_repository_codelets(self, repo): | |||
""" | |||
@@ -167,9 +164,9 @@ class GitIndexer(threading.Thread): | |||
authors = [(self._decode(author), None) for author in | |||
commits_meta[filename]["authors"]] | |||
codelet = Codelet("%s:%s" % (repo.name, filename), source, filename, | |||
None, authors, self._generate_file_url(filename, | |||
repo.url, repo.framework_name), | |||
url = self._generate_file_url(filename, repo.url, repo.framework_name) | |||
codelet = Codelet("%s: %s" % (repo.name, filename), source, | |||
filename, None, authors, url, | |||
commits_meta[filename]["time_created"], | |||
commits_meta[filename]["time_last_modified"], | |||
repo.rank) | |||
@@ -437,37 +434,20 @@ class _GitCloner(threading.Thread): | |||
""" | |||
GIT_CLONE_TIMEOUT = 500 | |||
queue_percent_full = (float(self.index_queue.qsize()) / | |||
self.index_queue.maxsize) * 100 | |||
exit_code = None | |||
command = ("perl -e 'alarm shift @ARGV; exec @ARGV' %d git clone" | |||
" --single-branch %s %s/%s || pkill -f git") | |||
command_attempt = 0 | |||
while exit_code is None: | |||
try: | |||
exit_code = subprocess.call(command % (GIT_CLONE_TIMEOUT, | |||
repo.url, GIT_CLONE_DIR, repo.name), shell=True) | |||
except Exception: | |||
time.sleep(1) | |||
command_attempt += 1 | |||
if command_attempt == 20: | |||
break | |||
else: | |||
continue | |||
else: | |||
break | |||
if exit_code != 0: | |||
if os.path.isdir("%s/%s" % (GIT_CLONE_DIR, repo.name)): | |||
shutil.rmtree("%s/%s" % (GIT_CLONE_DIR, repo.name)) | |||
self.index_queue.maxsize) * 100 | |||
command = ["perl", "-e", "alarm shift @ARGV; exec @ARGV", | |||
str(GIT_CLONE_TIMEOUT), "git", "clone", "--single-branch", | |||
repo.url, GIT_CLONE_DIR + "/" + repo.dirname] | |||
if subprocess.call(command) != 0: | |||
subprocess.call(["pkill", "-f", "git"]) # This makes Ben K upset | |||
if os.path.isdir("%s/%s" % (GIT_CLONE_DIR, repo.dirname)): | |||
shutil.rmtree("%s/%s" % (GIT_CLONE_DIR, repo.dirname)) | |||
return | |||
while self.index_queue.full(): | |||
time.sleep(THREAD_QUEUE_SLEEP) | |||
self.index_queue.put(repo) | |||
class _ChangeDir(object): | |||
@@ -131,7 +131,7 @@ class Database(object): | |||
def _decompose_url(self, cursor, url): | |||
"""Break up a URL into an origin (with a URL base) and a suffix.""" | |||
query = """SELECT origin_id, SUBSTR(?, LENGTH(origin_url_base)) | |||
query = """SELECT origin_id, SUBSTR(?, LENGTH(origin_url_base) + 1) | |||
FROM origins | |||
WHERE origin_url_base IS NOT NULL | |||
AND ? LIKE CONCAT(origin_url_base, "%")""" | |||
@@ -3,7 +3,7 @@ Contains information about database schema versions, and SQL queries to update | |||
between them. | |||
""" | |||
VERSION = 8 | |||
VERSION = 10 | |||
MIGRATIONS = [ | |||
# 1 -> 2 | |||
@@ -100,6 +100,28 @@ MIGRATIONS = [ | |||
[ | |||
"""ALTER TABLE `origins` | |||
DROP COLUMN `origin_image`""" | |||
], | |||
# 8 -> 9 | |||
[ | |||
"""DELIMITER // | |||
CREATE PROCEDURE `empty_database`() | |||
BEGIN | |||
DELETE FROM `codelets`; | |||
DELETE FROM `code`; | |||
DELETE FROM `cache`; | |||
ALTER TABLE `codelets` AUTO_INCREMENT = 1; | |||
ALTER TABLE `authors` AUTO_INCREMENT = 1; | |||
ALTER TABLE `symbols` AUTO_INCREMENT = 1; | |||
ALTER TABLE `symbol_locations` AUTO_INCREMENT = 1; | |||
END// | |||
DELIMITER ;""" | |||
], | |||
# 9 -> 10 | |||
[ | |||
"""ALTER TABLE `symbol_locations` | |||
MODIFY COLUMN `sloc_col` INT UNSIGNED DEFAULT NULL, | |||
MODIFY COLUMN `sloc_end_row` INT UNSIGNED DEFAULT NULL, | |||
MODIFY COLUMN `sloc_end_col` INT UNSIGNED DEFAULT NULL""" | |||
] | |||
] | |||
@@ -1,4 +1,4 @@ | |||
-- Schema version 10 | |||
CREATE DATABASE `bitshift` DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci; | |||
USE `bitshift`; | |||
@@ -6,7 +6,7 @@ USE `bitshift`; | |||
CREATE TABLE `version` ( | |||
`version` INT UNSIGNED NOT NULL | |||
) ENGINE=InnoDB; | |||
INSERT INTO `version` VALUES (8); | |||
INSERT INTO `version` VALUES (10); | |||
CREATE TABLE `origins` ( | |||
`origin_id` TINYINT UNSIGNED NOT NULL AUTO_INCREMENT, | |||
@@ -77,9 +77,9 @@ CREATE TABLE `symbol_locations` ( | |||
`sloc_symbol` BIGINT UNSIGNED NOT NULL, | |||
`sloc_type` TINYINT UNSIGNED NOT NULL, | |||
`sloc_row` INT UNSIGNED NOT NULL, | |||
`sloc_col` INT UNSIGNED NOT NULL, | |||
`sloc_end_row` INT UNSIGNED NOT NULL, | |||
`sloc_end_col` INT UNSIGNED NOT NULL, | |||
`sloc_col` INT UNSIGNED DEFAULT NULL, | |||
`sloc_end_row` INT UNSIGNED DEFAULT NULL, | |||
`sloc_end_col` INT UNSIGNED DEFAULT NULL, | |||
PRIMARY KEY (`sloc_id`), | |||
FOREIGN KEY (`sloc_symbol`) | |||
REFERENCES `symbols` (`symbol_id`) | |||
@@ -107,6 +107,19 @@ CREATE TABLE `cache_data` ( | |||
ON DELETE CASCADE ON UPDATE CASCADE | |||
) ENGINE=InnoDB; | |||
DELIMITER // | |||
CREATE PROCEDURE `empty_database`() | |||
BEGIN | |||
DELETE FROM `codelets`; | |||
DELETE FROM `code`; | |||
DELETE FROM `cache`; | |||
ALTER TABLE `codelets` AUTO_INCREMENT = 1; | |||
ALTER TABLE `authors` AUTO_INCREMENT = 1; | |||
ALTER TABLE `symbols` AUTO_INCREMENT = 1; | |||
ALTER TABLE `symbol_locations` AUTO_INCREMENT = 1; | |||
END// | |||
DELIMITER ; | |||
CREATE EVENT `flush_cache` | |||
ON SCHEDULE EVERY 1 HOUR | |||
DO | |||
@@ -8,7 +8,8 @@ def _load_langs(): | |||
filename = path.join(path.dirname(__file__), "languages.yml") | |||
with open(filename) as fp: | |||
data = yaml.load(fp)["languages"] | |||
langs = [it.keys()[0] if isinstance(it, dict) else it for it in data] | |||
langs = [(it.keys()[0] if isinstance(it, dict) else it).encode("utf8") | |||
for it in data] | |||
all_langs = {} | |||
for i, lang in enumerate(data): | |||
if isinstance(lang, dict): | |||
@@ -80,7 +80,7 @@ public class JavaParser extends Parser { | |||
int sl = this.root.getLineNumber(node.getStartPosition()); | |||
int sc = this.root.getColumnNumber(node.getStartPosition()); | |||
Integer el = -1; | |||
Integer el = sl; | |||
Integer ec = -1; | |||
if (statements.size() > 0) { | |||
@@ -110,7 +110,7 @@ public class JavaParser extends Parser { | |||
int sl = this.root.getLineNumber(node.getStartPosition()); | |||
int sc = this.root.getColumnNumber(node.getStartPosition()); | |||
data.put("coord", Symbols.createCoord(sl, sc, -1, -1)); | |||
data.put("coord", Symbols.createCoord(sl, sc, sl, -1)); | |||
data.put("name", name); | |||
this._cache.push(data); | |||
return true; | |||
@@ -140,7 +140,7 @@ public class JavaParser extends Parser { | |||
int sl = this.root.getLineNumber(node.getStartPosition()); | |||
int sc = this.root.getColumnNumber(node.getStartPosition()); | |||
data.put("coord", Symbols.createCoord(sl, sc, -1, -1)); | |||
data.put("coord", Symbols.createCoord(sl, sc, sl, -1)); | |||
this._cache.push(data); | |||
return true; | |||
} | |||
@@ -161,7 +161,7 @@ public class JavaParser extends Parser { | |||
int sl = this.root.getLineNumber(node.getStartPosition()); | |||
int sc = this.root.getColumnNumber(node.getStartPosition()); | |||
data.put("coord", Symbols.createCoord(sl, sc, -1, -1)); | |||
data.put("coord", Symbols.createCoord(sl, sc, sl, -1)); | |||
this._cache.push(data); | |||
return true; | |||
} | |||
@@ -0,0 +1,65 @@ | |||
td.linenos { background: rgba(65,131,196,0.05); padding-right: 10px; border-right: 1px solid #bbb; } | |||
span.lineno { background: rgba(65,131,196,0.05); padding: 0 5px 0 5px; } | |||
pre { line-height: 125% } | |||
.highlighttable { background-color: #fff; padding-left: 10px; width: inherit; height: inherit; } | |||
.hll { display: block } | |||
.c { color: #999988; font-style: italic } /* Comment */ | |||
.err { color: #a61717; background-color: #e3d2d2 } /* Error */ | |||
.k { color: #000000; font-weight: bold } /* Keyword */ | |||
.o { color: #000000; font-weight: bold } /* Operator */ | |||
.cm { color: #999988; font-style: italic } /* Comment.Multiline */ | |||
.cp { color: #999999; font-weight: bold; font-style: italic } /* Comment.Preproc */ | |||
.c1 { color: #999988; font-style: italic } /* Comment.Single */ | |||
.cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */ | |||
.gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ | |||
.ge { color: #000000; font-style: italic } /* Generic.Emph */ | |||
.gr { color: #aa0000 } /* Generic.Error */ | |||
.gh { color: #999999 } /* Generic.Heading */ | |||
.gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ | |||
.go { color: #888888 } /* Generic.Output */ | |||
.gp { color: #555555 } /* Generic.Prompt */ | |||
.gs { font-weight: bold } /* Generic.Strong */ | |||
.gu { color: #aaaaaa } /* Generic.Subheading */ | |||
.gt { color: #aa0000 } /* Generic.Traceback */ | |||
.kc { color: #000000; font-weight: bold } /* Keyword.Constant */ | |||
.kd { color: #000000; font-weight: bold } /* Keyword.Declaration */ | |||
.kn { color: #000000; font-weight: bold } /* Keyword.Namespace */ | |||
.kp { color: #000000; font-weight: bold } /* Keyword.Pseudo */ | |||
.kr { color: #000000; font-weight: bold } /* Keyword.Reserved */ | |||
.kt { color: #445588; font-weight: bold } /* Keyword.Type */ | |||
.m { color: #009999 } /* Literal.Number */ | |||
.s { color: #d01040 } /* Literal.String */ | |||
.na { color: #008080 } /* Name.Attribute */ | |||
.nb { color: #0086B3 } /* Name.Builtin */ | |||
.nc { color: #445588; font-weight: bold } /* Name.Class */ | |||
.no { color: #008080 } /* Name.Constant */ | |||
.nd { color: #3c5d5d; font-weight: bold } /* Name.Decorator */ | |||
.ni { color: #800080 } /* Name.Entity */ | |||
.ne { color: #990000; font-weight: bold } /* Name.Exception */ | |||
.nf { color: #990000; font-weight: bold } /* Name.Function */ | |||
.nl { color: #990000; font-weight: bold } /* Name.Label */ | |||
.nn { color: #555555 } /* Name.Namespace */ | |||
.nt { color: #000080 } /* Name.Tag */ | |||
.nv { color: #008080 } /* Name.Variable */ | |||
.ow { color: #000000; font-weight: bold } /* Operator.Word */ | |||
.w { color: #bbbbbb } /* Text.Whitespace */ | |||
.mf { color: #009999 } /* Literal.Number.Float */ | |||
.mh { color: #009999 } /* Literal.Number.Hex */ | |||
.mi { color: #009999 } /* Literal.Number.Integer */ | |||
.mo { color: #009999 } /* Literal.Number.Oct */ | |||
.sb { color: #d01040 } /* Literal.String.Backtick */ | |||
.sc { color: #d01040 } /* Literal.String.Char */ | |||
.sd { color: #d01040 } /* Literal.String.Doc */ | |||
.s2 { color: #d01040 } /* Literal.String.Double */ | |||
.se { color: #d01040 } /* Literal.String.Escape */ | |||
.sh { color: #d01040 } /* Literal.String.Heredoc */ | |||
.si { color: #d01040 } /* Literal.String.Interpol */ | |||
.sx { color: #d01040 } /* Literal.String.Other */ | |||
.sr { color: #009926 } /* Literal.String.Regex */ | |||
.s1 { color: #d01040 } /* Literal.String.Single */ | |||
.ss { color: #990073 } /* Literal.String.Symbol */ | |||
.bp { color: #999999 } /* Name.Builtin.Pseudo */ | |||
.vc { color: #008080 } /* Name.Variable.Class */ | |||
.vg { color: #008080 } /* Name.Variable.Global */ | |||
.vi { color: #008080 } /* Name.Variable.Instance */ | |||
.il { color: #009999 } /* Literal.Number.Integer.Long */ |
@@ -0,0 +1,64 @@ | |||
td.linenos { background-color: #f0f0f0; padding-right: 10px; } | |||
span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; } | |||
pre { line-height: 125% } | |||
.highlighttable { background-color: #49483e; width: inherit; height: inherit; } | |||
.hll { display: block } | |||
{ background: #272822; color: #f8f8f2 } | |||
.c { color: #75715e } /* Comment */ | |||
.err { color: #960050; background-color: #1e0010 } /* Error */ | |||
.k { color: #66d9ef } /* Keyword */ | |||
.l { color: #ae81ff } /* Literal */ | |||
.n { color: #f8f8f2 } /* Name */ | |||
.o { color: #f92672 } /* Operator */ | |||
.p { color: #f8f8f2 } /* Punctuation */ | |||
.cm { color: #75715e } /* Comment.Multiline */ | |||
.cp { color: #75715e } /* Comment.Preproc */ | |||
.c1 { color: #75715e } /* Comment.Single */ | |||
.cs { color: #75715e } /* Comment.Special */ | |||
.ge { font-style: italic } /* Generic.Emph */ | |||
.gs { font-weight: bold } /* Generic.Strong */ | |||
.kc { color: #66d9ef } /* Keyword.Constant */ | |||
.kd { color: #66d9ef } /* Keyword.Declaration */ | |||
.kn { color: #f92672 } /* Keyword.Namespace */ | |||
.kp { color: #66d9ef } /* Keyword.Pseudo */ | |||
.kr { color: #66d9ef } /* Keyword.Reserved */ | |||
.kt { color: #66d9ef } /* Keyword.Type */ | |||
.ld { color: #e6db74 } /* Literal.Date */ | |||
.m { color: #ae81ff } /* Literal.Number */ | |||
.s { color: #e6db74 } /* Literal.String */ | |||
.na { color: #a6e22e } /* Name.Attribute */ | |||
.nb { color: #f8f8f2 } /* Name.Builtin */ | |||
.nc { color: #a6e22e } /* Name.Class */ | |||
.no { color: #66d9ef } /* Name.Constant */ | |||
.nd { color: #a6e22e } /* Name.Decorator */ | |||
.ni { color: #f8f8f2 } /* Name.Entity */ | |||
.ne { color: #a6e22e } /* Name.Exception */ | |||
.nf { color: #a6e22e } /* Name.Function */ | |||
.nl { color: #f8f8f2 } /* Name.Label */ | |||
.nn { color: #f8f8f2 } /* Name.Namespace */ | |||
.nx { color: #a6e22e } /* Name.Other */ | |||
.py { color: #f8f8f2 } /* Name.Property */ | |||
.nt { color: #f92672 } /* Name.Tag */ | |||
.nv { color: #f8f8f2 } /* Name.Variable */ | |||
.ow { color: #f92672 } /* Operator.Word */ | |||
.w { color: #f8f8f2 } /* Text.Whitespace */ | |||
.mf { color: #ae81ff } /* Literal.Number.Float */ | |||
.mh { color: #ae81ff } /* Literal.Number.Hex */ | |||
.mi { color: #ae81ff } /* Literal.Number.Integer */ | |||
.mo { color: #ae81ff } /* Literal.Number.Oct */ | |||
.sb { color: #e6db74 } /* Literal.String.Backtick */ | |||
.sc { color: #e6db74 } /* Literal.String.Char */ | |||
.sd { color: #e6db74 } /* Literal.String.Doc */ | |||
.s2 { color: #e6db74 } /* Literal.String.Double */ | |||
.se { color: #ae81ff } /* Literal.String.Escape */ | |||
.sh { color: #e6db74 } /* Literal.String.Heredoc */ | |||
.si { color: #e6db74 } /* Literal.String.Interpol */ | |||
.sx { color: #e6db74 } /* Literal.String.Other */ | |||
.sr { color: #e6db74 } /* Literal.String.Regex */ | |||
.s1 { color: #e6db74 } /* Literal.String.Single */ | |||
.ss { color: #e6db74 } /* Literal.String.Symbol */ | |||
.bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */ | |||
.vc { color: #f8f8f2 } /* Name.Variable.Class */ | |||
.vg { color: #f8f8f2 } /* Name.Variable.Global */ | |||
.vi { color: #f8f8f2 } /* Name.Variable.Instance */ | |||
.il { color: #ae81ff } /* Literal.Number.Integer.Long */ |
@@ -37,6 +37,8 @@ var searchGroups = $("div#search-groups"); | |||
searchGroups.append( | |||
searchGroup.append(createSearchGroupInput("language"))); | |||
$("div#sidebar input[type=checkbox]#language").prop("checked", true); | |||
searchGroups[0].scrollTop = searchGroups[0].scrollHeight; | |||
}); | |||
// Remove the currently selected group if it's not the only one, and mark | |||
@@ -67,7 +69,7 @@ var searchGroups = $("div#search-groups"); | |||
}) | |||
}); | |||
// Add an input field to the currently selected search group. | |||
// Toggle the presence of an input field. | |||
$("div#sidebar input[type=checkbox]").click(function(){ | |||
var fieldId = $(this).prop("id"); | |||
if($(this).is(":checked")){ | |||
@@ -76,8 +78,13 @@ var searchGroups = $("div#search-groups"); | |||
if(fieldId.slice(0, 4) == "date") | |||
$(".search-group#selected ." + fieldId).datepicker(); | |||
} | |||
else | |||
$("div.search-group#selected #" + fieldId).remove() | |||
else { | |||
if($(".search-group#selected").children("div").length > 1) | |||
$(".search-group#selected #" + fieldId).remove() | |||
else | |||
$(this).prop("checked", true); | |||
} | |||
searchGroups[0].scrollTop = searchGroups[0].scrollHeight; | |||
}); | |||
var previousAdvancedQuery = ""; | |||
@@ -125,7 +132,8 @@ function assembleQuery(){ | |||
groupQuery.push(genFieldQueryString( | |||
inputFields[field], regexCheckbox[field].checked)); | |||
groupQueries.push(groupQuery.join(" AND ")); | |||
if(groupQuery.length > 0) | |||
groupQueries.push(groupQuery.join(" AND ")); | |||
} | |||
return groupQueries.join(" OR "); | |||
@@ -140,8 +148,5 @@ function assembleQuery(){ | |||
function genFieldQueryString(field, hasRegex){ | |||
var terms = field.value.replace(/\\/g, "\\\\").replace(/\"/g, "\\\""); | |||
var query = field.getAttribute("name") + ":" + (hasRegex?"re:":"") + terms; | |||
if(field.value.indexOf('"') >= 0){ | |||
return '"' + query + '"'; | |||
} | |||
return query; | |||
return '"' + query + '"'; | |||
} |
@@ -5,34 +5,145 @@ | |||
var advancedSearchDiv = $("div#advanced-search"); | |||
var advancedSearchButton = $("button#advanced-search"); | |||
advancedSearchButton.click(function(){ | |||
var searchField = $("div#search-field"); | |||
if(!advancedSearchDiv.hasClass("visible")){ | |||
searchField.addClass("partly-visible"); | |||
advancedSearchDiv.fadeIn(500).addClass("visible"); | |||
advancedSearchButton.addClass("clicked"); | |||
} | |||
else { | |||
advancedSearchDiv.fadeOut(300).removeClass("visible"); | |||
advancedSearchButton.removeClass("clicked"); | |||
if($("div#results .result").length == 0) | |||
searchField.removeClass("partly-visible"); | |||
FINISH_TYPING_INTERVAL = 650; | |||
var searchBar = $("form#search-bar input[type='text']")[0]; | |||
var resultsDiv = $("div#results")[0]; | |||
var typingTimer, scrollTimer, lastValue; | |||
var searchResultsPage = 1; | |||
/* | |||
* Set all page callbacks. | |||
*/ | |||
(function setHomePageCallbabacks(){ | |||
var results = $('#results').get(0); | |||
// Enable infinite scrolling down the results page. | |||
$(window).scroll(function(){ | |||
if($(window).scrollTop() + $(window).height() == $(document).height() && | |||
resultsDiv.querySelectorAll(".result").length > 0) | |||
loadMoreResults(); | |||
clearTimeout(scrollTimer); | |||
if (!results.classList.contains('disable-hover')) | |||
results.classList.add('disable-hover') | |||
scrollTimer = setTimeout(function(){ | |||
if (results.classList.contains('disable-hover')) | |||
results.classList.remove('disable-hover'); | |||
}, 200); | |||
}); | |||
// Toggle the advanced-search form's visibility. | |||
advancedSearchButton.click(function(){ | |||
var searchField = $("div#search-field"); | |||
if(!advancedSearchDiv.hasClass("visible")){ | |||
searchField.addClass("partly-visible"); | |||
advancedSearchDiv.fadeIn(500).addClass("visible"); | |||
advancedSearchButton.addClass("clicked"); | |||
} | |||
else { | |||
advancedSearchDiv.fadeOut(300).removeClass("visible"); | |||
advancedSearchButton.removeClass("clicked"); | |||
if($("div#results .result").length == 0) | |||
searchField.removeClass("partly-visible"); | |||
} | |||
}); | |||
// Enable capturing the `enter` key. | |||
$("form#search-bar").submit(function(event){ | |||
event.preventDefault(); | |||
return false; | |||
}); | |||
searchBar.onkeyup = typingTimer; | |||
}()); | |||
/* | |||
* Set keyboard shortcut mappings. | |||
*/ | |||
(function resultsHotkeys(){ | |||
/* | |||
* If the currently viewed result is not the first, scroll to the previous | |||
* result. | |||
*/ | |||
var previousResult = function(){ | |||
var currResult = $(".display-all"); | |||
if(currResult.length) { | |||
currResult.removeClass("display-all"); | |||
currResult = currResult.closest(".result").prev(".result"); | |||
} else { | |||
currResult = $(document.querySelectorAll(".result")[0]); | |||
} | |||
currResult.addClass("display-all"); | |||
currResult.each(function(){ | |||
$('html,body').stop().animate({ | |||
scrollTop: $(this).offset().top - ( | |||
$(window).height() - $(this).outerHeight(true)) / 2 | |||
}, 140); | |||
}); | |||
}; | |||
/* | |||
* If the currently viewed result is not the last, scroll to the next | |||
* result. | |||
*/ | |||
var nextResult = function(){ | |||
var currResult = $(".display-all"); | |||
if(currResult.length) { | |||
currResult.removeClass("display-all"); | |||
currResult = currResult.closest(".result").next(".result"); | |||
} else { | |||
currResult = $(document.querySelectorAll(".result")[0]); | |||
} | |||
currResult.addClass('display-all'); | |||
currResult.each(function(){ | |||
$('html,body').stop().animate({ | |||
scrollTop: $(this).offset().top - ( | |||
$(window).height() - $(this).outerHeight(true)) / 2 | |||
}, 140); | |||
}); | |||
}; | |||
var displayHotkeyHelp = function(){ | |||
var help = $("div#hotkey-help"); | |||
console.log("H"); | |||
if(help.hasClass("hidden")) | |||
help.fadeIn(420); | |||
else | |||
help.fadeOut(420); | |||
$("div#body").toggleClass("faded"); | |||
help.toggleClass("hidden"); | |||
} | |||
}); | |||
FINISH_TYPING_INTERVAL = 650; | |||
searchBar = $("form#search-bar input[type='text']")[0]; | |||
resultsDiv = $("div#results")[0]; | |||
var hotkeyActions = { | |||
"k" : previousResult, | |||
"j" : nextResult, | |||
"h" : previousSymbolMatch, | |||
"l" : nextSymbolMatch, | |||
"?" : displayHotkeyHelp | |||
}; | |||
$(window).keypress(function(key){ | |||
for(var hotkey in hotkeyActions){ | |||
var keyChar = String.fromCharCode(key.keyCode); | |||
if(keyChar == hotkey && | |||
!($(key.target).is("textarea") || $(key.target).is("input"))) | |||
hotkeyActions[keyChar](); | |||
} | |||
}); | |||
}()); | |||
var typingTimer, lastValue; | |||
//Obtained by parsing python file with pygments | |||
var codeExample = '<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1\n 2\n 3\n 4\n 5\n 6\n 7\n 8\n 9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26\n27\n28\n29\n30\n31\n32\n33\n34\n35\n36\n37\n38\n39\n40</pre></div></td><td class="code"><div class="hll"><pre><span class="sd">"""</span>\n<span class="sd">Module to contain all the project's Flask server plumbing.</span>\n<span class="sd">"""</span>\n\n<span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">Flask</span>\n<span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">render_template</span><span class="p">,</span> <span class="n">session</span>\n\n<span class="kn">from</span> <span class="nn">bitshift</span> <span class="kn">import</span> <span class="n">assets</span>\n<span class="c"># from bitshift.database import Database</span>\n<span class="c"># from bitshift.query import parse_query</span>\n\n<span class="n">app</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span>\n<span class="n">app</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">from_object</span><span class="p">(</span><span class="s">"bitshift.config"</span><span class="p">)</span>\n\n<span class="n">app_env</span> <span class="o">=</span> <span class="n">app</span><span class="o">.</span><span class="n">jinja_env</span>\n<span class="n">app_env</span><span class="o">.</span><span class="n">line_statement_prefix</span> <span class="o">=</span> <span class="s">"="</span>\n<span class="n">app_env</span><span class="o">.</span><span class="n">globals</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">assets</span><span class="o">=</span><span class="n">assets</span><span class="p">)</span>\n\n<span class="c"># database = Database()</span>\n\n<span class="nd">@app.route</span><span class="p">(</span><span class="s">"/"</span><span class="p">)</span>\n<span class="k">def</span> <span class="nf">index</span><span class="p">():</span>\n <span class="k">return</span> <span class="n">render_template</span><span class="p">(</span><span class="s">"index.html"</span><span class="p">)</span>\n\n<span class="nd">@app.route</span><span class="p">(</span><span class="s">"/search/<query>"</span><span class="p">)</span>\n<span class="k">def</span> <span class="nf">search</span><span class="p">(</span><span class="n">query</span><span class="p">):</span>\n <span class="c"># tree = parse_query(query)</span>\n <span class="c"># database.search(tree)</span>\n <span class="k">pass</span>\n\n<span class="nd">@app.route</span><span class="p">(</span><span class="s">"/about"</span><span class="p">)</span>\n<span class="k">def</span> <span class="nf">about</span><span class="p">():</span>\n <span class="k">return</span> <span class="n">render_template</span><span class="p">(</span><span class="s">"about.html"</span><span class="p">)</span>\n\n<span class="nd">@app.route</span><span class="p">(</span><span class="s">"/developers"</span><span class="p">)</span>\n<span class="k">def</span> <span class="nf">developers</span><span class="p">():</span>\n <span class="k">return</span> <span class="n">render_template</span><span class="p">(</span><span class="s">"developers.html"</span><span class="p">)</span>\n\n<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">"__main__"</span><span class="p">:</span>\n <span class="n">app</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">debug</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>\n</pre></div>\n</td></tr></table>' | |||
var codeExample = '<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1\n 2\n 3\n 4\n 5\n 6\n 7\n 8\n 9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26\n27\n28\n29\n30\n31\n32\n33\n34\n35\n36\n37\n38\n39\n40</pre></div></td><td class="code"><div class="highlight"><pre><span class="sd">"""</span>\n<span class="sd">Module to contain all the project's Flask server plumbing.</span>\n<span class="sd">"""</span>\n\n<span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">Flask</span>\n<span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">render_template</span><span class="p">,</span> <span class="n">session</span>\n\n<span class="kn">from</span> <span class="nn">bitshift</span> <span class="kn">import</span> <span class="n">assets</span>\n<span class="c"># from bitshift.database import Database</span>\n<span class="c"># from bitshift.query import parse_query</span>\n\n<span class="hll"><span class="n">app</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span>\n</span><span class="hll"><span class="n">app</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">from_object</span><span class="p">(</span><span class="s">"bitshift.config"</span><span class="p">)</span>\n</span>\n<span class="hll"><span class="n">app_env</span> <span class="o">=</span> <span class="n">app</span><span class="o">.</span><span class="n">jinja_env</span>\n</span><span class="hll"><span class="n">app_env</span><span class="o">.</span><span class="n">line_statement_prefix</span> <span class="o">=</span> <span class="s">"="</span>\n</span><span class="hll"><span class="n">app_env</span><span class="o">.</span><span class="n">globals</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">assets</span><span class="o">=</span><span class="n">assets</span><span class="p">)</span>\n</span>\n<span class="c"># database = Database()</span>\n\n<span class="hll"><span class="nd">@app.route</span><span class="p">(</span><span class="s">"/"</span><span class="p">)</span>\n</span><span class="k">def</span> <span class="nf">index</span><span class="p">():</span>\n <span class="k">return</span> <span class="n">render_template</span><span class="p">(</span><span class="s">"index.html"</span><span class="p">)</span>\n\n<span class="hll"><span class="nd">@app.route</span><span class="p">(</span><span class="s">"/search/<query>"</span><span class="p">)</span>\n</span><span class="k">def</span> <span class="nf">search</span><span class="p">(</span><span class="n">query</span><span class="p">):</span>\n <span class="c"># tree = parse_query(query)</span>\n <span class="c"># database.search(tree)</span>\n <span class="k">pass</span>\n\n<span class="hll"><span class="nd">@app.route</span><span class="p">(</span><span class="s">"/about"</span><span class="p">)</span>\n</span><span class="k">def</span> <span class="nf">about</span><span class="p">():</span>\n <span class="k">return</span> <span class="n">render_template</span><span class="p">(</span><span class="s">"about.html"</span><span class="p">)</span>\n\n<span class="hll"><span class="nd">@app.route</span><span class="p">(</span><span class="s">"/developers"</span><span class="p">)</span>\n</span><span class="k">def</span> <span class="nf">developers</span><span class="p">():</span>\n <span class="k">return</span> <span class="n">render_template</span><span class="p">(</span><span class="s">"developers.html"</span><span class="p">)</span>\n\n<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">"__main__"</span><span class="p">:</span>\n<span class="hll"> <span class="n">app</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">debug</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>\n</span></pre></div>\n</td></tr></table>' | |||
searchBar.onkeyup = typingTimer; | |||
var testCodelet = { | |||
'url': 'https://github.com/earwig/bitshift/blob/develop/app.py', | |||
'filename': 'app.py', | |||
'language': 'Python', | |||
'language': 'python', | |||
'date_created': 'May 10, 2014', | |||
'date_modified': '2 days ago', | |||
'origin': ['GitHub', 'https://github.com', ''], | |||
@@ -43,17 +154,12 @@ var testCodelet = { | |||
// Enable infinite scrolling down the results page. | |||
$(window).scroll(function() { | |||
var searchField = $("div#search-field"); | |||
if($(window).scrollTop() + $(window).height() == $(document).height() && searchField.hasClass('partly-visible')){ | |||
if($(window).scrollTop() + $(window).height() == $(document).height() && | |||
searchField.hasClass('partly-visible')){ | |||
loadMoreResults(); | |||
} | |||
}); | |||
// Enable capturing the `enter` key. | |||
$("form#search-bar").submit(function(event){ | |||
event.preventDefault(); | |||
return false; | |||
}); | |||
/* | |||
* Clear the existing timer and set a new one the the user types text into the | |||
* search bar. | |||
@@ -109,6 +215,7 @@ function clearResults(){ | |||
* with its response. | |||
*/ | |||
function populateResults(){ | |||
searchResultsPage = 1; | |||
var results = queryServer(); | |||
for(var result = 0; result < results.length; result++){ | |||
@@ -135,74 +242,108 @@ function createResult(codelet) { | |||
row = document.createElement("tr"); | |||
//Level 2 | |||
var displayInfo = document.createElement("div"), | |||
sidebar = document.createElement("td"), | |||
codeElt = document.createElement("td"), | |||
displayButton = document.createElement("td"), | |||
hiddenInfoContainer = document.createElement("td"), | |||
hiddenInfo = document.createElement("div"); | |||
hiddenInfo = document.createElement("div"), | |||
cycle = document.createElement("div"); | |||
//Level 3 | |||
var title = document.createElement("span"), | |||
site = document.createElement("span"), | |||
dateModified = document.createElement("span"), | |||
language = document.createElement("span"), | |||
dateCreated = document.createElement("span"), | |||
nextMatch = document.createElement("a"), | |||
prevMatch = document.createElement("a"), | |||
dateModified = document.createElement("div"), | |||
language = document.createElement("div"), | |||
dateCreated = document.createElement("div"), | |||
authors = document.createElement("div"); | |||
//Classes and ID's | |||
newDiv.classList.add('result'); | |||
displayInfo.id = 'display-info'; | |||
sidebar.id = 'sidebar'; | |||
codeElt.id = 'code'; | |||
displayButton.id = 'display-button'; | |||
hiddenInfo.id = 'hidden-info'; | |||
cycle.id = 'cycle-matches' | |||
title.id = 'title'; | |||
site.id = 'site'; | |||
nextMatch.id = 'next-match'; | |||
nextMatch.href = '#'; | |||
prevMatch.id = 'prev-match'; | |||
prevMatch.href = '#'; | |||
dateModified.id = 'date-modified'; | |||
language.id = 'language'; | |||
dateCreated.id = 'date-created'; | |||
authors.id = 'authors'; | |||
//Add the bulk of the html | |||
title.innerHTML = 'File <a href="' + codelet.url + '">' | |||
title.innerHTML = ' » <a href="' + codelet.url + '">' | |||
+ codelet.filename + '</a>'; | |||
site.innerHTML = 'on <a href="' + codelet.origin[1] + '">' + codelet.origin[0] +'</a>'; | |||
dateModified.innerHTML = 'Last modified ' + codelet.date_modified; | |||
site.innerHTML = '<a href="' + codelet.origin[1] + '">' + codelet.origin[0] +'</a>'; | |||
nextMatch.innerHTML = 'next match'; | |||
prevMatch.innerHTML = 'prev match'; | |||
language.innerHTML = 'Language: <span>' + codelet.language + '</span>'; | |||
dateModified.innerHTML = 'Last modified: <span>' + codelet.date_modified + '</span>'; | |||
// Needs to be changed from int to string on the server | |||
language.innerHTML = codelet.language; | |||
dateCreated.innerHTML = 'Created ' + codelet.date_created; | |||
authors.innerHTML = 'Authors: '; | |||
$.each(codelet.authors, function(i, a) { | |||
authors.innerHTML += '<a href=#>' + a + ' </a>'; | |||
dateCreated.innerHTML = 'Created: <span>' + codelet.date_created + '</span>'; | |||
var authorsHtml = 'Authors: <span>'; | |||
codelet.authors.forEach(function(a, i) { | |||
if (i == codelet.authors.length - 1) | |||
authorsHtml += '<a href=#>' + a + ' </a>'; | |||
else | |||
authorsHtml += '<a href=#>' + a + ' </a>, '; | |||
}); | |||
authors.innerHTML = authorsHtml; | |||
sidebar.innerHTML = ''; | |||
// Needs to be processed on the server | |||
codeElt.innerHTML = '<div id=tablecontainer>' + codelet.html_code + '</div>'; | |||
//Event binding | |||
$(displayButton).click(function(e) { | |||
$(hiddenInfo).toggleClass('visible'); | |||
$(this).toggleClass('active'); | |||
$(newDiv).on('mousemove', function(e) { | |||
var holdCondition = $('.disable-hover'); | |||
if(holdCondition.length == 0) { | |||
$(this).siblings().removeClass('display-all'); | |||
$(this).addClass('display-all'); | |||
} | |||
}); | |||
$(newDiv).on('mouseleave', function(e) { | |||
var holdCondition = $('.disable-hover'); | |||
if(holdCondition.length == 0) | |||
$(this).removeClass('display-all'); | |||
}); | |||
$(nextMatch).click(function(e) { | |||
e.stopPropagation(); | |||
e.preventDefault(); | |||
nextSymbolMatch(); | |||
}); | |||
$(prevMatch).click(function(e) { | |||
e.stopPropagation(); | |||
e.preventDefault(); | |||
previousSymbolMatch(); | |||
}); | |||
//Finish and append elements to parent elements | |||
hiddenInfo.appendChild(dateCreated); | |||
hiddenInfo.appendChild(dateModified); | |||
hiddenInfo.appendChild(authors); | |||
hiddenInfo.appendChild(language); | |||
hiddenInfo.appendChild(authors); | |||
hiddenInfoContainer.appendChild(hiddenInfo); | |||
row.appendChild(sidebar); | |||
row.appendChild(codeElt); | |||
row.appendChild(hiddenInfoContainer); | |||
row.appendChild(displayButton); | |||
table.appendChild(row); | |||
displayInfo.appendChild(title); | |||
displayInfo.appendChild(site); | |||
displayInfo.appendChild(title); | |||
cycle.appendChild(prevMatch); | |||
cycle.appendChild(nextMatch); | |||
newDiv.appendChild(displayInfo); | |||
newDiv.appendChild(table); | |||
@@ -210,6 +351,52 @@ function createResult(codelet) { | |||
return newDiv; | |||
} | |||
function previousSymbolMatch() { | |||
var currResult = $(".display-all"), | |||
currMatch = currResult.find(".hll.current"), | |||
matches = currResult.find(".hll"), | |||
scrollDiv = currResult.find("#tablecontainer"); | |||
if (currMatch.length == 0) | |||
currMatch = matches[0]; | |||
else | |||
currMatch.removeClass('current'); | |||
var index = matches.index(currMatch.get(0)) - 1; | |||
index = index <= 0 ? matches.length - 1 : index; | |||
var newMatch = $(matches[index]); | |||
scrollDiv.scrollTop(scrollDiv.scrollTop() | |||
- scrollDiv.height() / 2 | |||
+ newMatch.position().top + newMatch.height() / 2); | |||
newMatch.effect("highlight", {color: '#FFF'}, 750) | |||
newMatch.addClass('current'); | |||
}; | |||
function nextSymbolMatch() { | |||
var currResult = $(".display-all"), | |||
currMatch = currResult.find(".hll.current"), | |||
matches = currResult.find(".hll"), | |||
scrollDiv = currResult.find("#tablecontainer"); | |||
if (currMatch.length == 0) | |||
currMatch = $(matches[0]); | |||
else | |||
currMatch.removeClass("current"); | |||
var index = matches.index(currMatch.get(0)) + 1; | |||
index = index >= matches.length ? 0 : index; | |||
var newMatch = $(matches[index]); | |||
scrollDiv.scrollTop(scrollDiv.scrollTop() | |||
- scrollDiv.height() / 2 | |||
+ newMatch.position().top + newMatch.height() / 2); | |||
newMatch.effect("highlight", {color: "#FFF"}, 750) | |||
newMatch.addClass("current"); | |||
}; | |||
/* | |||
* AJAX the current query string to the server, and return its response. | |||
* | |||
@@ -217,10 +404,23 @@ function createResult(codelet) { | |||
* elements, to fill `div#results`. | |||
*/ | |||
function queryServer(){ | |||
var resultDivs = [] | |||
var queryUrl = document.URL + "search.json?" + $.param({ | |||
"q" : searchBar.value, | |||
"p" : searchResultsPage++ | |||
}); | |||
var resultDivs = []; | |||
$.getJSON(queryUrl, function(result){ | |||
if("error" in result) | |||
insertErrorMessage(result["error"]); | |||
else | |||
for(var codelet = 0; codelet < result["results"].length; codelet++) | |||
resultDivs.push(result["results"][codelet]); | |||
}); | |||
for(var result = 0; result < 20; result++){ | |||
var newDiv = createResult(testCodelet); | |||
resultDivs.push(newDiv); | |||
resultDivs.push(newDiv) | |||
} | |||
return resultDivs; | |||
@@ -230,7 +430,7 @@ function queryServer(){ | |||
* Adds more results to `div#results`. | |||
*/ | |||
function loadMoreResults(){ | |||
results = queryServer(); | |||
var results = queryServer(); | |||
for(var result = 0; result < results.length; result++){ | |||
var newDiv = results[result]; | |||
resultsDiv.appendChild(newDiv); | |||
@@ -243,3 +443,16 @@ function loadMoreResults(){ | |||
result * 20); | |||
} | |||
} | |||
/* | |||
* Displays a warning message in the UI. | |||
* | |||
* @param msg (str) The message string. | |||
*/ | |||
function insertErrorMessage(msg){ | |||
var error = $("<div id='error'><span>Error: </span></div>"); | |||
error.append(msg); | |||
resultsDiv.appendChild(error[0]); | |||
} | |||
// loadMoreResults(); |
@@ -10,6 +10,11 @@ | |||
-o-#{$property}: $value | |||
#{$property}: $value | |||
// Add portable opacity style. | |||
@mixin opaque($opacity) | |||
@include vendor(opacity, $opacity) | |||
filter: alpha(opacity=$opacity) | |||
.t1 | |||
@include vendor(transition, all 0.1s ease-out) | |||
@@ -6,9 +6,8 @@ | |||
@import variables | |||
$minSearchFieldsWidth: 490px | |||
$resultWidth: 830px | |||
$sidebarWidth: 30px | |||
$codeWidth: 500px | |||
$resultWidth: 1000px | |||
$codeWidth: 650px | |||
$hiddenInfoWidth: 250px | |||
.ui-datepicker | |||
@@ -23,6 +22,54 @@ $hiddenInfoWidth: 250px | |||
>li.ui-menu-item a.ui-state-focus | |||
@include vendor(transition, background-color 0.3s ease-out) | |||
div#body | |||
@extend .t3 | |||
&.faded | |||
@include opaque(0.8) | |||
div#hotkey-help | |||
$width: 40% | |||
background-color: white | |||
border: 1px solid $baseColor3 | |||
left: 50% - $width / 2 | |||
min-width: 400px | |||
padding: 35px | |||
position: fixed | |||
top: 30% | |||
width: $width | |||
z-index: 200 | |||
&.hidden | |||
display: none | |||
div | |||
border-bottom: 1px solid $baseColor2 | |||
color: $baseColor1 | |||
font-size: 130% | |||
padding-bottom: 8px | |||
text-align: center | |||
ul | |||
list-style: none | |||
margin-left: auto | |||
margin-right: auto | |||
position: relative | |||
width: 300px | |||
li | |||
margin-bottom: 4px | |||
span.hotkey | |||
color: $baseColor1 | |||
font-family: monospace | |||
font-size: 130% | |||
font-weight: bold | |||
span.seperator | |||
color: $baseColor2 | |||
div#search-field | |||
@extend .t2 | |||
@@ -34,6 +81,7 @@ div#search-field | |||
max-height: 100px | |||
right: 0 | |||
position: absolute | |||
z-index: 2 | |||
top: 0 | |||
width: 40% | |||
@@ -103,7 +151,6 @@ div#search-field | |||
&.partly-visible | |||
margin-top: 0% | |||
padding-bottom: 3% | |||
position: absolute | |||
width: 100% | |||
@@ -121,6 +168,11 @@ div#search-field | |||
margin-right: auto | |||
width: 60% | |||
input:hover | |||
@extend .t3 | |||
border: 1px solid $baseColor1 | |||
div#advanced-search | |||
background-color: white | |||
border: 1px solid $baseColor3 | |||
@@ -237,7 +289,7 @@ div#advanced-search | |||
#search-groups | |||
margin-top: 1% | |||
max-height: 93% | |||
max-height: 87% | |||
overflow-y: auto | |||
width: 75% | |||
@@ -286,112 +338,116 @@ div#results | |||
margin-right: auto | |||
width: 80% | |||
/* TODO: | |||
1) Sidebar | |||
- Add way to cycle through hits in the code. | |||
2) Hidden info | |||
- Add links for authors. | |||
- Remove language field. | |||
3) Header | |||
- Add an icon for the website. | |||
- Add language tag. | |||
4) Code body | |||
- Add highlighting.*/ | |||
div.result | |||
width: $resultWidth | |||
height: 200px | |||
margin-top: 2% | |||
margin-bottom: 6% | |||
#display-info | |||
font-size: 1.2em | |||
a | |||
text-decoration: none | |||
&:hover | |||
color: orange | |||
#title | |||
margin-right: 10px | |||
#site | |||
text-transform: capitalize | |||
a | |||
text-decoration: none | |||
&:hover | |||
color: orange | |||
div#error | |||
font-size: 170% | |||
margin-top: 22% | |||
text-align: center | |||
span | |||
color: $baseColor1 | |||
font-size: 150% | |||
&.disable-hover | |||
pointer-events: none | |||
div.result | |||
@extend .t3 | |||
width: $resultWidth | |||
height: 200px | |||
margin-bottom: 100% | |||
pointer-events: auto | |||
table | |||
border-collapse: collapse | |||
height: inherit | |||
tr | |||
@extend .t3 | |||
@include opaque(0.8) | |||
table | |||
border-collapse: collapse | |||
border: 1px solid $baseColor3 | |||
height: inherit | |||
tr | |||
height: inherit | |||
#sidebar | |||
width: $sidebarWidth | |||
background-color: #eee | |||
border-right: 1px solid $baseColor3 | |||
height: inherit | |||
#code | |||
width: $codeWidth | |||
height: inherit | |||
border-right: 1px solid $baseColor3 | |||
#tablecontainer | |||
overflow: scroll | |||
width: 100% | |||
height: inherit | |||
background-color: #49483e | |||
table | |||
table-layout:fixed | |||
border-collapse: collapse | |||
border: none | |||
font-family: monospace | |||
#display-button | |||
width: 25px | |||
background: url(http://icons.iconarchive.com/icons/visualpharm/icons8-metro-style/512/Image-Edition-Tools-Arrow-icon.png) | |||
background-size: 25px 25px | |||
background-repeat: no-repeat | |||
background-position: center | |||
&.cascade | |||
@extend .t1 | |||
margin-bottom: 15% | |||
&:hover | |||
background-color: #eee | |||
&.display-all table tr | |||
@include opaque(1.0) | |||
&.active | |||
@include vendor(transform, rotateY(180deg)) | |||
div#display-info | |||
font-size: 1.3em | |||
padding: 5px 0px 5px 5px | |||
width: 100% | |||
#hidden-info | |||
width: $hiddenInfoWidth | |||
margin-left: -$hiddenInfoWidth | |||
height: 100% | |||
padding-top: 50px | |||
text-align: center | |||
font-size: 1em | |||
line-height: 1.5em | |||
@include vendor(transition, margin-left 0.2s ease-in-out) | |||
#title | |||
margin-right: 10px | |||
&.visible | |||
margin-left: 0px | |||
#site | |||
text-transform: capitalize | |||
#date-created | |||
display: inline-block | |||
td#code | |||
@include vendor(transition, width 0.2s ease-in-out) | |||
#date-modified | |||
display: block | |||
width: $codeWidth | |||
height: inherit | |||
padding: 0px | |||
border: 1px solid #bbb | |||
#language | |||
display: inline-block | |||
font-weight: bold | |||
color: orange | |||
#tablecontainer | |||
overflow: hidden | |||
width: 100% | |||
height: inherit | |||
background-color: #49483e | |||
position: relative | |||
z-index: 1 | |||
#authors | |||
a | |||
text-decoration: none | |||
table | |||
border-collapse: collapse | |||
font-family: monospace | |||
&:hover | |||
color: orange | |||
.linenos | |||
padding-left: 1% | |||
&.cascade | |||
@extend .t3 | |||
pre | |||
margin-top: 5px | |||
.code pre | |||
margin-top: 5px | |||
.hll | |||
background: #5B5A51 | |||
div#hidden-info | |||
width: $hiddenInfoWidth | |||
margin-left: -$hiddenInfoWidth - 10px | |||
height: 100% | |||
padding-top: 40px | |||
font-size: 1.2em | |||
line-height: 1.5em | |||
position: relative | |||
z-index: 0 | |||
@include vendor(transition, margin-left 0.2s ease-in-out) | |||
.display-all & | |||
margin-left: 0px | |||
padding-left: 20px | |||
span | |||
font-family: monospace | |||
color: $baseColor1 | |||
float: right | |||
div | |||
display: block | |||
#authors | |||
a | |||
font-family: monospace |
@@ -1,14 +1,13 @@ | |||
= extends "layout.html" | |||
= block title | |||
Home | |||
home | |||
= endblock | |||
= block head | |||
{{ assets.tag("lib/jqueryui.custom.min.css") }} | |||
{{ assets.tag("lib/jquery.min.js") }} | |||
{{ assets.tag("lib/jquery-ui.min.js") }} | |||
{{ assets.tag("lib/typeahead.bundle.min.js") }} | |||
{{ assets.tag("lib/highlight.css") }} | |||
{{ assets.tag("index.css") }} | |||
@@ -30,7 +29,7 @@ | |||
<form id="search-bar"> | |||
<input type="text" name="query" | |||
><button id="advanced-search" title="advanced search"> | |||
><button id="advanced-search" title="advanced search" type="button"> | |||
<img src="static/img/search_bar_magnifying_glass.png"> | |||
</button> | |||
@@ -100,3 +99,15 @@ | |||
{{ assets.tag("index.js") }} | |||
{{ assets.tag("index.advanced-search-form.js") }} | |||
= endblock | |||
= block after_body | |||
<div id="hotkey-help" class="hidden"> | |||
<div>Hotkeys</div> | |||
<ul> | |||
<li><span class="hotkey">k</span> <span class="seperator">:</span> move window up to the previous result</li> | |||
<li><span class="hotkey">j</span> <span class="seperator">:</span> move window down to the next result</li> | |||
<li><span class="hotkey">h</span> <span class="seperator">:</span> move to the previous symbol match</li> | |||
<li><span class="hotkey">l</span> <span class="seperator">:</span> move to the next symbol match</li> | |||
</ul> | |||
</div> | |||
= endblock |
@@ -4,8 +4,11 @@ | |||
<html> | |||
<head> | |||
<title> | |||
= block title | |||
= endblock | |||
bitshift « | |||
= filter lower | |||
= block title | |||
= endblock | |||
= endfilter | |||
</title> | |||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/> | |||
@@ -30,6 +33,9 @@ | |||
</div> | |||
</div> | |||
= block after_body | |||
= endblock | |||
<div id="footer"> | |||
<a href="/">home</a> | |||
<a href="/about">about</a> | |||
@@ -0,0 +1,40 @@ | |||
""" | |||
Module to contain all the project's Flask server plumbing. | |||
""" | |||
from flask import Flask | |||
from flask import render_template, session | |||
from bitshift import assets | |||
# from bitshift.database import Database | |||
# from bitshift.query import parse_query | |||
app = Flask(__name__) | |||
app.config.from_object("bitshift.config") | |||
app_env = app.jinja_env | |||
app_env.line_statement_prefix = "=" | |||
app_env.globals.update(assets=assets) | |||
# database = Database() | |||
@app.route("/") | |||
def index(): | |||
return render_template("index.html") | |||
@app.route("/search/<query>") | |||
def search(query): | |||
# tree = parse_query(query) | |||
# database.search(tree) | |||
pass | |||
@app.route("/about") | |||
def about(): | |||
return render_template("about.html") | |||
@app.route("/developers") | |||
def developers(): | |||
return render_template("developers.html") | |||
if __name__ == "__main__": | |||
app.run(debug=True) |