Conflicts: bitshift/crawler/crawl.py bitshift/languages.pytags/v1.0^2
@@ -1,5 +1,5 @@ | |||||
static/css/* | static/css/* | ||||
!static/css/lib/* | |||||
!lib | |||||
*.swp | *.swp | ||||
.sass-cache | .sass-cache | ||||
@@ -22,7 +22,7 @@ database = Database() | |||||
@app.route("/") | @app.route("/") | ||||
def index(): | def index(): | ||||
return render_template("index.html", typeahead_languages=LANGS) | |||||
return render_template("index.html", autocomplete_languages=LANGS) | |||||
@app.route("/search.json") | @app.route("/search.json") | ||||
def search(): | def search(): | ||||
@@ -39,6 +39,7 @@ def crawl(): | |||||
indexer.GitIndexer(repo_clone_queue, run_event)] | indexer.GitIndexer(repo_clone_queue, run_event)] | ||||
parse_servers = start_parse_servers() | parse_servers = start_parse_servers() | ||||
time.sleep(5) | |||||
for thread in threads: | for thread in threads: | ||||
thread.start() | thread.start() | ||||
@@ -33,6 +33,7 @@ class GitRepository(object): | |||||
repository belongs to (eg, GitHub, BitBucket). | repository belongs to (eg, GitHub, BitBucket). | ||||
:ivar rank: (float) The rank of the repository, as assigned by | :ivar rank: (float) The rank of the repository, as assigned by | ||||
:class:`crawler.GitHubCrawler`. | :class:`crawler.GitHubCrawler`. | ||||
:ivar dirname: (str) The repository's on-disk directory name. | |||||
""" | """ | ||||
def __init__(self, url, name, framework_name, rank): | def __init__(self, url, name, framework_name, rank): | ||||
@@ -54,6 +55,7 @@ class GitRepository(object): | |||||
self.name = name | self.name = name | ||||
self.framework_name = framework_name | self.framework_name = framework_name | ||||
self.rank = rank | self.rank = rank | ||||
self.dirname = name.replace("-", "--").replace("/", "-") | |||||
class GitIndexer(threading.Thread): | class GitIndexer(threading.Thread): | ||||
""" | """ | ||||
@@ -125,19 +127,14 @@ class GitIndexer(threading.Thread): | |||||
:type repo_url: :class:`GitRepository` | :type repo_url: :class:`GitRepository` | ||||
""" | """ | ||||
with _ChangeDir("%s/%s" % (GIT_CLONE_DIR, repo.name)): | |||||
with _ChangeDir("%s/%s" % (GIT_CLONE_DIR, repo.dirname)): | |||||
try: | try: | ||||
self._insert_repository_codelets(repo) | self._insert_repository_codelets(repo) | ||||
except Exception: | except Exception: | ||||
self._logger.exception("Exception raised while indexing:") | self._logger.exception("Exception raised while indexing:") | ||||
finally: | 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): | def _insert_repository_codelets(self, repo): | ||||
""" | """ | ||||
@@ -167,9 +164,9 @@ class GitIndexer(threading.Thread): | |||||
authors = [(self._decode(author), None) for author in | authors = [(self._decode(author), None) for author in | ||||
commits_meta[filename]["authors"]] | 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_created"], | ||||
commits_meta[filename]["time_last_modified"], | commits_meta[filename]["time_last_modified"], | ||||
repo.rank) | repo.rank) | ||||
@@ -437,37 +434,20 @@ class _GitCloner(threading.Thread): | |||||
""" | """ | ||||
GIT_CLONE_TIMEOUT = 500 | GIT_CLONE_TIMEOUT = 500 | ||||
queue_percent_full = (float(self.index_queue.qsize()) / | 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 | return | ||||
while self.index_queue.full(): | while self.index_queue.full(): | ||||
time.sleep(THREAD_QUEUE_SLEEP) | time.sleep(THREAD_QUEUE_SLEEP) | ||||
self.index_queue.put(repo) | self.index_queue.put(repo) | ||||
class _ChangeDir(object): | class _ChangeDir(object): | ||||
@@ -131,7 +131,7 @@ class Database(object): | |||||
def _decompose_url(self, cursor, url): | def _decompose_url(self, cursor, url): | ||||
"""Break up a URL into an origin (with a URL base) and a suffix.""" | """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 | FROM origins | ||||
WHERE origin_url_base IS NOT NULL | WHERE origin_url_base IS NOT NULL | ||||
AND ? LIKE CONCAT(origin_url_base, "%")""" | AND ? LIKE CONCAT(origin_url_base, "%")""" | ||||
@@ -3,7 +3,7 @@ Contains information about database schema versions, and SQL queries to update | |||||
between them. | between them. | ||||
""" | """ | ||||
VERSION = 8 | |||||
VERSION = 10 | |||||
MIGRATIONS = [ | MIGRATIONS = [ | ||||
# 1 -> 2 | # 1 -> 2 | ||||
@@ -100,6 +100,28 @@ MIGRATIONS = [ | |||||
[ | [ | ||||
"""ALTER TABLE `origins` | """ALTER TABLE `origins` | ||||
DROP COLUMN `origin_image`""" | 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; | CREATE DATABASE `bitshift` DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci; | ||||
USE `bitshift`; | USE `bitshift`; | ||||
@@ -6,7 +6,7 @@ USE `bitshift`; | |||||
CREATE TABLE `version` ( | CREATE TABLE `version` ( | ||||
`version` INT UNSIGNED NOT NULL | `version` INT UNSIGNED NOT NULL | ||||
) ENGINE=InnoDB; | ) ENGINE=InnoDB; | ||||
INSERT INTO `version` VALUES (8); | |||||
INSERT INTO `version` VALUES (10); | |||||
CREATE TABLE `origins` ( | CREATE TABLE `origins` ( | ||||
`origin_id` TINYINT UNSIGNED NOT NULL AUTO_INCREMENT, | `origin_id` TINYINT UNSIGNED NOT NULL AUTO_INCREMENT, | ||||
@@ -77,9 +77,9 @@ CREATE TABLE `symbol_locations` ( | |||||
`sloc_symbol` BIGINT UNSIGNED NOT NULL, | `sloc_symbol` BIGINT UNSIGNED NOT NULL, | ||||
`sloc_type` TINYINT UNSIGNED NOT NULL, | `sloc_type` TINYINT UNSIGNED NOT NULL, | ||||
`sloc_row` INT 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`), | PRIMARY KEY (`sloc_id`), | ||||
FOREIGN KEY (`sloc_symbol`) | FOREIGN KEY (`sloc_symbol`) | ||||
REFERENCES `symbols` (`symbol_id`) | REFERENCES `symbols` (`symbol_id`) | ||||
@@ -107,6 +107,19 @@ CREATE TABLE `cache_data` ( | |||||
ON DELETE CASCADE ON UPDATE CASCADE | ON DELETE CASCADE ON UPDATE CASCADE | ||||
) ENGINE=InnoDB; | ) 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` | CREATE EVENT `flush_cache` | ||||
ON SCHEDULE EVERY 1 HOUR | ON SCHEDULE EVERY 1 HOUR | ||||
DO | DO | ||||
@@ -8,7 +8,8 @@ def _load_langs(): | |||||
filename = path.join(path.dirname(__file__), "languages.yml") | filename = path.join(path.dirname(__file__), "languages.yml") | ||||
with open(filename) as fp: | with open(filename) as fp: | ||||
data = yaml.load(fp)["languages"] | 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 = {} | all_langs = {} | ||||
for i, lang in enumerate(data): | for i, lang in enumerate(data): | ||||
if isinstance(lang, dict): | if isinstance(lang, dict): | ||||
@@ -80,7 +80,7 @@ public class JavaParser extends Parser { | |||||
int sl = this.root.getLineNumber(node.getStartPosition()); | int sl = this.root.getLineNumber(node.getStartPosition()); | ||||
int sc = this.root.getColumnNumber(node.getStartPosition()); | int sc = this.root.getColumnNumber(node.getStartPosition()); | ||||
Integer el = -1; | |||||
Integer el = sl; | |||||
Integer ec = -1; | Integer ec = -1; | ||||
if (statements.size() > 0) { | if (statements.size() > 0) { | ||||
@@ -110,7 +110,7 @@ public class JavaParser extends Parser { | |||||
int sl = this.root.getLineNumber(node.getStartPosition()); | int sl = this.root.getLineNumber(node.getStartPosition()); | ||||
int sc = this.root.getColumnNumber(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); | data.put("name", name); | ||||
this._cache.push(data); | this._cache.push(data); | ||||
return true; | return true; | ||||
@@ -140,7 +140,7 @@ public class JavaParser extends Parser { | |||||
int sl = this.root.getLineNumber(node.getStartPosition()); | int sl = this.root.getLineNumber(node.getStartPosition()); | ||||
int sc = this.root.getColumnNumber(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); | this._cache.push(data); | ||||
return true; | return true; | ||||
} | } | ||||
@@ -161,7 +161,7 @@ public class JavaParser extends Parser { | |||||
int sl = this.root.getLineNumber(node.getStartPosition()); | int sl = this.root.getLineNumber(node.getStartPosition()); | ||||
int sc = this.root.getColumnNumber(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); | this._cache.push(data); | ||||
return true; | 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( | searchGroups.append( | ||||
searchGroup.append(createSearchGroupInput("language"))); | searchGroup.append(createSearchGroupInput("language"))); | ||||
$("div#sidebar input[type=checkbox]#language").prop("checked", true); | $("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 | // 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(){ | $("div#sidebar input[type=checkbox]").click(function(){ | ||||
var fieldId = $(this).prop("id"); | var fieldId = $(this).prop("id"); | ||||
if($(this).is(":checked")){ | if($(this).is(":checked")){ | ||||
@@ -76,8 +78,13 @@ var searchGroups = $("div#search-groups"); | |||||
if(fieldId.slice(0, 4) == "date") | if(fieldId.slice(0, 4) == "date") | ||||
$(".search-group#selected ." + fieldId).datepicker(); | $(".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 = ""; | var previousAdvancedQuery = ""; | ||||
@@ -125,7 +132,8 @@ function assembleQuery(){ | |||||
groupQuery.push(genFieldQueryString( | groupQuery.push(genFieldQueryString( | ||||
inputFields[field], regexCheckbox[field].checked)); | inputFields[field], regexCheckbox[field].checked)); | ||||
groupQueries.push(groupQuery.join(" AND ")); | |||||
if(groupQuery.length > 0) | |||||
groupQueries.push(groupQuery.join(" AND ")); | |||||
} | } | ||||
return groupQueries.join(" OR "); | return groupQueries.join(" OR "); | ||||
@@ -140,8 +148,5 @@ function assembleQuery(){ | |||||
function genFieldQueryString(field, hasRegex){ | function genFieldQueryString(field, hasRegex){ | ||||
var terms = field.value.replace(/\\/g, "\\\\").replace(/\"/g, "\\\""); | var terms = field.value.replace(/\\/g, "\\\\").replace(/\"/g, "\\\""); | ||||
var query = field.getAttribute("name") + ":" + (hasRegex?"re:":"") + terms; | 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 advancedSearchDiv = $("div#advanced-search"); | ||||
var advancedSearchButton = $("button#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 | //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; | searchBar.onkeyup = typingTimer; | ||||
var testCodelet = { | var testCodelet = { | ||||
'url': 'https://github.com/earwig/bitshift/blob/develop/app.py', | 'url': 'https://github.com/earwig/bitshift/blob/develop/app.py', | ||||
'filename': 'app.py', | 'filename': 'app.py', | ||||
'language': 'Python', | |||||
'language': 'python', | |||||
'date_created': 'May 10, 2014', | 'date_created': 'May 10, 2014', | ||||
'date_modified': '2 days ago', | 'date_modified': '2 days ago', | ||||
'origin': ['GitHub', 'https://github.com', ''], | 'origin': ['GitHub', 'https://github.com', ''], | ||||
@@ -43,17 +154,12 @@ var testCodelet = { | |||||
// Enable infinite scrolling down the results page. | // Enable infinite scrolling down the results page. | ||||
$(window).scroll(function() { | $(window).scroll(function() { | ||||
var searchField = $("div#search-field"); | 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(); | 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 | * Clear the existing timer and set a new one the the user types text into the | ||||
* search bar. | * search bar. | ||||
@@ -109,6 +215,7 @@ function clearResults(){ | |||||
* with its response. | * with its response. | ||||
*/ | */ | ||||
function populateResults(){ | function populateResults(){ | ||||
searchResultsPage = 1; | |||||
var results = queryServer(); | var results = queryServer(); | ||||
for(var result = 0; result < results.length; result++){ | for(var result = 0; result < results.length; result++){ | ||||
@@ -135,74 +242,108 @@ function createResult(codelet) { | |||||
row = document.createElement("tr"); | row = document.createElement("tr"); | ||||
//Level 2 | //Level 2 | ||||
var displayInfo = document.createElement("div"), | var displayInfo = document.createElement("div"), | ||||
sidebar = document.createElement("td"), | |||||
codeElt = document.createElement("td"), | codeElt = document.createElement("td"), | ||||
displayButton = document.createElement("td"), | |||||
hiddenInfoContainer = document.createElement("td"), | hiddenInfoContainer = document.createElement("td"), | ||||
hiddenInfo = document.createElement("div"); | |||||
hiddenInfo = document.createElement("div"), | |||||
cycle = document.createElement("div"); | |||||
//Level 3 | //Level 3 | ||||
var title = document.createElement("span"), | var title = document.createElement("span"), | ||||
site = 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"); | authors = document.createElement("div"); | ||||
//Classes and ID's | //Classes and ID's | ||||
newDiv.classList.add('result'); | newDiv.classList.add('result'); | ||||
displayInfo.id = 'display-info'; | displayInfo.id = 'display-info'; | ||||
sidebar.id = 'sidebar'; | |||||
codeElt.id = 'code'; | codeElt.id = 'code'; | ||||
displayButton.id = 'display-button'; | |||||
hiddenInfo.id = 'hidden-info'; | hiddenInfo.id = 'hidden-info'; | ||||
cycle.id = 'cycle-matches' | |||||
title.id = 'title'; | title.id = 'title'; | ||||
site.id = 'site'; | site.id = 'site'; | ||||
nextMatch.id = 'next-match'; | |||||
nextMatch.href = '#'; | |||||
prevMatch.id = 'prev-match'; | |||||
prevMatch.href = '#'; | |||||
dateModified.id = 'date-modified'; | dateModified.id = 'date-modified'; | ||||
language.id = 'language'; | language.id = 'language'; | ||||
dateCreated.id = 'date-created'; | dateCreated.id = 'date-created'; | ||||
authors.id = 'authors'; | authors.id = 'authors'; | ||||
//Add the bulk of the html | //Add the bulk of the html | ||||
title.innerHTML = 'File <a href="' + codelet.url + '">' | |||||
title.innerHTML = ' » <a href="' + codelet.url + '">' | |||||
+ codelet.filename + '</a>'; | + 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 | // 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 | // Needs to be processed on the server | ||||
codeElt.innerHTML = '<div id=tablecontainer>' + codelet.html_code + '</div>'; | codeElt.innerHTML = '<div id=tablecontainer>' + codelet.html_code + '</div>'; | ||||
//Event binding | //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 | //Finish and append elements to parent elements | ||||
hiddenInfo.appendChild(dateCreated); | hiddenInfo.appendChild(dateCreated); | ||||
hiddenInfo.appendChild(dateModified); | hiddenInfo.appendChild(dateModified); | ||||
hiddenInfo.appendChild(authors); | |||||
hiddenInfo.appendChild(language); | hiddenInfo.appendChild(language); | ||||
hiddenInfo.appendChild(authors); | |||||
hiddenInfoContainer.appendChild(hiddenInfo); | hiddenInfoContainer.appendChild(hiddenInfo); | ||||
row.appendChild(sidebar); | |||||
row.appendChild(codeElt); | row.appendChild(codeElt); | ||||
row.appendChild(hiddenInfoContainer); | row.appendChild(hiddenInfoContainer); | ||||
row.appendChild(displayButton); | |||||
table.appendChild(row); | table.appendChild(row); | ||||
displayInfo.appendChild(title); | |||||
displayInfo.appendChild(site); | displayInfo.appendChild(site); | ||||
displayInfo.appendChild(title); | |||||
cycle.appendChild(prevMatch); | |||||
cycle.appendChild(nextMatch); | |||||
newDiv.appendChild(displayInfo); | newDiv.appendChild(displayInfo); | ||||
newDiv.appendChild(table); | newDiv.appendChild(table); | ||||
@@ -210,6 +351,52 @@ function createResult(codelet) { | |||||
return newDiv; | 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. | * AJAX the current query string to the server, and return its response. | ||||
* | * | ||||
@@ -217,10 +404,23 @@ function createResult(codelet) { | |||||
* elements, to fill `div#results`. | * elements, to fill `div#results`. | ||||
*/ | */ | ||||
function queryServer(){ | 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++){ | for(var result = 0; result < 20; result++){ | ||||
var newDiv = createResult(testCodelet); | var newDiv = createResult(testCodelet); | ||||
resultDivs.push(newDiv); | |||||
resultDivs.push(newDiv) | |||||
} | } | ||||
return resultDivs; | return resultDivs; | ||||
@@ -230,7 +430,7 @@ function queryServer(){ | |||||
* Adds more results to `div#results`. | * Adds more results to `div#results`. | ||||
*/ | */ | ||||
function loadMoreResults(){ | function loadMoreResults(){ | ||||
results = queryServer(); | |||||
var results = queryServer(); | |||||
for(var result = 0; result < results.length; result++){ | for(var result = 0; result < results.length; result++){ | ||||
var newDiv = results[result]; | var newDiv = results[result]; | ||||
resultsDiv.appendChild(newDiv); | resultsDiv.appendChild(newDiv); | ||||
@@ -243,3 +443,16 @@ function loadMoreResults(){ | |||||
result * 20); | 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 | -o-#{$property}: $value | ||||
#{$property}: $value | #{$property}: $value | ||||
// Add portable opacity style. | |||||
@mixin opaque($opacity) | |||||
@include vendor(opacity, $opacity) | |||||
filter: alpha(opacity=$opacity) | |||||
.t1 | .t1 | ||||
@include vendor(transition, all 0.1s ease-out) | @include vendor(transition, all 0.1s ease-out) | ||||
@@ -6,9 +6,8 @@ | |||||
@import variables | @import variables | ||||
$minSearchFieldsWidth: 490px | $minSearchFieldsWidth: 490px | ||||
$resultWidth: 830px | |||||
$sidebarWidth: 30px | |||||
$codeWidth: 500px | |||||
$resultWidth: 1000px | |||||
$codeWidth: 650px | |||||
$hiddenInfoWidth: 250px | $hiddenInfoWidth: 250px | ||||
.ui-datepicker | .ui-datepicker | ||||
@@ -23,6 +22,54 @@ $hiddenInfoWidth: 250px | |||||
>li.ui-menu-item a.ui-state-focus | >li.ui-menu-item a.ui-state-focus | ||||
@include vendor(transition, background-color 0.3s ease-out) | @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 | div#search-field | ||||
@extend .t2 | @extend .t2 | ||||
@@ -34,6 +81,7 @@ div#search-field | |||||
max-height: 100px | max-height: 100px | ||||
right: 0 | right: 0 | ||||
position: absolute | position: absolute | ||||
z-index: 2 | |||||
top: 0 | top: 0 | ||||
width: 40% | width: 40% | ||||
@@ -103,7 +151,6 @@ div#search-field | |||||
&.partly-visible | &.partly-visible | ||||
margin-top: 0% | margin-top: 0% | ||||
padding-bottom: 3% | |||||
position: absolute | position: absolute | ||||
width: 100% | width: 100% | ||||
@@ -121,6 +168,11 @@ div#search-field | |||||
margin-right: auto | margin-right: auto | ||||
width: 60% | width: 60% | ||||
input:hover | |||||
@extend .t3 | |||||
border: 1px solid $baseColor1 | |||||
div#advanced-search | div#advanced-search | ||||
background-color: white | background-color: white | ||||
border: 1px solid $baseColor3 | border: 1px solid $baseColor3 | ||||
@@ -237,7 +289,7 @@ div#advanced-search | |||||
#search-groups | #search-groups | ||||
margin-top: 1% | margin-top: 1% | ||||
max-height: 93% | |||||
max-height: 87% | |||||
overflow-y: auto | overflow-y: auto | ||||
width: 75% | width: 75% | ||||
@@ -286,112 +338,116 @@ div#results | |||||
margin-right: auto | margin-right: auto | ||||
width: 80% | 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 | 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" | = extends "layout.html" | ||||
= block title | = block title | ||||
Home | |||||
home | |||||
= endblock | = endblock | ||||
= block head | = block head | ||||
{{ assets.tag("lib/jqueryui.custom.min.css") }} | {{ assets.tag("lib/jqueryui.custom.min.css") }} | ||||
{{ assets.tag("lib/jquery.min.js") }} | {{ assets.tag("lib/jquery.min.js") }} | ||||
{{ assets.tag("lib/jquery-ui.min.js") }} | {{ assets.tag("lib/jquery-ui.min.js") }} | ||||
{{ assets.tag("lib/typeahead.bundle.min.js") }} | |||||
{{ assets.tag("lib/highlight.css") }} | {{ assets.tag("lib/highlight.css") }} | ||||
{{ assets.tag("index.css") }} | {{ assets.tag("index.css") }} | ||||
@@ -30,7 +29,7 @@ | |||||
<form id="search-bar"> | <form id="search-bar"> | ||||
<input type="text" name="query" | <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"> | <img src="static/img/search_bar_magnifying_glass.png"> | ||||
</button> | </button> | ||||
@@ -100,3 +99,15 @@ | |||||
{{ assets.tag("index.js") }} | {{ assets.tag("index.js") }} | ||||
{{ assets.tag("index.advanced-search-form.js") }} | {{ assets.tag("index.advanced-search-form.js") }} | ||||
= endblock | = 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> | <html> | ||||
<head> | <head> | ||||
<title> | <title> | ||||
= block title | |||||
= endblock | |||||
bitshift « | |||||
= filter lower | |||||
= block title | |||||
= endblock | |||||
= endfilter | |||||
</title> | </title> | ||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/> | <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/> | ||||
@@ -30,6 +33,9 @@ | |||||
</div> | </div> | ||||
</div> | </div> | ||||
= block after_body | |||||
= endblock | |||||
<div id="footer"> | <div id="footer"> | ||||
<a href="/">home</a> | <a href="/">home</a> | ||||
<a href="/about">about</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) |