├── .nvmrc ├── src ├── assets │ ├── .gitkeep │ └── img │ │ ├── add.png │ │ ├── go.png │ │ ├── config.png │ │ ├── github.png │ │ └── qrcode.jpg ├── favicon.ico ├── environments │ ├── environment.prod.ts │ └── environment.ts ├── app │ ├── base-view.ts │ ├── app-routing.module.ts │ ├── components │ │ ├── mssearch-box │ │ │ ├── mssearch-box.component.html │ │ │ ├── mssearch-box.component.scss │ │ │ └── mssearch-box.component.ts │ │ └── msiframe │ │ │ ├── msiframe.component.scss │ │ │ ├── msiframe.component.html │ │ │ └── msiframe.component.ts │ ├── MSConfig.ts │ ├── msservice.service.ts │ ├── app.module.ts │ ├── app.component.html │ ├── app.component.scss │ └── app.component.ts ├── styles.scss ├── tsconfig.app.json ├── tsconfig.spec.json ├── tslint.json ├── browserslist ├── main.ts ├── index.html ├── test.ts ├── karma.conf.js └── polyfills.ts ├── qrcode.jpg ├── show.jpg ├── imgs ├── 20011101.png ├── 20011102.png ├── 20011103.png ├── 20011104.png ├── 20011105.png ├── 20011106.png ├── 20011107.png ├── 20011108.png ├── 20011109.png ├── 20011110.png └── 20011201.png ├── e2e ├── src │ ├── app.po.ts │ └── app.e2e-spec.ts ├── tsconfig.e2e.json └── protractor.conf.js ├── .editorconfig ├── tsconfig.json ├── how-use.md ├── .gitignore ├── how-to-use-old.md ├── README.md ├── package.json ├── tslint.json └── angular.json /.nvmrc: -------------------------------------------------------------------------------- 1 | 12.14.0 2 | -------------------------------------------------------------------------------- /src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qrcode.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feige2/MoreSearch/HEAD/qrcode.jpg -------------------------------------------------------------------------------- /show.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feige2/MoreSearch/HEAD/show.jpg -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feige2/MoreSearch/HEAD/src/favicon.ico -------------------------------------------------------------------------------- /imgs/20011101.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feige2/MoreSearch/HEAD/imgs/20011101.png -------------------------------------------------------------------------------- /imgs/20011102.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feige2/MoreSearch/HEAD/imgs/20011102.png -------------------------------------------------------------------------------- /imgs/20011103.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feige2/MoreSearch/HEAD/imgs/20011103.png -------------------------------------------------------------------------------- /imgs/20011104.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feige2/MoreSearch/HEAD/imgs/20011104.png -------------------------------------------------------------------------------- /imgs/20011105.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feige2/MoreSearch/HEAD/imgs/20011105.png -------------------------------------------------------------------------------- /imgs/20011106.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feige2/MoreSearch/HEAD/imgs/20011106.png -------------------------------------------------------------------------------- /imgs/20011107.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feige2/MoreSearch/HEAD/imgs/20011107.png -------------------------------------------------------------------------------- /imgs/20011108.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feige2/MoreSearch/HEAD/imgs/20011108.png -------------------------------------------------------------------------------- /imgs/20011109.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feige2/MoreSearch/HEAD/imgs/20011109.png -------------------------------------------------------------------------------- /imgs/20011110.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feige2/MoreSearch/HEAD/imgs/20011110.png -------------------------------------------------------------------------------- /imgs/20011201.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feige2/MoreSearch/HEAD/imgs/20011201.png -------------------------------------------------------------------------------- /src/assets/img/add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feige2/MoreSearch/HEAD/src/assets/img/add.png -------------------------------------------------------------------------------- /src/assets/img/go.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feige2/MoreSearch/HEAD/src/assets/img/go.png -------------------------------------------------------------------------------- /src/assets/img/config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feige2/MoreSearch/HEAD/src/assets/img/config.png -------------------------------------------------------------------------------- /src/assets/img/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feige2/MoreSearch/HEAD/src/assets/img/github.png -------------------------------------------------------------------------------- /src/assets/img/qrcode.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feige2/MoreSearch/HEAD/src/assets/img/qrcode.jpg -------------------------------------------------------------------------------- /src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /src/app/base-view.ts: -------------------------------------------------------------------------------- 1 | export abstract class BaseView { 2 | public viewData: VD; 3 | 4 | protected constructor(viewData: VD) { 5 | this.viewData = viewData; 6 | } 7 | 8 | } 9 | -------------------------------------------------------------------------------- /src/styles.scss: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | 3 | html, body { 4 | width: 100%; 5 | height: 100%; 6 | margin: 0 0; 7 | padding: 0 0; 8 | } 9 | -------------------------------------------------------------------------------- /src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "types": [] 6 | }, 7 | "exclude": [ 8 | "src/test.ts", 9 | "**/*.spec.ts" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | getParagraphText() { 9 | return element(by.css('MS-root h1')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types": [ 8 | "jasmine", 9 | "jasminewd2", 10 | "node" 11 | ] 12 | } 13 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | 4 | const routes: Routes = []; 5 | 6 | @NgModule({ 7 | imports: [RouterModule.forRoot(routes)], 8 | exports: [RouterModule] 9 | }) 10 | export class AppRoutingModule { } 11 | -------------------------------------------------------------------------------- /src/app/components/mssearch-box/mssearch-box.component.html: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "test.ts", 12 | "polyfills.ts" 13 | ], 14 | "include": [ 15 | "**/*.spec.ts", 16 | "**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /src/app/MSConfig.ts: -------------------------------------------------------------------------------- 1 | export class MSConfig { 2 | static baidu = 'https://www.baidu.com/s?wd={query}'; 3 | static google = 'https://www.google.com/search?q={query}'; 4 | static v2ex = 'https://www.google.com/search?q=site:v2ex.com/t {query}'; 5 | static zhihu = 'https://www.zhihu.com/search?type=content&q={query}'; 6 | static juejin = 'https://juejin.im/search?query={query}'; 7 | } 8 | -------------------------------------------------------------------------------- /e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | 3 | describe('workspace-project App', () => { 4 | let page: AppPage; 5 | 6 | beforeEach(() => { 7 | page = new AppPage(); 8 | }); 9 | 10 | it('should display welcome message', () => { 11 | page.navigateTo(); 12 | expect(page.getParagraphText()).toEqual('Welcome to MoreSearch!'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /src/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tslint.json", 3 | "rules": { 4 | "directive-selector": [ 5 | true, 6 | "attribute", 7 | "MS", 8 | "camelCase" 9 | ], 10 | "component-selector": [ 11 | true, 12 | "element", 13 | "MS", 14 | "kebab-case" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/browserslist: -------------------------------------------------------------------------------- 1 | # This file is currently used by autoprefixer to adjust CSS to support the below specified browsers 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | # For IE 9-11 support, please uncomment the last line of the file and adjust as needed 5 | > 0.5% 6 | last 2 versions 7 | Firefox ESR 8 | not dead 9 | # IE 9-11 -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.log(err)); 13 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "module": "es2015", 9 | "moduleResolution": "node", 10 | "emitDecoratorMetadata": true, 11 | "experimentalDecorators": true, 12 | "target": "es5", 13 | "typeRoots": [ 14 | "node_modules/@types" 15 | ], 16 | "lib": [ 17 | "es2017", 18 | "dom" 19 | ] 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /how-use.md: -------------------------------------------------------------------------------- 1 | 2 | 说明:Fork了[iHeader项目](https://github.com/xuefengnice/IHeader),并扩展,**安装即用**。 3 | 4 | ps. 时间有限,代码未整理,只为快速适配猫搜。会添加一条All listener的适配所有URL的规则,以去除X-Frame-Options响应头。 5 | 6 | ~~老版本使用说明,[参见这里](https://github.com/xuefengnice/MoreSearch/blob/master/how-to-use-old.md)。~~ 7 | 8 | # 如何安装 9 | 10 | 1. 克隆iHeader项目到你本地 11 | 12 | ```shell 13 | git clone https://github.com/xuefengnice/IHeader.git 14 | ``` 15 | 16 | 2. 使用chrome开发者模式加载此插件**根目录**(加载已解压的扩展程序)即可。 17 | 18 | ![](./imgs/20011102.png) 19 | 20 | ![](./imgs/20011201.png) -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 聚合搜索引擎 | 猫搜一下,你就知道更多。 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/app/components/mssearch-box/mssearch-box.component.scss: -------------------------------------------------------------------------------- 1 | 2 | .ms-search-box { 3 | 4 | $w_box: 40%; 5 | 6 | display: flex; 7 | justify-content: center; 8 | align-items: center; 9 | width: $w_box; 10 | min-width: 200px; 11 | border-radius: 4px; 12 | margin: 0 auto; 13 | 14 | .img-search { 15 | width: 50px; 16 | height: 50px; 17 | } 18 | 19 | .input-search { 20 | width: 0; 21 | height: 38px; 22 | flex: 1; 23 | font-size: 18px; 24 | } 25 | input:focus { 26 | outline-width: 2px; 27 | } 28 | 29 | .btn-search { 30 | height: 45px; 31 | font-size: 14px; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | yarn-error.log 34 | testem.log 35 | /typings 36 | 37 | # System Files 38 | .DS_Store 39 | Thumbs.db 40 | -------------------------------------------------------------------------------- /src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build ---prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * In development mode, to ignore zone related error stack frames such as 11 | * `zone.run`, `zoneDelegate.invokeTask` for easier debugging, you can 12 | * import the following file, but please comment it out in production mode 13 | * because it will have performance impact when throw error 14 | */ 15 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI. 16 | -------------------------------------------------------------------------------- /src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: any; 11 | 12 | // First, initialize the Angular testing environment. 13 | getTestBed().initTestEnvironment( 14 | BrowserDynamicTestingModule, 15 | platformBrowserDynamicTesting() 16 | ); 17 | // Then we find all the tests. 18 | const context = require.context('./', true, /\.spec\.ts$/); 19 | // And load the modules. 20 | context.keys().map(context); 21 | -------------------------------------------------------------------------------- /e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './src/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | onPrepare() { 23 | require('ts-node').register({ 24 | project: require('path').join(__dirname, './tsconfig.e2e.json') 25 | }); 26 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 27 | } 28 | }; -------------------------------------------------------------------------------- /src/app/msservice.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core'; 2 | import {MSIframeComponent} from './components/msiframe/msiframe.component'; 3 | import {HttpClient} from '@angular/common/http'; 4 | 5 | @Injectable({ 6 | providedIn: 'root' 7 | }) 8 | export class MSServiceService { 9 | private browsers: MSIframeComponent[] = []; 10 | 11 | constructor(public httpClient: HttpClient) { 12 | } 13 | 14 | search(inputText: string) { 15 | this.browsers.forEach(async (browser) => { 16 | browser.onSearch(inputText); 17 | }); 18 | } 19 | 20 | addBrowser(browser: MSIframeComponent) { 21 | this.browsers.push(browser); 22 | } 23 | 24 | saveDefineURL(scrnIndexID: string, defineURL: string) { 25 | localStorage.setItem(scrnIndexID, defineURL); 26 | } 27 | 28 | getDefineURL(scrnIndexID: string) { 29 | return localStorage.getItem(scrnIndexID); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import {BrowserModule} from '@angular/platform-browser'; 2 | import {NgModule} from '@angular/core'; 3 | 4 | import {AppRoutingModule} from './app-routing.module'; 5 | import {AppComponent} from './app.component'; 6 | import {MSSearchBoxComponent} from './components/mssearch-box/mssearch-box.component'; 7 | import {FormsModule} from '@angular/forms'; 8 | import {MSIframeComponent} from './components/msiframe/msiframe.component'; 9 | import {HttpClientJsonpModule, HttpClientModule} from '@angular/common/http'; 10 | 11 | @NgModule({ 12 | declarations: [ 13 | AppComponent, 14 | MSSearchBoxComponent, 15 | MSIframeComponent 16 | ], 17 | imports: [ 18 | BrowserModule, 19 | AppRoutingModule, 20 | FormsModule, 21 | HttpClientModule, 22 | HttpClientJsonpModule 23 | ], 24 | providers: [], 25 | bootstrap: [AppComponent] 26 | }) 27 | export class AppModule { 28 | } 29 | -------------------------------------------------------------------------------- /src/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, '../coverage'), 20 | reports: ['html', 'lcovonly'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false 30 | }); 31 | }; -------------------------------------------------------------------------------- /src/app/components/mssearch-box/mssearch-box.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, EventEmitter, OnInit, Output, Input} from '@angular/core'; 2 | import {BaseView} from '../../base-view'; 3 | import hotkeys, {HotkeysEvent} from 'hotkeys-js'; 4 | 5 | interface IViewData { 6 | inputText: string; 7 | searchBtnText: string; 8 | } 9 | 10 | @Component({ 11 | selector: 'ms-search-box', 12 | templateUrl: './mssearch-box.component.html', 13 | styleUrls: ['./mssearch-box.component.scss'] 14 | }) 15 | export class MSSearchBoxComponent extends BaseView implements OnInit { 16 | 17 | @Output() onClick_Search: EventEmitter = new EventEmitter(); 18 | @Input() inputText; 19 | 20 | constructor() { 21 | super({ 22 | searchBtnText: '猫搜一下', 23 | inputText: '' 24 | }) 25 | ; 26 | } 27 | 28 | ngOnInit(): void { 29 | hotkeys('enter', { 30 | scope: 'input', 31 | element: document.getElementById('input-search') 32 | }, (keyEvent: KeyboardEvent, hkevent: HotkeysEvent) => { 33 | this.onClick_search(); 34 | }); 35 | if(this.inputText){ 36 | this.viewData.inputText = this.inputText; 37 | } 38 | } 39 | 40 | onClick_search() { 41 | this.onClick_Search.emit(this.viewData.inputText); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /how-to-use-old.md: -------------------------------------------------------------------------------- 1 | 依据以下方法**只需配置一次**,只要不关闭插件,就可以一直使用了。 2 | 3 | --- 4 | 5 | # 1. 打开Chrome,下载并安装iHeader插件 6 | 7 | 1. 您可以**通过chrome应用商店**下载: 8 | 9 | [点击这里](https://chrome.google.com/webstore/detail/iheader/polajedphjkpjbfljoabmcejpcckeked?utm_source=chrome-ntp-icon) 10 | 11 | ![](./imgs/20011101.png) 12 | 13 | 这里因为我已经安装过,所以显示"从Chrome中删除",你的应该是安装。 14 | 15 | 2. 也可以通过Github下载源码使用开发者模式安装: 16 | 17 | [点击这里](https://github.com/Louiszhai/IHeader) 18 | 19 | 记得在chrome扩展中打开开发者模式 20 | 21 | ![](./imgs/20011102.png) 22 | 23 | # 2. 安装完成,配置iHeader 24 | 25 | 1. 首先对插件图标右键,进入选项设置,把「ab开启监听时, 默认为其所有请求添加CORS响应头」**打勾去掉**,这个是解决跨域的响应头,有时候会出问题,比如访问掘金的时候,等有需要我们再为单独请求添加。 26 | 27 | ![](./imgs/20011103.png) 28 | 29 | ![](./imgs/20011104.png) 30 | 31 | 2. 对插件图标右键,**打开监听模式**。 32 | 33 | ![](./imgs/20011105.png) 34 | 35 | 3. 新标签页打开猫搜 https://www.moresearch.ga 36 | 37 | 4. 在猫搜界面随便搜索一个(发现只有百度打开了..),iHeader拦截相应请求,并过滤想修改header的域名,比如google 38 | 39 | ![](./imgs/20011106.png) 40 | 41 | 5. 修改Response header,**把X-Frame-Options响应头删除**,点击创建全局监听、然后点击对勾完成。 42 | 43 | ![](./imgs/20011107.png) 44 | 45 | ![](./imgs/20011108.png) 46 | 47 | 6. 切换到All listener去修改域名,比如google。完成✅ 48 | 49 | ![](./imgs/20011109.png) 50 | 51 | 7. 根据以上方法,**修改其他域名**的响应头,比如zhihu.com等,重新搜索一下: 52 | 53 | 噔!噔!噔!打开了! perfect~ 54 | 55 | ![](./imgs/20011110.png) 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 简介 2 | 3 | 猫搜(moresearch)是一个多页聚合搜索引擎,为提高搜索效率而生。纯前端,使用Angular构建。你可以[点击这里](https://juejin.im/post/5e147c716fb9a0480d1702d1)阅读更多内容。 4 | 5 | ~~由于**跨域限制,您需要禁止「浏览器同源策略」后运行访问,或自行搭建代理服务器**~~。**推荐使用Chrome**。 6 | 7 | ~~Mac下Chrome如何禁止同源策略:~~ 8 | 9 | ~~1. 完全退出浏览器~~ 10 | 11 | ~~2. 命令行下运行:~~ 12 | ~~open -a "Google Chrome" --args --disable-web-security --user-data-dir~~ 13 | 14 | ~~Windows及其他浏览器「禁止同源策略」的方法可自行搜索。~~ 15 | 16 | 由于禁止浏览器同源策略运行,此操作**极端危险**,故我们不再推荐此方式。推荐大家使用**Chrome插件[iHeader](http://github.com/Louiszhai/IHeader)**来完成X-Frame-Options响应头的去除,或者也可以自行**搭建代理服务器**。 17 | 18 | 关于iHeader的使用,可以[参见这里](./how-use.md),我fork并扩展了一下,让它变成**安装即用**。 19 | 20 | # 效果图 21 | 22 | ![](./show.jpg) 23 | 24 | # 构建运行 25 | 26 | ## 依赖 27 | 28 | ```shell 29 | 1. Node.js 10.9.0或更高版本 30 | 31 | 2. Angular CLI: 32 | 33 | npm install -g @angular/cli 34 | ``` 35 | 36 | ## 如何构建 37 | 38 | 1. 克隆本项目到你本地 39 | 40 | ```shell 41 | git clone https://github.com/xuefengnice/MoreSearch.git 42 | ``` 43 | 44 | 2. cd到项目根目录 45 | 46 | ```shell 47 | cd ./MoreSearch 48 | ``` 49 | 50 | 3. 安装npm包 51 | 52 | ```shell 53 | npm install 54 | ``` 55 | 56 | 4. 构建运行 57 | 58 | ```shell 59 | ng serve --open 60 | ``` 61 | 62 | # 如何使用 63 | 64 | **[点击这里查看](./how-use.md)**,如何搭配chrome插件iHeader使用。 65 | 66 | # 关于 67 | 68 | 本项目为闲暇之余构建,感兴趣的朋友可以扫码关注公众号**加群交流**,亦可吹水摸鱼:) 69 | 70 | > 斜杠青年:独立开发者/业余交易员/传统文化爱好者 71 | > 72 | > 更多原创尽在公众号: 「优雅的程序员呀」。全栈。程序员赚钱之道。优雅的技术,优雅的赚钱。 73 | > 74 | > 关注公众号,可以加我好友交流,也可加群技术交流哦。 75 | 76 | ![](./qrcode.jpg) 77 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "more-search", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build", 8 | "test": "ng test", 9 | "lint": "ng lint", 10 | "e2e": "ng e2e" 11 | }, 12 | "private": true, 13 | "dependencies": { 14 | "@angular/animations": "^6.1.0", 15 | "@angular/common": "^6.1.0", 16 | "@angular/compiler": "^6.1.0", 17 | "@angular/core": "^6.1.0", 18 | "@angular/forms": "^6.1.0", 19 | "@angular/http": "^6.1.0", 20 | "@angular/platform-browser": "^6.1.0", 21 | "@angular/platform-browser-dynamic": "^6.1.0", 22 | "@angular/router": "^6.1.0", 23 | "core-js": "^2.5.4", 24 | "hotkeys-js": "^3.7.3", 25 | "jquery": "^3.4.1", 26 | "rxjs": "^6.3.3", 27 | "zone.js": "^0.8.26" 28 | }, 29 | "devDependencies": { 30 | "@angular-devkit/build-angular": "~0.7.0", 31 | "@angular/cli": "~6.1.0", 32 | "@angular/compiler-cli": "^6.1.0", 33 | "@angular/language-service": "^6.1.0", 34 | "@types/jasmine": "~2.8.6", 35 | "@types/jasminewd2": "~2.0.3", 36 | "@types/jquery": "^3.3.31", 37 | "@types/node": "~8.9.4", 38 | "codelyzer": "~4.2.1", 39 | "jasmine-core": "~2.99.1", 40 | "jasmine-spec-reporter": "~4.2.1", 41 | "karma": "~1.7.1", 42 | "karma-chrome-launcher": "~2.2.0", 43 | "karma-coverage-istanbul-reporter": "~2.0.0", 44 | "karma-jasmine": "~1.1.1", 45 | "karma-jasmine-html-reporter": "^0.2.2", 46 | "protractor": "~5.3.0", 47 | "ts-node": "~5.0.1", 48 | "tslint": "~5.9.1", 49 | "typescript": "~2.7.2" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/app/app.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 | 6 | 7 | 8 |
11 | {{scrn.index }}屏 12 |
13 |
14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 | 23 | 24 |
25 | 26 |
27 | 29 | 30 | 31 | 33 |
34 |
35 | 36 |
37 | 38 |
39 |
40 | 41 | -------------------------------------------------------------------------------- /src/app/app.component.scss: -------------------------------------------------------------------------------- 1 | 2 | .box-root { 3 | display: flex; 4 | flex-direction: column; 5 | height: 100%; 6 | width: 100%; 7 | 8 | .box-top { 9 | margin-top: 10px; 10 | width: 100%; 11 | position: relative; 12 | display: flex; 13 | align-items: center; 14 | justify-content: center; 15 | flex-wrap: wrap; 16 | 17 | ms-search-box { 18 | width: 100%; 19 | } 20 | 21 | .box-btns { 22 | position: absolute; 23 | right: 0px; 24 | top: 2px; 25 | display: flex; 26 | align-items: center; 27 | margin: 0 6px; 28 | flex-wrap: wrap; 29 | flex-direction: row-reverse; 30 | overflow: scroll; 31 | height: 48px; 32 | max-width: 250px; 33 | 34 | .btn { 35 | width: 40px; 36 | height: 40px; 37 | border-radius: 100%; 38 | background: rgba(226, 226, 226, 1); 39 | margin: 0 3px; 40 | display: flex; 41 | justify-content: center; 42 | align-items: center; 43 | box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.36); 44 | color: white; 45 | font-size: 18px; 46 | font-weight: 600; 47 | } 48 | 49 | .btn-screen { 50 | border: solid 1px rgba(134, 165, 222, 1); 51 | 52 | .pop { 53 | width: 10px; 54 | height: 20px; 55 | background: red; 56 | position: absolute; 57 | top: 40px; 58 | //left: 20px; 59 | } 60 | } 61 | 62 | .btn:hover { 63 | cursor: default; 64 | } 65 | 66 | .btn-add { 67 | width: 20px; 68 | height: 20px; 69 | } 70 | } 71 | } 72 | 73 | 74 | .box-result-list { 75 | 76 | flex: 1; 77 | width: 100%; 78 | margin: 10px 0 6px 0; 79 | height: 0; 80 | 81 | .screen { 82 | width: 100%; 83 | height: 100%; 84 | display: flex; 85 | justify-content: center; 86 | align-items: center; 87 | 88 | .box-browser { 89 | overflow: hidden; 90 | flex: 1; 91 | width: 0; 92 | height: 100%; 93 | margin: 0 3px; 94 | background: white; 95 | border-radius: 6px; 96 | box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.36), -1px -1px 3px rgba(0, 0, 0, 0.24) 97 | } 98 | 99 | .box-browser1 { 100 | margin-left: 6px; 101 | } 102 | 103 | .box-browser4 { 104 | margin-right: 6px; 105 | } 106 | } 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /src/app/components/msiframe/msiframe.component.scss: -------------------------------------------------------------------------------- 1 | .box-iframe-root { 2 | width: 100%; 3 | height: 100%; 4 | position: relative; 5 | 6 | iframe.box-iframe { 7 | width: 125%; 8 | height: 125%; 9 | border: 0; 10 | transform: scale(0.8); 11 | transform-origin: 0 0; 12 | } 13 | 14 | .box-no-setting{ 15 | width: 100%; 16 | height: 100%; 17 | background: white; 18 | font-size: 40px; 19 | font-weight: 600; 20 | color: gray; 21 | display: flex; 22 | justify-content: center; 23 | align-items: center; 24 | flex-direction: column; 25 | } 26 | .box-setting{ 27 | width: 100%; 28 | height: 100%; 29 | background: white; 30 | font-size: 12px; 31 | font-weight: 400; 32 | color: gray; 33 | display: flex; 34 | justify-content: center; 35 | align-items: center; 36 | flex-direction: column; 37 | } 38 | 39 | div.box-loading { 40 | width: 100%; 41 | height: 100%; 42 | display: flex; 43 | justify-content: center; 44 | align-items: center; 45 | flex-direction: column; 46 | } 47 | 48 | .btn-config { 49 | width: 15px; 50 | height: 15px; 51 | position: absolute; 52 | bottom: 6px; 53 | right: 6px; 54 | } 55 | .btn-go{ 56 | width: 15px; 57 | height: 15px; 58 | position: absolute; 59 | top: 6px; 60 | right: 6px; 61 | } 62 | 63 | .dialog-bg { 64 | position: absolute; 65 | top: 0; 66 | left: 0; 67 | width: 100%; 68 | height: 100%; 69 | background: rgba(0, 0, 0, 0.4); 70 | display: flex; 71 | justify-content: center; 72 | align-items: center; 73 | 74 | .dialog-content { 75 | width: 80%; 76 | background: white; 77 | border-radius: 6px; 78 | text-align: center; 79 | padding: 20px; 80 | display: flex; 81 | justify-content: center; 82 | flex-direction: column; 83 | align-items: center; 84 | 85 | .box-input{ 86 | display: flex; 87 | justify-content: center; 88 | align-items: center; 89 | width: 100%; 90 | position: relative; 91 | 92 | button{ 93 | margin-left: 5px; 94 | border-radius: 4px; 95 | padding: 3px 3px; 96 | } 97 | 98 | } 99 | 100 | input { 101 | width: 75%; 102 | height: 35px; 103 | } 104 | 105 | .box-btns { 106 | margin-top: 20px; 107 | position: relative; 108 | width: 100%; 109 | 110 | .btn { 111 | margin: 0 10px; 112 | border-radius: 6px; 113 | font-size: 14px; 114 | padding: 4px 12px; 115 | } 116 | 117 | .box-select-items{ 118 | position: absolute; 119 | top: -25px; 120 | right: 0px; 121 | border-radius: 4px; 122 | background: white; 123 | font-size: 12px; 124 | font-weight: 400; 125 | border: solid 1px gray; 126 | 127 | .item{ 128 | border-bottom: solid 1px gray; 129 | padding: 3px 3px; 130 | } 131 | } 132 | } 133 | } 134 | } 135 | } 136 | 137 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": [ 3 | "node_modules/codelyzer" 4 | ], 5 | "rules": { 6 | "arrow-return-shorthand": true, 7 | "callable-types": true, 8 | "class-name": true, 9 | "comment-format": [ 10 | true, 11 | "check-space" 12 | ], 13 | "curly": true, 14 | "deprecation": { 15 | "severity": "warn" 16 | }, 17 | "eofline": true, 18 | "forin": true, 19 | "import-blacklist": [ 20 | true, 21 | "rxjs/Rx" 22 | ], 23 | "import-spacing": true, 24 | "indent": [ 25 | true, 26 | "spaces" 27 | ], 28 | "interface-over-type-literal": true, 29 | "label-position": true, 30 | "max-line-length": [ 31 | true, 32 | 140 33 | ], 34 | "member-access": false, 35 | "member-ordering": [ 36 | true, 37 | { 38 | "order": [ 39 | "static-field", 40 | "instance-field", 41 | "static-method", 42 | "instance-method" 43 | ] 44 | } 45 | ], 46 | "no-arg": true, 47 | "no-bitwise": true, 48 | "no-console": [ 49 | true, 50 | "debug", 51 | "info", 52 | "time", 53 | "timeEnd", 54 | "trace" 55 | ], 56 | "no-construct": true, 57 | "no-debugger": true, 58 | "no-duplicate-super": true, 59 | "no-empty": false, 60 | "no-empty-interface": true, 61 | "no-eval": true, 62 | "no-inferrable-types": [ 63 | true, 64 | "ignore-params" 65 | ], 66 | "no-misused-new": true, 67 | "no-non-null-assertion": true, 68 | "no-shadowed-variable": true, 69 | "no-string-literal": false, 70 | "no-string-throw": true, 71 | "no-switch-case-fall-through": true, 72 | "no-trailing-whitespace": true, 73 | "no-unnecessary-initializer": true, 74 | "no-unused-expression": true, 75 | "no-use-before-declare": true, 76 | "no-var-keyword": true, 77 | "object-literal-sort-keys": false, 78 | "one-line": [ 79 | true, 80 | "check-open-brace", 81 | "check-catch", 82 | "check-else", 83 | "check-whitespace" 84 | ], 85 | "prefer-const": true, 86 | "quotemark": [ 87 | true, 88 | "single" 89 | ], 90 | "radix": true, 91 | "semicolon": [ 92 | true, 93 | "always" 94 | ], 95 | "triple-equals": [ 96 | true, 97 | "allow-null-check" 98 | ], 99 | "typedef-whitespace": [ 100 | true, 101 | { 102 | "call-signature": "nospace", 103 | "index-signature": "nospace", 104 | "parameter": "nospace", 105 | "property-declaration": "nospace", 106 | "variable-declaration": "nospace" 107 | } 108 | ], 109 | "unified-signatures": true, 110 | "variable-name": false, 111 | "whitespace": [ 112 | true, 113 | "check-branch", 114 | "check-decl", 115 | "check-operator", 116 | "check-separator", 117 | "check-type" 118 | ], 119 | "no-output-on-prefix": true, 120 | "use-input-property-decorator": true, 121 | "use-output-property-decorator": true, 122 | "use-host-property-decorator": true, 123 | "no-input-rename": true, 124 | "no-output-rename": true, 125 | "use-life-cycle-interface": true, 126 | "use-pipe-transform-interface": true, 127 | "component-class-suffix": true, 128 | "directive-class-suffix": true 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE9, IE10 and IE11 requires all of the following polyfills. **/ 22 | // import 'core-js/es6/symbol'; 23 | // import 'core-js/es6/object'; 24 | // import 'core-js/es6/function'; 25 | // import 'core-js/es6/parse-int'; 26 | // import 'core-js/es6/parse-float'; 27 | // import 'core-js/es6/number'; 28 | // import 'core-js/es6/math'; 29 | // import 'core-js/es6/string'; 30 | // import 'core-js/es6/date'; 31 | // import 'core-js/es6/array'; 32 | // import 'core-js/es6/regexp'; 33 | // import 'core-js/es6/map'; 34 | // import 'core-js/es6/weak-map'; 35 | // import 'core-js/es6/set'; 36 | 37 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */ 38 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 39 | 40 | /** IE10 and IE11 requires the following for the Reflect API. */ 41 | // import 'core-js/es6/reflect'; 42 | 43 | 44 | /** Evergreen browsers require these. **/ 45 | // Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove. 46 | import 'core-js/es7/reflect'; 47 | 48 | 49 | /** 50 | * Web Animations `@angular/platform-browser/animations` 51 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. 52 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). 53 | **/ 54 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 55 | 56 | /** 57 | * By default, zone.js will patch all possible macroTask and DomEvents 58 | * user can disable parts of macroTask/DomEvents patch by setting following flags 59 | */ 60 | 61 | // (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 62 | // (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 63 | // (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 64 | 65 | /* 66 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 67 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 68 | */ 69 | // (window as any).__Zone_enable_cross_context_check = true; 70 | 71 | /*************************************************************************************************** 72 | * Zone JS is required by default for Angular itself. 73 | */ 74 | import 'zone.js/dist/zone'; // Included with Angular CLI. 75 | 76 | 77 | 78 | /*************************************************************************************************** 79 | * APPLICATION IMPORTS 80 | */ 81 | -------------------------------------------------------------------------------- /src/app/components/msiframe/msiframe.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 10 | 11 |
13 | 已配置:
{{this.viewData.inputDefineURL}} 14 |
由于源站可能禁止iframe嵌套,
您需要搭配chrome插件 iHeader 一起使用:) 16 |
17 |
18 | 19 |
暂无配置 20 |
由于源站可能禁止iframe嵌套,
您需要搭配chrome插件 iHeader 一起使用:) 22 |
23 |
24 | 25 |
26 | 28 | 29 | 31 | 32 | 33 | 35 | 36 | 37 | 39 | 40 | 41 |
42 | 43 | 44 | 45 |
46 |
47 |

请配置搜索引擎链接:

48 |
49 | 50 | 51 |
52 |
53 | 54 | 55 |
56 |
{{item.name}}
57 |
58 |
59 |
60 |
61 |
62 | -------------------------------------------------------------------------------- /src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, ViewChild } from '@angular/core'; 2 | import {ActivatedRoute} from '@angular/router'; 3 | import {MSServiceService} from './msservice.service'; 4 | import {BaseView} from './base-view'; 5 | import {MSConfig} from './MSConfig'; 6 | import hotkeys from 'hotkeys-js'; 7 | import { MSSearchBoxComponent } from './components/mssearch-box/mssearch-box.component'; 8 | 9 | interface IScreen { 10 | isShow: boolean; 11 | index: number; 12 | defineURL1: string; 13 | defineURL2: string; 14 | defineURL3: string; 15 | defineURL4: string; 16 | } 17 | 18 | interface IViewData { 19 | screens: IScreen[]; 20 | query?: string; 21 | } 22 | 23 | @Component({ 24 | selector: 'MS-root', 25 | templateUrl: './app.component.html', 26 | styleUrls: ['./app.component.scss'] 27 | }) 28 | export class AppComponent extends BaseView implements OnInit{ 29 | title = 'MoreSearch'; 30 | 31 | @ViewChild(MSSearchBoxComponent) searchBox: MSSearchBoxComponent; 32 | 33 | constructor(public msService: MSServiceService,public router: ActivatedRoute) { 34 | super({ 35 | query: '', 36 | screens: [/*{ 37 | isShow: false, 38 | index: 4, 39 | defineURL1: '', 40 | defineURL2: '', 41 | defineURL3: '', 42 | defineURL4: '' 43 | }, { 44 | isShow: false, 45 | index: 3, 46 | defineURL1: '', 47 | defineURL2: '', 48 | defineURL3: '', 49 | defineURL4: '' 50 | },*/ { 51 | isShow: false, 52 | index: 2, 53 | defineURL1: '', 54 | defineURL2: '', 55 | defineURL3: '', 56 | defineURL4: '' 57 | }, { 58 | isShow: true, 59 | index: 1, 60 | defineURL1: MSConfig.google, 61 | defineURL2: MSConfig.baidu, 62 | defineURL3: MSConfig.v2ex, 63 | defineURL4: MSConfig.zhihu 64 | }] 65 | }); 66 | 67 | hotkeys.filter = function (event) { 68 | const eventTarget: any = event.target || event.srcElement; 69 | const tagName = eventTarget.tagName; 70 | const contenteditable = (tagName.isContentEditable || tagName == 'INPUT' || tagName == 'SELECT' || tagName == 'TEXTAREA'); 71 | hotkeys.setScope(contenteditable ? 'input' : 'other'); 72 | return true; 73 | }; 74 | } 75 | 76 | ngOnInit() { 77 | this.router.queryParams.subscribe(params => { 78 | let query = params['query']; 79 | if(query){ 80 | this.viewData.query = query; 81 | if(this.searchBox){ 82 | this.searchBox.viewData.inputText = query; 83 | } 84 | this.onClick_Search(query); 85 | } 86 | }); 87 | } 88 | 89 | onClick_Search(inputText: string) { 90 | this.msService.search(inputText); 91 | } 92 | 93 | onClick_Screen_Select(event, scrn: IScreen) { 94 | event.stopPropagation(); 95 | event.preventDefault(); 96 | this.viewData.screens.forEach(item => { 97 | if (item.index === scrn.index) { 98 | item.isShow = true; 99 | } else { 100 | item.isShow = false; 101 | } 102 | }); 103 | } 104 | 105 | onClick_addScreen() { 106 | this.viewData.screens.unshift({ 107 | isShow: false, 108 | index: this.viewData.screens.length + 1, 109 | defineURL1: '', 110 | defineURL2: '', 111 | defineURL3: '', 112 | defineURL4: '' 113 | }); 114 | } 115 | 116 | removeScreen(index: number) { 117 | if (this.viewData.screens.length > 1) { 118 | this.viewData.screens.splice(this.viewData.screens.findIndex(item => item.index === index), 1); 119 | } 120 | } 121 | 122 | onClick_open_github() { 123 | window.open('https://github.com/xuefengnice/MoreSearch'); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "MoreSearch": { 7 | "root": "", 8 | "sourceRoot": "src", 9 | "projectType": "application", 10 | "prefix": "MS", 11 | "schematics": { 12 | "@schematics/angular:component": { 13 | "styleext": "scss" 14 | } 15 | }, 16 | "architect": { 17 | "build": { 18 | "builder": "@angular-devkit/build-angular:browser", 19 | "options": { 20 | "outputPath": "dist/MoreSearch", 21 | "index": "src/index.html", 22 | "main": "src/main.ts", 23 | "polyfills": "src/polyfills.ts", 24 | "tsConfig": "src/tsconfig.app.json", 25 | "assets": [ 26 | "src/favicon.ico", 27 | "src/assets" 28 | ], 29 | "styles": [ 30 | "src/styles.scss" 31 | ], 32 | "scripts": [] 33 | }, 34 | "configurations": { 35 | "production": { 36 | "fileReplacements": [ 37 | { 38 | "replace": "src/environments/environment.ts", 39 | "with": "src/environments/environment.prod.ts" 40 | } 41 | ], 42 | "optimization": true, 43 | "outputHashing": "all", 44 | "sourceMap": false, 45 | "extractCss": true, 46 | "namedChunks": false, 47 | "aot": true, 48 | "extractLicenses": true, 49 | "vendorChunk": false, 50 | "buildOptimizer": true 51 | } 52 | } 53 | }, 54 | "serve": { 55 | "builder": "@angular-devkit/build-angular:dev-server", 56 | "options": { 57 | "browserTarget": "MoreSearch:build" 58 | }, 59 | "configurations": { 60 | "production": { 61 | "browserTarget": "MoreSearch:build:production" 62 | } 63 | } 64 | }, 65 | "extract-i18n": { 66 | "builder": "@angular-devkit/build-angular:extract-i18n", 67 | "options": { 68 | "browserTarget": "MoreSearch:build" 69 | } 70 | }, 71 | "test": { 72 | "builder": "@angular-devkit/build-angular:karma", 73 | "options": { 74 | "main": "src/test.ts", 75 | "polyfills": "src/polyfills.ts", 76 | "tsConfig": "src/tsconfig.spec.json", 77 | "karmaConfig": "src/karma.conf.js", 78 | "styles": [ 79 | "src/styles.scss" 80 | ], 81 | "scripts": [], 82 | "assets": [ 83 | "src/favicon.ico", 84 | "src/assets" 85 | ] 86 | } 87 | }, 88 | "lint": { 89 | "builder": "@angular-devkit/build-angular:tslint", 90 | "options": { 91 | "tsConfig": [ 92 | "src/tsconfig.app.json", 93 | "src/tsconfig.spec.json" 94 | ], 95 | "exclude": [ 96 | "**/node_modules/**" 97 | ] 98 | } 99 | } 100 | } 101 | }, 102 | "MoreSearch-e2e": { 103 | "root": "e2e/", 104 | "projectType": "application", 105 | "architect": { 106 | "e2e": { 107 | "builder": "@angular-devkit/build-angular:protractor", 108 | "options": { 109 | "protractorConfig": "e2e/protractor.conf.js", 110 | "devServerTarget": "MoreSearch:serve" 111 | }, 112 | "configurations": { 113 | "production": { 114 | "devServerTarget": "MoreSearch:serve:production" 115 | } 116 | } 117 | }, 118 | "lint": { 119 | "builder": "@angular-devkit/build-angular:tslint", 120 | "options": { 121 | "tsConfig": "e2e/tsconfig.e2e.json", 122 | "exclude": [ 123 | "**/node_modules/**" 124 | ] 125 | } 126 | } 127 | } 128 | } 129 | }, 130 | "defaultProject": "MoreSearch" 131 | } -------------------------------------------------------------------------------- /src/app/components/msiframe/msiframe.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Input, OnInit} from '@angular/core'; 2 | import {MSServiceService} from '../../msservice.service'; 3 | import {BaseView} from '../../base-view'; 4 | import {DomSanitizer} from '@angular/platform-browser'; 5 | import {MSConfig} from '../../MSConfig'; 6 | 7 | interface IViewData { 8 | selectItems: { name: string, queryURL: string }[]; 9 | isShowSelect: boolean; 10 | isError: boolean; 11 | isShowFrame: boolean; 12 | inputDefineURL: string; 13 | isShowDialog: boolean; 14 | url: any; 15 | isLoading: boolean; 16 | } 17 | 18 | @Component({ 19 | selector: 'ms-iframe-box', 20 | templateUrl: './msiframe.component.html', 21 | styleUrls: ['./msiframe.component.scss'] 22 | }) 23 | export class MSIframeComponent extends BaseView implements OnInit { 24 | @Input() defineURL: string; 25 | @Input() scrnIndexID: string; 26 | private urlGO: string; 27 | 28 | constructor(public msService: MSServiceService, 29 | public ds: DomSanitizer) { 30 | super({ 31 | selectItems: [ 32 | {name: 'Google', queryURL: MSConfig.google}, 33 | {name: '百度', queryURL: MSConfig.baidu}, 34 | {name: 'V2EX', queryURL: MSConfig.v2ex}, 35 | {name: '知乎', queryURL: MSConfig.zhihu}, 36 | {name: '掘金', queryURL: MSConfig.juejin}, 37 | ], 38 | isShowSelect: false, 39 | isError: false, 40 | isShowFrame: false, 41 | isLoading: false, 42 | url: ds.bypassSecurityTrustResourceUrl(''), 43 | isShowDialog: false, 44 | inputDefineURL: '' 45 | }); 46 | } 47 | 48 | ngOnInit() { 49 | this.msService.addBrowser(this); 50 | const url = this.msService.getDefineURL(this.scrnIndexID); 51 | this.viewData.inputDefineURL = (url || url === '') ? url : this.defineURL; 52 | this.defineURL = this.viewData.inputDefineURL; 53 | } 54 | 55 | onSearch(inputText: string) { 56 | if (this.defineURL) { 57 | this.viewData.isLoading = true; 58 | this.viewData.isShowFrame = true; 59 | this.viewData.isError = false; 60 | const url = this.defineURL.replace(`{query}`, inputText); 61 | this.urlGO = encodeURI(url); 62 | /*this.msService.httpClient.get(this.urlGO, {responseType: 'text'}) 63 | .subscribe(value => { 64 | const iframe: any = document.getElementById(this.scrnIndexID); 65 | const iframedoc: any = iframe.contentDocument || iframe.contentWindow.document; 66 | iframedoc.children[0].innerHTML = value; // 事先拿到的html 67 | let index = 0; 68 | let isFind = false; 69 | while (index < this.defineURL.length) { 70 | const number = this.defineURL.indexOf('/', index); 71 | if (number - 1 >= 0 && url.charAt(number - 1) !== ':' && url.charAt(number - 1) !== '/') { 72 | isFind = true; 73 | index = number; 74 | break; 75 | } else { 76 | index = number + 1; 77 | } 78 | } 79 | const htmlBaseElement = document.createElement('base'); 80 | htmlBaseElement.href = isFind ? this.defineURL.substring(0, index + 1) : '/'; 81 | htmlBaseElement.target = '_blank'; 82 | iframedoc.children[0].children[0].appendChild(htmlBaseElement); 83 | this.onLoad(); 84 | }, error => { 85 | this.onLoad(); 86 | });*/ 87 | this.viewData.url = this.ds.bypassSecurityTrustResourceUrl(this.urlGO); 88 | } 89 | } 90 | 91 | onLoad() { 92 | this.viewData.isLoading = false; 93 | /*try { 94 | // const iframe: any = window.frames[this.scrnIndexID]; 95 | // const iframedoc: any = iframe.contentDocument || iframe.contentWindow.document; 96 | } catch (err) { 97 | this.viewData.isError = true; 98 | }*/ 99 | } 100 | 101 | onError() { 102 | this.onLoad(); 103 | } 104 | 105 | onClick_config() { 106 | this.setIsShowDialog(true); 107 | } 108 | 109 | onClick_ok() { 110 | this.defineURL = this.viewData.inputDefineURL; 111 | this.setIsShowDialog(false, true); 112 | } 113 | 114 | onClick_go() { 115 | if (this.urlGO) { 116 | window.open(this.urlGO); 117 | } 118 | } 119 | 120 | setIsShowDialog(isShow: boolean, isSave?: boolean) { 121 | this.viewData.isShowDialog = isShow; 122 | this.viewData.isShowSelect = false; 123 | if (isSave) { 124 | this.msService.saveDefineURL(this.scrnIndexID, this.defineURL); 125 | } else { 126 | this.viewData.inputDefineURL = this.defineURL; 127 | } 128 | } 129 | 130 | onClick_select_item(event: Event, item: { name: string; queryURL: string }) { 131 | event.stopPropagation(); 132 | this.viewData.inputDefineURL = item.queryURL; 133 | this.viewData.isShowSelect = false; 134 | } 135 | 136 | onDialogContentClick(event: Event) { 137 | this.viewData.isShowSelect = false; 138 | event.stopPropagation(); 139 | } 140 | 141 | onClick_show_select(event: Event) { 142 | event.stopPropagation(); 143 | this.viewData.isShowSelect = !this.viewData.isShowSelect; 144 | } 145 | } 146 | --------------------------------------------------------------------------------