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