├── icon_ex.png
├── img
└── se_logo.png
├── screenshots
├── main.png
├── promo.png
├── main_v2.png
├── promo2.png
├── promo3.png
├── results.jpg
├── full_page.png
├── results2.jpg
├── results3.jpg
├── results4.jpg
└── results5.jpg
├── css
├── custom.css
├── fonts
│ ├── FontAwesome.otf
│ ├── fontawesome-webfont.eot
│ ├── fontawesome-webfont.ttf
│ ├── fontawesome-webfont.woff
│ └── fontawesome-webfont.woff2
├── default.min.css
├── background.css
└── font-awesome.css
├── js
├── login_success.js
├── popup.js
├── options.js
├── lib
│ ├── stack_exchnage.js
│ ├── tracker.js
│ ├── utils.js
│ ├── stack-exchange-wrapper.js
│ ├── analytics.js
│ └── highlight.min.js
├── background.js
└── answers_manager.js
├── html
├── background.html
├── options.html
└── popups.html
├── LICENSE.md
├── ReadMe.md
└── manifest.json
/icon_ex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirdor/stack-search/HEAD/icon_ex.png
--------------------------------------------------------------------------------
/img/se_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirdor/stack-search/HEAD/img/se_logo.png
--------------------------------------------------------------------------------
/screenshots/main.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirdor/stack-search/HEAD/screenshots/main.png
--------------------------------------------------------------------------------
/screenshots/promo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirdor/stack-search/HEAD/screenshots/promo.png
--------------------------------------------------------------------------------
/screenshots/main_v2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirdor/stack-search/HEAD/screenshots/main_v2.png
--------------------------------------------------------------------------------
/screenshots/promo2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirdor/stack-search/HEAD/screenshots/promo2.png
--------------------------------------------------------------------------------
/screenshots/promo3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirdor/stack-search/HEAD/screenshots/promo3.png
--------------------------------------------------------------------------------
/screenshots/results.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirdor/stack-search/HEAD/screenshots/results.jpg
--------------------------------------------------------------------------------
/css/custom.css:
--------------------------------------------------------------------------------
1 |
2 | body, section {
3 | width: 350px;
4 | height: 250px;
5 | overflow-x: hidden;
6 | }
--------------------------------------------------------------------------------
/css/fonts/FontAwesome.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirdor/stack-search/HEAD/css/fonts/FontAwesome.otf
--------------------------------------------------------------------------------
/screenshots/full_page.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirdor/stack-search/HEAD/screenshots/full_page.png
--------------------------------------------------------------------------------
/screenshots/results2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirdor/stack-search/HEAD/screenshots/results2.jpg
--------------------------------------------------------------------------------
/screenshots/results3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirdor/stack-search/HEAD/screenshots/results3.jpg
--------------------------------------------------------------------------------
/screenshots/results4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirdor/stack-search/HEAD/screenshots/results4.jpg
--------------------------------------------------------------------------------
/screenshots/results5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirdor/stack-search/HEAD/screenshots/results5.jpg
--------------------------------------------------------------------------------
/css/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirdor/stack-search/HEAD/css/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/css/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirdor/stack-search/HEAD/css/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/css/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirdor/stack-search/HEAD/css/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/css/fonts/fontawesome-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirdor/stack-search/HEAD/css/fonts/fontawesome-webfont.woff2
--------------------------------------------------------------------------------
/js/login_success.js:
--------------------------------------------------------------------------------
1 | // Example of hash: #access_token=ZxqGlCmJzvrr99D(9dcEwA))&state=3&expires=86400
2 | var token = location.hash.match(/\baccess_token=([^&]+)/);
3 | var account_id = document.querySelector('a[href*="/users/"]');
4 | if (account_id) {
5 | account_id = account_id.getAttribute('href').match(/\d+/)[0];
6 | }
7 | chrome.runtime.sendMessage({
8 | auth_token: token && token[1],
9 | account_id: account_id
10 | });
--------------------------------------------------------------------------------
/html/background.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Stack Search
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/css/default.min.css:
--------------------------------------------------------------------------------
1 | .hljs{display:block;overflow-x:auto;padding:0.5em;background:#F0F0F0}.hljs,.hljs-subst{color:#444}.hljs-comment{color:#888888}.hljs-keyword,.hljs-attribute,.hljs-selector-tag,.hljs-meta-keyword,.hljs-doctag,.hljs-name{font-weight:bold}.hljs-type,.hljs-string,.hljs-number,.hljs-selector-id,.hljs-selector-class,.hljs-quote,.hljs-template-tag,.hljs-deletion{color:#880000}.hljs-title,.hljs-section{color:#880000;font-weight:bold}.hljs-regexp,.hljs-symbol,.hljs-variable,.hljs-template-variable,.hljs-link,.hljs-selector-attr,.hljs-selector-pseudo{color:#BC6060}.hljs-literal{color:#78A960}.hljs-built_in,.hljs-bullet,.hljs-code,.hljs-addition{color:#397300}.hljs-meta{color:#1f7199}.hljs-meta-string{color:#4d99bf}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:bold}
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Dor Amir
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/css/background.css:
--------------------------------------------------------------------------------
1 | @keyframes thingy {
2 | 0% {
3 | transform: scale(0.6);
4 | }
5 | 45% {
6 | transform: scale(1);
7 | }
8 | 65% {
9 | transform: scale(1);
10 | }
11 | 100% {
12 | transform: scale(0.6);
13 | }
14 | }
15 | /*.wrapper {
16 | padding: 15px;
17 | }*/
18 |
19 | ._loader_:before {
20 | content: '';
21 | background-color: #262626;
22 | display: inline-block;
23 | height: 15px;
24 | width: 15px;
25 | border-radius: 50%;
26 | animation: thingy 1s ease-in-out .33s infinite;
27 | }
28 | ._loader_ div {
29 | background-color: #262626;
30 | display: inline-block;
31 | width: 150px;
32 | height: 15px;
33 | width: 15px;
34 | margin: 0 5px;
35 | border-radius: 50%;
36 | animation: thingy 1s ease-in-out .66s infinite;
37 | }
38 | ._loader_:after {
39 | content: '';
40 | background-color: #262626;
41 | display: inline-block;
42 | height: 15px;
43 | width: 15px;
44 | border-radius: 50%;
45 | animation: thingy 1s ease-in-out .99s infinite;
46 | }
47 | ._loader_ {
48 | width: 60px;
49 | position: absolute;
50 | top: 0;
51 | bottom: 0;
52 | left: 0;
53 | right: 0;
54 | margin: auto;
55 | }
56 | #stack_link_title{
57 | color: #504f4f;
58 | text-decoration: underline;
59 | }
--------------------------------------------------------------------------------
/js/popup.js:
--------------------------------------------------------------------------------
1 | window.app = window.app || {};
2 | var bg = chrome.extension.getBackgroundPage();
3 |
4 | window.addEventListener('load', _onLoad);
5 |
6 | function trackButton(e) {
7 | app.TRACKER.event('event', e.id, 'popup', 'clicked');
8 | };
9 | StackExchangeWrapper.auth.getToken()
10 |
11 | function _onLoad() {
12 | app.TRACKER.page('popups.html');
13 | $('.btn_an').click(function() {
14 | trackButton($(this)[0])
15 | });
16 | app.Utils.restore_options();
17 | chrome.storage.sync.get(null, function(items) {
18 | if (items['se_auth_token'] && items['se_auth_token'] != '') {
19 | app.Utils.login_success();
20 | } else {
21 | app.Utils.logout_success();
22 | }
23 | });
24 |
25 | }
26 | classname = document.getElementsByClassName("options")
27 | for (var i = 0; i < classname.length; i++) {
28 | classname[i].addEventListener("change", app.Utils.save_options);
29 | }
30 |
31 | document.getElementById('open_options').addEventListener('click', function() {
32 | chrome.tabs.create({
33 | 'url': 'chrome://extensions/?options=' + chrome.runtime.id
34 | });
35 | })
36 |
37 | document.getElementById('register').addEventListener('click', function() {
38 | StackExchangeWrapper.auth.requestToken();
39 | })
40 | document.getElementById('logout').addEventListener('click', function() {
41 | StackExchangeWrapper.auth.deactivate();
42 | })
--------------------------------------------------------------------------------
/js/options.js:
--------------------------------------------------------------------------------
1 | window.app = window.app || {};
2 |
3 | window.addEventListener('load', _onLoad);
4 | StackExchangeWrapper.auth.getToken()
5 |
6 | function _onLoad() {
7 | app.TRACKER.page('options.html');
8 | $('.btn_an').click(function() {
9 | trackButton($(this)[0])
10 | });
11 |
12 | chrome.storage.sync.get(null, function(items) {
13 | if (items['se_auth_token'] && items['se_auth_token'] != '') {
14 | app.Utils.login_success();
15 | } else {
16 | app.Utils.logout_success();
17 | }
18 | });
19 | }
20 |
21 | function trackButton(e) {
22 | app.TRACKER.event('event', e.id, 'options', 'clicked');
23 | };
24 |
25 | function click_answers() {
26 | var answers = document.getElementById('answers').checked;
27 | app.TRACKER.event('event', 'show_answers', answers + "", 'clicked')
28 | if (answers) {
29 | document.getElementById('answer_color').disabled = false;
30 | } else {
31 | document.getElementById('answer_color').disabled = true;
32 | }
33 | }
34 |
35 | document.addEventListener('DOMContentLoaded', app.Utils.restore_options);
36 | document.getElementById('reset').addEventListener('click', app.Utils.reset_options);
37 | document.getElementById('save').addEventListener('click', app.Utils.save_options);
38 | document.getElementById("answers").addEventListener("change", click_answers);
39 | document.getElementById('register').addEventListener('click', function() {
40 | StackExchangeWrapper.auth.requestToken();
41 | })
42 | document.getElementById('logout').addEventListener('click', function() {
43 | StackExchangeWrapper.auth.deactivate();
44 | })
--------------------------------------------------------------------------------
/ReadMe.md:
--------------------------------------------------------------------------------
1 | # Stack Search
2 |
3 | Stack Search is the chrome extension you’ve always dreamed of!
4 |
5 | Stack Search adds to your Google Search results a filtered set of the most relevant answers from your top trusted coding sources: StackOverflow and StackExchange. These results are displayed on the right-hand side of the Google SERP, along with links to reach the exact source of the chosen answer.
6 |
7 | Additionally, the extension displays the amount of answers available under each StackOverflow and StackExchange organic search result, along with a score for the answer and whether the latter has been accepted as reliable.
8 |
9 | A quick install will change the way you search for coding help forever! It doesn’t take space nor makes the SERP loading time slower.
10 |
11 | I hope you enjoy it and please, share it and leave comments for further improvements!
12 |
13 | What's new in version 2
14 | fix issue with change html tags on stackoverflow
15 |
16 | Stack Search was created by [Dor Amir](mailto:amirdor@gmail.com)
17 |
18 | ### Version
19 | 2.0.0
20 |
21 | ### Installation
22 | Via Chrome browser, click on the link below
23 |
24 | [Chrome extension store]( https://chrome.google.com/webstore/detail/stack-search/mmbkjfdlhegphofeodeinpbcifaobacl?utm_source=github&utm_medium=readme)
25 |
26 | Then, click on **"ADD TO CHROME"**
27 |
28 | ### Getting started
29 | Search on Google, if the results will include any questions on stackoverflow you will get the enricment that **Stack Search** will give.
30 |
31 | ### Results
32 | 
33 |
34 |
35 | 
36 |
37 |
38 | 
39 |
40 |
41 | 
42 |
43 | License
44 | ----
45 |
46 | **Free Software, Hell Yeah!**
47 |
--------------------------------------------------------------------------------
/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Stack Search",
3 | "description": "Stack Search adds to your Google Search results answers from: StackOverflow and StackExchange sites.",
4 | "version": "2.2.0",
5 | "short_name": "Stack Search",
6 | "content_security_policy": "script-src 'self' https://www.google-analytics.com/; object-src 'self'",
7 | "minimum_chrome_version": "40",
8 | "background": {
9 | "run_at": "document_end",
10 | "page": "html/background.html",
11 | "js": ["js/lib/analytics.js", "js/lib/tracker.js", "js/answers_manager.js", "js/background.js"],
12 | "persistent": false
13 | },
14 | "options_ui": {
15 | "page": "html/options.html",
16 | "chrome_style": true
17 | },
18 | "content_scripts": [{
19 | "run_at": "document_end",
20 | "js": ["js/lib/jquery.js", "js/lib/highlight.min.js", "js/lib/analytics.js", "js/lib/stack_exchnage.js", "js/lib/stack-exchange-wrapper.js", "js/lib/utils.js", "js/lib/tracker.js", "js/answers_manager.js", "js/background.js"],
21 | "css": ["css/font-awesome.css", "css/bootstrap.css", "css/background.css", "css/default.min.css"],
22 | "matches": ["*://*/*"],
23 | "include_globs": ["*://www.google.*/*", "*://google.*/*"]
24 | }, {
25 | "matches": ["https://stackexchange.com/oauth/login_success?robw&*"],
26 | "run_at": "document_end",
27 | "js": ["js/login_success.js"],
28 | "all_frames": true
29 | }],
30 | "optional_permissions": [
31 | "background", "tabs"
32 | ],
33 | "browser_action": {
34 | "default_title": "Stack Search",
35 | "default_icon": "icon_ex.png",
36 | "default_popup": "html/popups.html"
37 | },
38 | "web_accessible_resources": ["css/fonts/*.*", "*.ttf", "*.eot", "*.svg", "*.woff", "*.woff2"],
39 | "author": "dor amir",
40 | "permissions": ["https://api.stackexchange.com/2.2/*", "storage", "tabs"],
41 | "manifest_version": 2,
42 | "icons": {
43 | "16": "icon_ex.png",
44 | "48": "icon_ex.png",
45 | "128": "icon_ex.png"
46 | }
47 | }
--------------------------------------------------------------------------------
/html/options.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Stack Search | Options
6 |
7 |
8 |
9 |
13 |
14 |
18 |
19 | Answers color:
20 |
21 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
Get more features!
33 |
34 |
35 |
36 |
37 |
38 |
You are connected :) Yay!
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/js/lib/stack_exchnage.js:
--------------------------------------------------------------------------------
1 | window.SE=function(e){"use strict";function t(e,t){var r=e[t];if(!r)throw t+" required";return r}function r(e){if(!e)throw g;var r=t(e,"clientId"),o=t(e,"channelUrl"),n=t(e,"complete"),d=window.location.protocol,w=d.substring(0,d.length-1),u=(d+"//"+window.location.host).toLowerCase();if(c=t(e,"key"),i=r,a=o,0!==a.toLowerCase().indexOf(u))throw"channelUrl must be under the current domain";s=h+"/oauth/dialog?redirect_uri="+l(h+"/oauth/login_success?assisted="+r+"&protocol="+w+"&proxy="+l(a)),setTimeout(function(){n({"version":"26039"})})}function o(t,r,o,n){for(var i,s="sec"+u++,a=m,d=function(a){return window[s]=e,i.parentNode.removeChild(i),a.error_id?(n({"errorName":a.error_name,"errorMessage":a.error_message}),void 0):(o({"accessToken":t,"expirationDate":r,"networkUsers":a.items}),void 0)};window[s]||w.getElementById(s);)s="sec"+u++;window[s]=d,a+="?pagesize=100&access_token="+l(t)+"&key="+l(c)+"&callback="+l(s),i=w.createElement("script"),i.type="text/javascript",i.src=a,i.id=s,w.getElementsByTagName("head")[0].appendChild(i)}function n(e){if(!e)throw g;var r,n,a,c,w,m=t(e,"success"),f=e.scope,v="",k=u++,x=s+"&client_id="+i+"&state="+k,y=e.error;if(f&&"[object Array]"!==Object.prototype.toString.call(f))throw"scope must be an Array";f&&(v=f.join(" ")),v.length>0&&(x+="&scope="+l(v)),c=function(t){if(t.origin===h&&t.source===a){var n,i,s,d,w=t.data.substring(1).split("&"),l={};for(s=0;s[^<]*<\/a>/;
10 | const regex = /[^<]*<\/a>/;
11 |
12 |
13 | f = true
14 |
15 | app.TRACKER.page('background.js');
16 | /* MutationObserver configuration data: Listen for "childList"
17 | /* Traverse 'rootNode' and its descendants and modify '' tags */
18 | function modifyLinks(rootNode) {
19 | answers_div = [];
20 | app.g_stack_link_count = 0;
21 | var nodes = [rootNode];
22 | while (nodes.length > 0) {
23 | var node = nodes.shift();
24 | if (node.tagName == "A") {
25 | /* Modify the '' element */
26 | if (app.Utils.valid_link(node)) {
27 | href = node.href.replace('http://', 'https://');
28 | app.g_stack_link_count += 1;
29 | if (f) {
30 | var elem = document.createElement('div')
31 | elem.className = "_loader_";
32 | elem.id = 'typingLoad';
33 | elem.innerHTML = ""
34 | $('#rhs').append(elem)
35 | f = false
36 | }
37 | app.ANSWERS.show_answers(node, href);
38 | }
39 | } else {
40 | /* If the current node has children, queue them for further
41 | * processing, ignoring any '
65 |
66 |
67 |
68 |
69 |
70 |
71 |