├── .gitignore
├── README.md
├── build
└── .gitkeep
├── chrome
├── _locales
│ └── en
│ │ └── messages.json
├── icons
│ ├── icon128.png
│ ├── icon16.png
│ ├── icon19.png
│ └── icon48.png
├── manifest.json
└── src
│ ├── .gitkeep
│ ├── inject
│ └── .gitkeep
│ └── lib
│ └── .gitkeep
├── firefox
├── data
│ └── .gitkeep
├── lib
│ └── main.js
└── package.json
├── package-exts
└── src
├── inject.css
├── inject.js
└── lib
└── jquery.min.js
/.gitignore:
--------------------------------------------------------------------------------
1 | chrome/src/inject/inject*
2 | chrome/src/lib/jquery*
3 | firefox/data/inject*
4 | firefox/data/jquery*
5 | *.xpi
6 | *.zip
7 | *debuglog.txt
8 |
9 | ### vim ###
10 | [._]*.s[a-w][a-z]
11 | [._]s[a-w][a-z]
12 | *.un~
13 | Session.vim
14 | .netrwhist
15 | *~
16 |
17 | ### OSX ###
18 | .DS_Store
19 | .AppleDouble
20 | .LSOverride
21 |
22 | # Icon must end with two \r
23 | Icon
24 |
25 |
26 | # Thumbnails
27 | ._*
28 |
29 | # Files that might appear on external disk
30 | .Spotlight-V100
31 | .Trashes
32 |
33 | # Directories potentially created on remote AFP share
34 | .AppleDB
35 | .AppleDesktop
36 | Network Trash Folder
37 | Temporary Items
38 | .apdisk
39 |
40 | /build
41 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CodeNav
2 |
3 | CodeNav is a Chrome extension and Firefox addon that makes navigating code on Github easier and more intuitive. It borrows features from popular IDEs for more seamless movement around code.
4 |
5 | ## Install for Chrome or Firefox
6 |
7 | Get the latest download links on the [CodeNav site](http://ianww.com/codenav).
8 |
9 | ## Building from source
10 |
11 | ```sh
12 | ./package-exts
13 | ```
14 |
15 | ## License (MIT)
16 |
17 | Copyright (C) 2014 by Ian Webster
18 |
19 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
20 |
21 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
22 |
23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 |
--------------------------------------------------------------------------------
/build/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/typpo/codenav/6d7c5d8e7354fee1d97ef7fa7014b738c9ba7dc2/build/.gitkeep
--------------------------------------------------------------------------------
/chrome/_locales/en/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "l10nTabName": {
3 | "message":"Localization"
4 | ,"description":"name of the localization tab"
5 | }
6 | ,"l10nHeader": {
7 | "message":"It does localization too! (this whole tab is, actually)"
8 | ,"description":"Header text for the localization section"
9 | }
10 | ,"l10nIntro": {
11 | "message":"'L10n' refers to 'Localization' - 'L' an 'n' are obvious, and 10 comes from the number of letters between those two. It is the process/whatever of displaying something in the language of choice. It uses 'I18n', 'Internationalization', which refers to the tools / framework supporting L10n. I.e., something is internationalized if it has I18n support, and can be localized. Something is localized for you if it is in your language / dialect."
12 | ,"description":"introduce the basic idea."
13 | }
14 | ,"l10nProd": {
15 | "message":"You are planning to allow localization, right? You have no idea who will be using your extension! You have no idea who will be translating it! At least support the basics, it's not hard, and having the framework in place will let you transition much more easily later on."
16 | ,"description":"drive the point home. It's good for you."
17 | }
18 | ,"l10nFirstParagraph": {
19 | "message":"When the options page loads, elements decorated with data-l10n will automatically be localized!"
20 | ,"description":"inform that elements will be localized on load"
21 | }
22 | ,"l10nSecondParagraph": {
23 | "message":"If you need more complex localization, you can also define data-l10n-args. This should contain $containerType$ filled with $dataType$, which will be passed into Chrome's i18n API as $functionArgs$. In fact, this paragraph does just that, and wraps the args in mono-space font. Easy!"
24 | ,"description":"introduce the data-l10n-args attribute. End on a lame note."
25 | ,"placeholders": {
26 | "containerType": {
27 | "content":"$1"
28 | ,"example":"'array', 'list', or something similar"
29 | ,"description":"type of the args container"
30 | }
31 | ,"dataType": {
32 | "content":"$2"
33 | ,"example":"string"
34 | ,"description":"type of data in each array index"
35 | }
36 | ,"functionArgs": {
37 | "content":"$3"
38 | ,"example":"arguments"
39 | ,"description":"whatever you call what you pass into a function/method. args, params, etc."
40 | }
41 | }
42 | }
43 | ,"l10nThirdParagraph": {
44 | "message":"Message contents are passed right into innerHTML without processing - include any tags (or even scripts) that you feel like. If you have an input field, the placeholder will be set instead, and buttons will have the value attribute set."
45 | ,"description":"inform that we handle placeholders, buttons, and direct HTML input"
46 | }
47 | ,"l10nButtonsBefore": {
48 | "message":"Different types of buttons are handled as well. <button> elements have their html set:"
49 | }
50 | ,"l10nButton": {
51 | "message":"in a button"
52 | }
53 | ,"l10nButtonsBetween": {
54 | "message":"while <input type='submit'> and <input type='button'> get their 'value' set (note: no HTML):"
55 | }
56 | ,"l10nSubmit": {
57 | "message":"a submit value"
58 | }
59 | ,"l10nButtonsAfter": {
60 | "message":"Awesome, no?"
61 | }
62 | ,"l10nExtras": {
63 | "message":"You can even set data-l10n on things like the <title> tag, which lets you have translatable page titles, or fieldset <legend> tags, or anywhere else - the default Boil.localize() behavior will check every tag in the document, not just the body."
64 | ,"description":"inform about places which may not be obvious, like
, etc"
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/chrome/icons/icon128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/typpo/codenav/6d7c5d8e7354fee1d97ef7fa7014b738c9ba7dc2/chrome/icons/icon128.png
--------------------------------------------------------------------------------
/chrome/icons/icon16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/typpo/codenav/6d7c5d8e7354fee1d97ef7fa7014b738c9ba7dc2/chrome/icons/icon16.png
--------------------------------------------------------------------------------
/chrome/icons/icon19.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/typpo/codenav/6d7c5d8e7354fee1d97ef7fa7014b738c9ba7dc2/chrome/icons/icon19.png
--------------------------------------------------------------------------------
/chrome/icons/icon48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/typpo/codenav/6d7c5d8e7354fee1d97ef7fa7014b738c9ba7dc2/chrome/icons/icon48.png
--------------------------------------------------------------------------------
/chrome/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "manifest_version": 2,
3 | "name": "CodeNav (Github code navigation)",
4 | "version": "0.0.14",
5 | "manifest_version": 2,
6 | "description": "Navigate Github code easily.",
7 | "homepage_url": "http://ianww.com/codenav",
8 | "icons": {
9 | "16": "icons/icon16.png",
10 | "48": "icons/icon48.png",
11 | "128": "icons/icon128.png"
12 | },
13 | "default_locale": "en",
14 | "permissions": [
15 | "https://github.com/*",
16 | "http://github.com/*"
17 | ],
18 | "content_scripts": [
19 | {
20 | "matches": [
21 | "https://github.com/*",
22 | "http://github.com/*"
23 | ],
24 | "js": [
25 | "src/lib/jquery.min.js",
26 | "src/inject/inject.js"
27 | ],
28 | "css": [
29 | "src/inject/inject.css"
30 | ]
31 | }
32 | ],
33 | "applications": {
34 | "gecko": {
35 | "id": "@codenav",
36 | "strict_min_version": "55.0"
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/chrome/src/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/typpo/codenav/6d7c5d8e7354fee1d97ef7fa7014b738c9ba7dc2/chrome/src/.gitkeep
--------------------------------------------------------------------------------
/chrome/src/inject/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/typpo/codenav/6d7c5d8e7354fee1d97ef7fa7014b738c9ba7dc2/chrome/src/inject/.gitkeep
--------------------------------------------------------------------------------
/chrome/src/lib/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/typpo/codenav/6d7c5d8e7354fee1d97ef7fa7014b738c9ba7dc2/chrome/src/lib/.gitkeep
--------------------------------------------------------------------------------
/firefox/data/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/typpo/codenav/6d7c5d8e7354fee1d97ef7fa7014b738c9ba7dc2/firefox/data/.gitkeep
--------------------------------------------------------------------------------
/firefox/lib/main.js:
--------------------------------------------------------------------------------
1 | var pageMod = require("sdk/page-mod");
2 | var self = require("sdk/self");
3 |
4 | // Create a page mod
5 | // It will run a script whenever a ".org" URL is loaded
6 | // The script replaces the page contents with a message
7 | pageMod.PageMod({
8 | include: ["http://github.com/*", "https://github.com/*"],
9 | contentScriptFile: [self.data.url("jquery.min.js"), self.data.url("inject.js")],
10 | contentStyleFile: self.data.url("inject.css")
11 | });
12 |
--------------------------------------------------------------------------------
/firefox/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "codenav",
3 | "title": "CodeNav",
4 | "id": "jid1-sDYWrhm3vTaDVw@jetpack",
5 | "description": "easier github browsing",
6 | "author": "Ian Webster",
7 | "license": "MIT",
8 | "version": "0.12.0",
9 | "main": "lib/main.js"
10 | }
11 |
--------------------------------------------------------------------------------
/package-exts:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -eo pipefail
3 | shopt -s nullglob
4 |
5 | root="${0%/*}"
6 | build="$root/build"
7 |
8 | build() {
9 | local browser="${1:?}"
10 |
11 | (
12 | set -x
13 | cd "$build"
14 |
15 | rsync -ahS -L --delete-after "../$browser/" "$browser"
16 |
17 | cd "$browser"
18 |
19 | case "$browser" in
20 | chrome)
21 | web-ext build -s . -a .. -o
22 | ;;
23 | firefox)
24 | jpm xpi --addon-dir .
25 | mv -vf -- *.xpi ..
26 | ;;
27 | *)
28 | printf 'Unknown browser: %s\n' "$browser" >&2
29 | ;;
30 | esac
31 |
32 | )
33 | }
34 |
35 | [ $# -gt 0 ] || set -- chrome firefox
36 |
37 | for browser in "$@"; do
38 | printf '# %s:\n' "$browser"
39 | build "$browser"
40 | echo
41 | done
42 |
43 | echo '# build/* :'
44 | ls -ltrh $(find "$build" -maxdepth 1 -type f -not -name '.*')
45 |
46 |
--------------------------------------------------------------------------------
/src/inject.css:
--------------------------------------------------------------------------------
1 | .codenav_word_split span {
2 | cursor: pointer;
3 | }
4 | .codenav_highlight {
5 | background-color: rgb(255, 255, 170);
6 | }
7 |
8 | .codenav_highlight_sticky {
9 | background-color: #88ffb8 !important;
10 | }
11 |
12 | .codenav_ignore {
13 | cursor: text !important;
14 | }
15 |
16 | #codenav_search_results {
17 | border-top: 2px solid #000;
18 | padding: 20px;
19 | background-color: #fff;
20 |
21 | width:100%;
22 | position: fixed;
23 | bottom:0;
24 | height: 300px; /* see preferred_search_box_height in js */
25 |
26 | overflow-y: scroll;
27 | z-index: 999999;
28 | }
29 |
30 | .codenav_search_results_highlight {
31 | background-color: #88ffb8;
32 | cursor: pointer;
33 | }
34 |
35 | #codenav_search_x {
36 | font-size: 20px;
37 | font-weight: bold;
38 | background-color: #ccc;
39 | padding-left: 5px;
40 | padding-right: 5px;
41 |
42 | margin-top: -13px;
43 | margin-right: 20px;
44 |
45 | position: fixed;
46 | right: 0;
47 |
48 | cursor: pointer;
49 | z-index: 9;
50 | }
51 |
52 | .codenav_scroll_indicator {
53 | width: 10px;
54 |
55 | vertical-align: top;
56 | text-align: right;
57 |
58 | line-height: 1;
59 | float: right;
60 | margin-top: 3px;
61 | margin-bottom: 3px;
62 |
63 | top: 45px;
64 | right: 12px;
65 | position: absolute;
66 |
67 | z-index: 999999;
68 | }
69 |
70 | .codenav_scroll_indicator_mark {
71 | position: absolute;
72 |
73 | background-color: #ffa;
74 | border: 1px solid #909090;
75 | width: 10px;
76 | height: 8px;
77 |
78 | float: right;
79 |
80 | cursor: pointer;
81 | }
82 |
83 | #codenav_search_results h1 {
84 | text-align:center;
85 | }
86 |
87 | #codenav_search_summary {
88 | margin-top: -16px;
89 | }
90 |
91 | #codenav_search_drag {
92 | cursor: row-resize;
93 | height: 4px;
94 | background-color: #ccc;
95 | margin: 0;
96 | padding: 0;
97 | width: 100%;
98 |
99 | position: fixed;
100 | bottom: 300px; /* see preferred_search_box_height in js */
101 |
102 | z-index: 999999;
103 | }
104 |
--------------------------------------------------------------------------------
/src/inject.js:
--------------------------------------------------------------------------------
1 | var $ = window.jQuery;
2 | var cfg = {};
3 | var fns = {};
4 |
5 | $(function() {
6 | run();
7 |
8 | // Silly detection for pushstate changes
9 | var lastloc = window.location.pathname;
10 | setInterval(function() {
11 | if (lastloc != window.location.pathname) {
12 | setTimeout(run, 300);
13 | lastloc = window.location.pathname;
14 | }
15 | }, 100);
16 | });
17 |
18 | function run() {
19 | setup_config();
20 | setup_code_highlighting();
21 | setup_scroll_bar();
22 | setup_search();
23 | setup_scroll_bar_positioning();
24 |
25 | setTimeout(function() {
26 | $(window).trigger('scroll.codenav');
27 | }, 100);
28 | }
29 |
30 | function is_code_page() {
31 | return $('#LC1').length > 0;
32 | }
33 |
34 | function setup_config() {
35 | // eg. /typpo/asterank
36 | cfg.repo_home_link = window.location.pathname.split('/').slice(0, 3).join('/');
37 | cfg.original_scroll_pos = $(window).scrollTop();
38 |
39 | cfg.$code_body = $('.js-file-line-container');
40 |
41 | var font_size = cfg.$code_body.css('font-size');
42 | cfg.line_height = font_size ? Math.floor(parseInt(font_size.replace('px','')) * 1.5) : 19;
43 | }
44 |
45 | function wrap_text_nodes_in_span($container) {
46 | $container.find('*').contents().filter(function() {
47 | return this.nodeType == Node.TEXT_NODE;
48 | }).wrap('');
49 | }
50 |
51 | function get_token_from_elt($elt) {
52 | var tok = $elt.text();
53 | if (!tok && $elt.length > 0) {
54 | // elt is a text node.
55 | tok = $elt[0].nodeValue;
56 | }
57 | var token_regexp = /[a-zA-Z_\-\$]+/g;
58 | var matches = token_regexp.exec(tok);
59 | if (matches && matches.length > 0) {
60 | return matches[0];
61 | }
62 | return null;
63 | }
64 |
65 | function setup_code_highlighting() {
66 | var token_index = {};
67 |
68 | cfg.$code_body.addClass('codenav_word_split');
69 |
70 | // Necessary because you can't bind events to text nodes.
71 | wrap_text_nodes_in_span(cfg.$code_body);
72 |
73 | // Build the index on startup
74 | cfg.$code_body.find('td').contents().each(function() {
75 | var $this = $(this);
76 | var tok = get_token_from_elt($this);
77 | if (!tok || /^[ ,\(\)\.\\\/\[\]\{\}\'\"\:\;\+]*$/.test(tok)) {
78 | return;
79 | }
80 |
81 | if (!(token_index[tok] instanceof Array)) {
82 | token_index[tok] = [];
83 | }
84 | var token_list = token_index[tok];
85 | token_list.push($this);
86 | });
87 |
88 | // omit comments and such
89 | cfg.$code_body.find('.c,.c1').addClass('codenav_ignore');
90 |
91 | // TODO(ian): Bind all events efficiently to container, not individual elements.
92 | // Click behavior
93 | cfg.$code_body.find('td').contents().on('click', function() {
94 | var $this = $(this);
95 | if ($this.hasClass('codenav_ignore')) {
96 | return;
97 | }
98 | cfg.$code_body.find('.codenav_highlight_sticky').removeClass('codenav_highlight_sticky');
99 | var tok_from_elt = get_token_from_elt($this);
100 | var tokens = token_index[tok_from_elt];
101 | if (!tokens) {
102 | // This token wasn't indexed.
103 | return;
104 | }
105 | for (var i=0; i < tokens.length; i++) {
106 | tokens[i].addClass('codenav_highlight_sticky');
107 | }
108 | });
109 |
110 | // Hover behavior
111 | cfg.$code_body.find('td').contents().hover(function() {
112 | var $this = $(this);
113 | if ($this.hasClass('codenav_ignore')) {
114 | return;
115 | }
116 |
117 | // Unhighlight existing
118 | cfg.$code_body.find('.codenav_highlight').removeClass('codenav_highlight');
119 |
120 | // Then highlight
121 | var tok = get_token_from_elt($this);
122 | var tokens = token_index[tok];
123 | if (!tokens) {
124 | // We didn't index this token
125 | return;
126 | }
127 | fns.codenav_clear_marks();
128 | for (var i=0; i < tokens.length; i++) {
129 | var $tok = tokens[i];
130 | $tok.addClass('codenav_highlight');
131 | var lineno = parseInt($tok.closest('td').attr('id').slice(2), 10);
132 | fns.codenav_mark_line(lineno, $tok);
133 | }
134 | }, function() {
135 | });
136 | }
137 |
138 | function scroll_to_lineno(n) {
139 | var $bwrapper = $('.blob-wrapper');
140 | var $lineelt = $('#LC' + n);
141 | var linepos = $lineelt.offset().top;
142 | var margin = Math.round($lineelt.height() / 3);
143 | $('html, body').animate({ scrollTop: (linepos - margin)});
144 | }
145 |
146 | // As we scroll past the top of the file code container, attach the line marker container to be
147 | // fixed in the viewport (& reset it to be contained in the file container if we scroll back up.)
148 | function setup_scroll_bar_positioning() {
149 | // This function is called on pjax page loads (where the window object persists but the page
150 | // content changes), so first unregister any old window event handlers before adding new ones
151 | $(window)
152 | .off('scroll.codenav')
153 | .off('resize.codenav');
154 |
155 | if(!is_code_page()) {
156 | return;
157 | }
158 |
159 | var $bwrapper = $('.blob-wrapper');
160 | var $scrollindicator = $('.codenav_scroll_indicator');
161 |
162 | // Cache the current 'position' attribute of $scrollindicator to save a CSS lookup/set each scroll
163 | var last_position = null;
164 |
165 | // On page scroll, check if the $scrollindicator container holding our line markings should be
166 | // attached to its parent like a normal element, or fixed in the viewport as we scroll down
167 | $(window).on('scroll.codenav', function() {
168 | var amount_scrolled_below_top_of_bwrapper = $(window).scrollTop() - $bwrapper.offset().top;
169 | var amount_scrolled_below_bottom_of_bwrapper = amount_scrolled_below_top_of_bwrapper +
170 | $(window).height() - $bwrapper.height();
171 |
172 | if(amount_scrolled_below_top_of_bwrapper > 0) {
173 | // If we've scrolled past the top of the code blob container, fix $scrollindicator to viewport
174 | if (last_position !== 'fixed') { // Only update CSS attributes if not already set correctly
175 | $scrollindicator
176 | .css('position', 'fixed')
177 | // We don't need to add padding for the file header bar because it's scrolled offscreen
178 | // at this point
179 | .css('top', '0px')
180 | .css('left', Math.round($bwrapper.offset().left + $bwrapper.width() - 7) + 'px');
181 |
182 | last_position = 'fixed';
183 | }
184 | } else {
185 | // If we're above the top of the code blob container, attach $scrollindicator to it
186 | if (last_position !== 'absolute') {
187 | $scrollindicator
188 | .css('position', 'absolute')
189 | // We add 45px of padding above it to account for the file header info/actions bar
190 | .css('top', '45px')
191 | .css('left', 'auto');
192 |
193 | last_position = 'absolute';
194 | }
195 | }
196 |
197 | if (amount_scrolled_below_bottom_of_bwrapper > 0) {
198 | $scrollindicator.height($(window).innerHeight() - amount_scrolled_below_bottom_of_bwrapper);
199 | } else {
200 | $scrollindicator.height($(window).innerHeight());
201 | }
202 | })
203 |
204 | // We resize the $scrollindicator container to be the visible height of the blob wrapper
205 | $(window).on('resize.codenav', function() {
206 | $scrollindicator.height($(window).innerHeight());
207 | $(window).trigger('scroll.codenav');
208 | });
209 | }
210 |
211 | function setup_scroll_bar() {
212 | // Manual width is to fix firefox problem.
213 | var $scrollindicator = $('')
214 | .appendTo($('.js-file-line-container').parent());
215 | var $bwrapper = $('.blob-wrapper');
216 |
217 | var total_num_lines = $('.js-line-number').length; // total lines in file
218 |
219 | var did_set_border = false;
220 |
221 | // Define marking functions.
222 | fns.codenav_mark_line = function(n, $elt) {
223 | // Reset height to handle resize
224 | var $bwrapper = $('.blob-wrapper');
225 | $scrollindicator.height(Math.min($(window).innerHeight(), $bwrapper.height()));
226 |
227 | if(!did_set_border) {
228 | $bwrapper.css('border-right', '14px solid rgba(0, 0, 0, 0.04)');
229 | did_set_border = true;
230 | }
231 |
232 | // Compute marker position
233 | var height;
234 | if ($('body').height() > $(window).height()) {
235 | // Has scroll bar.
236 | height = Math.round((n/total_num_lines) * 100) + '%';
237 | } else {
238 | // Handle the special case where the document fits within the entire window.
239 | height = (cfg.line_height * n - 20) + 'px';
240 | }
241 |
242 | var $mark = $('')
243 | .appendTo($scrollindicator)
244 | .css('top', height)
245 | // Fix positioning if code is horizontally scrollable
246 | //.css('margin-left', -1*Math.max(0, $fcode.width() - 920 + 11))
247 | .on('click', function() {
248 | // Note this doesn't handle resize between setup and click.
249 | scroll_to_lineno(n);
250 | // remove green sticky things; the user has clicked on something new.
251 | $('.codenav_highlight_sticky').removeClass('codenav_highlight_sticky');
252 | $elt.addClass('codenav_highlight_sticky');
253 | });
254 | }
255 |
256 | fns.codenav_clear_marks = function() {
257 | $('.codenav_scroll_indicator_mark').remove();
258 | }
259 | }
260 |
261 | var $prevdiv = null;
262 | function setup_search() {
263 | cfg.$code_body.find('span').on('click', function() {
264 | var $this = $(this);
265 | if ($this.hasClass('codenav_ignore')) {
266 | return;
267 | }
268 | var query = $this.text();
269 | var url = 'https://github.com' + cfg.repo_home_link + '/search?utf8=✓&type=Code&q=' + query;
270 |
271 | var $div = $(SEARCH_DIV).appendTo('body');
272 | if ($prevdiv) {
273 | $prevdiv.remove();
274 | }
275 | $prevdiv = $div;
276 |
277 | setup_search_dragbar();
278 | var $search_content = $div.find('#codenav_search_content');
279 |
280 | // Run github search and extract results into codenav div
281 | $.get(url, function(data) {
282 | var $data = $(data);
283 | var $results = $data.find('#code_search_results');
284 | if ($results.length === 0) {
285 | $search_content.empty().append('