Browse Source

Merge remote-tracking branch 'origin/develop' into develop

Conflicts:
	bitshift/crawler/crawl.py
	bitshift/languages.py
tags/v1.0^2
Ben Kurtovic 10 years ago
parent
commit
3c786c5b47
19 changed files with 700 additions and 224 deletions
  1. +1
    -1
      .gitignore
  2. +1
    -1
      app.py
  3. +1
    -0
      bitshift/crawler/crawl.py
  4. +17
    -37
      bitshift/crawler/indexer.py
  5. +1
    -1
      bitshift/database/__init__.py
  6. +23
    -1
      bitshift/database/migration.py
  7. +18
    -4
      bitshift/database/schema.sql
  8. +2
    -1
      bitshift/languages.py
  9. +4
    -4
      parsers/java/src/main/java/com/bitshift/parsing/parsers/JavaParser.java
  10. +65
    -0
      static/css/lib/github.css
  11. +64
    -0
      static/css/lib/highlight.css
  12. +13
    -8
      static/js/index.advanced-search-form.js
  13. +266
    -53
      static/js/index.js
  14. +0
    -7
      static/js/lib/typeahead.bundle.min.js
  15. +5
    -0
      static/sass/_mixins.sass
  16. +157
    -101
      static/sass/index.sass
  17. +14
    -3
      templates/index.html
  18. +8
    -2
      templates/layout.html
  19. +40
    -0
      test/resources/app.py

+ 1
- 1
.gitignore View File

@@ -1,5 +1,5 @@
static/css/* static/css/*
!static/css/lib/*
!lib


*.swp *.swp
.sass-cache .sass-cache


+ 1
- 1
app.py View File

@@ -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():


+ 1
- 0
bitshift/crawler/crawl.py View File

@@ -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()




+ 17
- 37
bitshift/crawler/indexer.py View File

@@ -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):


+ 1
- 1
bitshift/database/__init__.py View File

@@ -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, "%")"""


+ 23
- 1
bitshift/database/migration.py View File

@@ -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"""
] ]
] ]




+ 18
- 4
bitshift/database/schema.sql View File

@@ -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


+ 2
- 1
bitshift/languages.py View File

@@ -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):


+ 4
- 4
parsers/java/src/main/java/com/bitshift/parsing/parsers/JavaParser.java View File

@@ -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;
} }


+ 65
- 0
static/css/lib/github.css View File

@@ -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 */

+ 64
- 0
static/css/lib/highlight.css View File

@@ -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 */

+ 13
- 8
static/js/index.advanced-search-form.js View File

@@ -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 + '"';
} }

+ 266
- 53
static/js/index.js View File

@@ -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">&quot;&quot;&quot;</span>\n<span class="sd">Module to contain all the project&#39;s Flask server plumbing.</span>\n<span class="sd">&quot;&quot;&quot;</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">&quot;bitshift.config&quot;</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">&quot;=&quot;</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">&quot;/&quot;</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">&quot;index.html&quot;</span><span class="p">)</span>\n\n<span class="nd">@app.route</span><span class="p">(</span><span class="s">&quot;/search/&lt;query&gt;&quot;</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">&quot;/about&quot;</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">&quot;about.html&quot;</span><span class="p">)</span>\n\n<span class="nd">@app.route</span><span class="p">(</span><span class="s">&quot;/developers&quot;</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">&quot;developers.html&quot;</span><span class="p">)</span>\n\n<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&quot;__main__&quot;</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">&quot;&quot;&quot;</span>\n<span class="sd">Module to contain all the project&#39;s Flask server plumbing.</span>\n<span class="sd">&quot;&quot;&quot;</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">&quot;bitshift.config&quot;</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">&quot;=&quot;</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">&quot;/&quot;</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">&quot;index.html&quot;</span><span class="p">)</span>\n\n<span class="hll"><span class="nd">@app.route</span><span class="p">(</span><span class="s">&quot;/search/&lt;query&gt;&quot;</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">&quot;/about&quot;</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">&quot;about.html&quot;</span><span class="p">)</span>\n\n<span class="hll"><span class="nd">@app.route</span><span class="p">(</span><span class="s">&quot;/developers&quot;</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">&quot;developers.html&quot;</span><span class="p">)</span>\n\n<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&quot;__main__&quot;</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 = ' &raquo; <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();

+ 0
- 7
static/js/lib/typeahead.bundle.min.js
File diff suppressed because it is too large
View File


+ 5
- 0
static/sass/_mixins.sass View File

@@ -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)




+ 157
- 101
static/sass/index.sass View File

@@ -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

+ 14
- 3
templates/index.html View File

@@ -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

+ 8
- 2
templates/layout.html View File

@@ -4,8 +4,11 @@
<html> <html>
<head> <head>
<title> <title>
= block title
= endblock
bitshift &laquo;
= 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>


+ 40
- 0
test/resources/app.py View File

@@ -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)

Loading…
Cancel
Save