master dc50c871d9b5 cached
38 files
73.7 KB
22.0k tokens
90 symbols
1 requests
Download .txt
Repository: zhongyi-tong/electronic-wechat
Branch: master
Commit: dc50c871d9b5
Files: 38
Total size: 73.7 KB

Directory structure:
gitextract_2blxg1ih/

├── .eslintrc
├── .gitignore
├── .travis.yml
├── CHANGELOG.md
├── CONTRIBUTING.md
├── ISSUE_TEMPLATE.md
├── LICENSE.md
├── README.md
├── README_zh.md
├── assets/
│   └── icon.icns
├── config.json
├── package.json
├── scripts/
│   ├── build-all.sh
│   ├── build-win32.bat
│   ├── build.sh
│   ├── qiniu.sh
│   └── tar-all.sh
└── src/
    ├── common.js
    ├── common_cn.js
    ├── configuration.js
    ├── handlers/
    │   ├── menu.js
    │   ├── message.js
    │   └── update.js
    ├── inject/
    │   ├── badge_count.js
    │   ├── css.js
    │   ├── emoji_parser.js
    │   ├── mention_menu.js
    │   ├── preload.js
    │   └── share_menu.js
    ├── main.js
    └── windows/
        ├── controllers/
        │   ├── app_tray.js
        │   ├── settings.js
        │   ├── splash.js
        │   └── wechat.js
        ├── styles/
        │   ├── settings.css
        │   └── splash.css
        └── views/
            ├── settings.html
            └── splash.html

================================================
FILE CONTENTS
================================================

================================================
FILE: .eslintrc
================================================
{
  "parser": "babel-eslint",
  "extends": "airbnb/base",
  "rules": {
      "strict": "off",
      "max-len": "off",
      "prefer-template": "warn",
      "arrow-body-style": "off",
      "no-unused-vars": "warn",
      "no-undef": "off",
      "array-callback-return": "off",
      "no-confusing-arrow": "off",
      "consistent-return": "warn",
      "no-param-reassign": "off",
      "default-case": "off",
      "guard-for-in": "off",
      "no-restricted-syntax": "off",
      "no-underscore-dangle": "off",
      "new-cap": "warn",
      "no-console": "off",
      "global-require": "off",
      "class-methods-use-this": "warn"
    },
}


================================================
FILE: .gitignore
================================================
.DS_Store
/dist
npm-debug.log*
.idea

# Dependency directories
node_modules

*.sublime-project
*.sublime-workspace


================================================
FILE: .travis.yml
================================================
language: node_js
sudo: required
node_js:
- '5.2'
branches:
  only:
  - master
  - production
before_script:
- npm install
script:
- ./scripts/build-all.sh
- ./scripts/tar-all.sh
deploy:
  provider: releases
  api_key:
    secure: ETudcaMBembv5mq5WcA0Zu5YCQt02A8sfMIYJ+XN0dTUCFRODYgyk8SiW3ndI4zLfhsc31KbYecSVfcrvYhPlkLucdhD0hY+v4mowrGaG6q3DUE4v9+qATOE5z51MPNTQO/suPNZpeFkSCKaWh6SY9oSd/tsD+YmbcpuD0//DMiFMpYqA8ueQ7yka4SmlZq8C48MsRbULAtyHNEVNJ4en9xdE9vFHZ45kM2A2IWYVikuCa5J6YoL7N2CyIFwtKMeF68d0vwidXUXEc7z1VOHwosG7V0vEfNRrIy4mft0tXyEYe/nM8GlYnirVRCy3xF4h4ssERXbLMuZSYGm+bg/pqReL+dvsN5oKszuo7IseZnE8QfmmhfbMB4dWf8Le5WXfFgJTG28lNvl2VwTTEW4Cj5qeJmfO524GydqRE+i3uQvW4c2tBTFmfpusPnaFqVXTPH7o54hT18hYvgaBvJQv6pyMNMLLXq0BbkzquTTWTwb8lSi8XiRr/fWkQreRZNofJc21ZUSI5YcuqZpzbz1fOLseC4QJ8YXQ9b2OU/LiFF3gvHTK6vSKMQmbOFg0zFXMi5FT1SzCi/mKduax/OR/H6lolVW83eXCG1Ni+sIrwUkp0d/UL6E1pVeJMibBrOEgriWIpD+AiVzNVyBdq/oDC6qG9IXRWzii9Ks6J9zH7k=
  file:
  - 'dist/mac-osx.tar.gz'
  - 'dist/linux-x64.tar.gz'
  - 'dist/linux-ia32.tar.gz'
  skip_cleanup: true
  on:
    repo: geeeeeeeeek/electronic-wechat
    branch: production
notifications:
  webhooks:
    urls:
      - https://webhooks.gitter.im/e/d6bab2376f47ee992d78
    on_success: always  # options: [always|never|change] default: always
    on_failure: always  # options: [always|never|change] default: always
    on_start: always     # options: [always|never|change] default: always
after_deploy:
  - ./scripts/qiniu.sh


================================================
FILE: CHANGELOG.md
================================================
# CHANGELOG

**v2.0 (2017.02.13) CN**

1. 升级 **Electron** 至 **V1.4.15**,**Chromium** 至 **54**
2. 增加了**偏好设置**(感谢设计建议 @**[xiaoyusilen](https://github.com/xiaoyusilen)**)
3. 增加了英文版本的支持
4. 增加了一键隐藏窗口(**`ESC`** 键)
5. 修复了 **macOS** 上窗口最小化时不显示新消息提示的红点(感谢 @wujysh 的贡献)
6. 修复了聊天框内换行提示仅针对 macOS 的问题
7. 增加了两个快捷键(感谢 @awmleer 的贡献)
	- 搜索联系人:**`Ctrl + F`**
	- 切换到全屏模式:**macOS** 下 **`Ctrl + Command + F`**,**Linux** 下为 **`F11`**
8. 修复了在 Linux 系统下部分菜单按钮失效的问题(感谢 @qzchenwl 的贡献)
8. 更新了依赖的第三方库的版本至最新兼容版本

**v2.0 (2017.02.13) EN**

1. Update Electron to V1.4.15, Chromium API level 54
2. Add **Preference Panel** (Thanks for the design advises from @**[xiaoyusilen](https://github.com/xiaoyusilen)**](https://github.com/xiaoyusilen))
3. Fully support English UI!
4. Quick hide windows shortcut (**Press `ESC`**)
5. Fix **macOS** new message red dot display improperly (Thanks to @wujysh)
6. Tips in chat window now are adapted with platform
7. Add two shortcuts (Thanks to @awmleer)
	- Search Contact人: **`Ctrl + F`**
	- Toggle Fullscreen Mode: **macOS** **`Ctrl + Command + F`**, **Linux** **`F11`**
8. Fix unfunctional menu items on **Linux** (Thanks to @qzchenwl)
8. All thrid party libraries are up-to-date


**v1.3 (2016.05.19)**

1. 升级 electron 至 1.1.0, Chrome 至 50.0.2661.102,Node 至 6.1.0 (感谢 @lfs1102 的贡献)
2. 新增 `brew cask` 安装方式 (最新可下载版本为 v1.2.0)
3. 新增 Windows 下的安装脚本 (感谢 @3dseals 的贡献)
4. 新增 应用启动动画,缩短首次展现时间
5. 优化 应用启动稳定性,增加超时重试
6. 优化 主要文案均统一为英文
7. 优化 减少 20M 应用体积
8. 修复 关于页面版本号显示的 bug
9. 修复 Linux 系统下左边栏组件重叠的 bug
10. 修复 部分 Linux KDE 系统下托盘图标空白的 bug
11. 其他修改 (感谢 @wzyboy, @rivershang, @hexchain, @samurai00, @boltomli 的贡献)


**v1.2 (2016.04.21)**

1. 新增 更新检测模块,应用内即可检查更新
2. 新增 公众号文章的第三方分享功能。现支持一键分享到微博、QQ 空间、Facebook、Twitter、Evernote 和邮件 (感谢 @oblank 的贡献)
3. 新增 群聊 @ 提及成员功能,但收到提醒需要服务端支持 (感谢 @iamcc 的贡献)
4. 优化 登录界面使用单独的尺寸 (感谢 @xnfa 的贡献)
5. 优化 修改 OS X 下隐藏其他窗口的快捷键为 `Command+Alt+H`
6. 优化 Linux 下可执行文件文件名使用小写字母,去除空格
7. 优化 Linux 下使用彩色图标
8. 升级 `electron-prebuilt` 版本至 `0.37.6` , `electron-packager` 版本至 `7.0.0`
9. ~~降级 Emoji贴纸显示的功能。由于微信协议调整和官方代码缺陷,现有商店内贴纸及部分个人收藏的贴纸无法显示。后续跟进微信的修复进行调整。~~ (Update: 微信已修复,贴纸均可正常显示)


**v1.1 (2016.03.17)**

1. 新增 OS X 和 Linux 下的托盘菜单,点击可进入应用、退出应用 (仅Linux) (感谢 @iamcc 和 @wenLiangcan 的贡献)
2. 新增 cnpm 镜像提醒
3. 优化 应用的退出逻辑,Cmd+Q 退出应用,Cmd+W 或点击关闭隐藏应用
4. 优化 OS X 和 Linux 下的应用菜单显示
5. 优化 Emoji贴纸的实现方式,避免滑动时内容抖动,无法回到底部
6. 优化 接管应用刷新的逻辑,Cmd+R 重新加载页面
7. 优化 OS X 下 build 后将应用拷贝到 Application 文件夹
8. 优化 Linux 下使用 Ctrl+Shift+I 打开开发者工具 (感谢 @wenLiangcan 的贡献)
9. 修复 错误的微信站内重定向 (感谢 @gucheen 的贡献)
10. 修复 Linux 下应用图标的显示
11. 修复 聊天列表滑动性能问题
12. 修复 公众号新窗口打开报错 (感谢 @gzzhanghao 的贡献)

**v1.0 (2016.03.01)**

1. 新增 阻止消息撤回的功能 (感谢 @arrowrowe 的贡献)
2. 新增 引入了 Travis CI 和 Gitter.im
3. 优化 贴纸显示的实现方式 (感谢 @arrowrowe 的贡献)
4. 优化 build 脚本 (感谢 @gaocegege, @viko16 和 @htc550605125 的贡献)
5. 优化 Linux 下自动隐藏菜单 (感谢 @wenLiangcan 的贡献)
6. 优化 Linux 下用户头像的显示
7. 优化 禁用缩放、选中文本、默认光标

**v0.1 (2016.02.19)**

1. Create the project.
2. Auto resize web content.
3. Drag to send pictures.
4. Open inhibited links without additional redirect.


================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to Electronic WeChat

First of all, thanks for contributing to this project. It would be appreciated if you read through this contributing guide.

## Issues

- Check if your issue is already [there](https://github.com/geeeeeeeeek/electronic-wechat/issues). 

- Check if your issue is `Electronic WeChat` related rather than upstream related.

- Follow the guide in the issue template.

## Pull Requests

PR are always welcomed. It's better if you put up an issue before firing a PR. **Remember**, the smaller your focus, the better chance to get merged.

## Be a collaborator!

If you are excited about the project, and happen to have skills in Angular, Node, Electron, or else. Do not hesitate to contact me. Let's build together!


================================================
FILE: ISSUE_TEMPLATE.md
================================================
#### Description

First of all, thanks for your attention to open an issue for this project.
Please notice that if you are requesting a **feature**, then you should give a **brief description** of your request.
If you are reporting a **bug**, please **follow the template** below.
A bug report **without detailed information** required will have a **very low priority** and even be **ignored** (closed directly)!

#### Specifications

- Version of Electron (run `$ electron --version`): `v0.0.0`
- OS: `<OS>`
- Stack trace from the error message (if any)

```
<Stack trace here>
```


================================================
FILE: LICENSE.md
================================================
The MIT License (MIT)

Copyright (c) 2017 Zhongyi Tong

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:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

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.


================================================
FILE: README.md
================================================
<img src="assets/icon.png" alt="logo" height="120" align="right" />

# Electronic WeChat

*A better WeChat on macOS and Linux. Built with [Electron](https://github.com/atom/electron).*

> **⚠️⚠️ NO LONGER IN ACTIVE DEVELOPMENT | 项目不再维护 ⚠️⚠️** 
> 
> Thanks for supporting this project for **1000** days since Feb 16, 2016. 
> 
> It started with the idea to make WeChat better on MacOS when the official support was abscent. It was de facto dead when Tencent rolled out a new WeChat and started to block other third-party clients. For me, it's no longer worthwhile to hack a lot to accomplish little. Hope this project had been helpful to you in any way. You're welcome to fork or make copies with a reference. HAPPY HACKING.
>
> 感谢历史上的用户和贡献者,你们已经陪伴这个项目走过了 **1000** 个日子。我曾经想要打造一个更好的 Mac 微信客户端,因为官方版本几年没有更新、bug 层出。而在腾讯自己开始了定期更新并限制第三方客户端时,这个项目实际已经没有什么意义。这个项目目前作为一个存档供大家学习。希望它曾经对你有所帮助,你也可以 fork 或者转载(标注来源)来进行修改。祝你玩得愉快。
>
> **SPECIAL THANKS TO | 特别感谢**
> 
> [Kulbear](https://github.com/Kulbear), 
> [arrowrowe](https://github.com/arrowrowe), 
> [Rocka](https://github.com/rocka), 
> [CC](https://github.com/iamcc), 
> [xgdgsc](https://github.com/xgdgsc), 
> [死水微澜](https://github.com/ripples-alive), 
> [Jason](https://github.com/gzzhanghao), 
> [Ce Gao](https://github.com/gaocegege), 
> [viko16](https://github.com/viko16), 
> [卡晨](https://github.com/awmleer), 
> [Ray](https://github.com/ray26), 
> [尹良灿](https://github.com/wenLiangcan), 
> [gehuangyi20](https://github.com/gehuangyi20), 
> [Kevin Tan](https://github.com/stkevintan), 
> [Jiaye Wu](https://github.com/wujysh), 
> [loufq](https://github.com/loufq), 
> [Miaow](https://github.com/miaowing), 
> [Chuan Ji](https://github.com/jichu4n), 
> [Oaker](https://github.com/cyio), 
> [Fengshuang Li](https://github.com/lfs1102), 
> [Song Li](https://github.com/boltomli), 
> [afon](https://github.com/samurai00), 
> [lional wang](https://github.com/3dseals), 
> [Haochen Tong](https://github.com/hexchain), 
> [Zhuoyun Wei](https://github.com/wzyboy), 
> [rivershang](https://github.com/rivershang), 
> [Ivan Jiang](https://github.com/iplus26), 
> [oBlank](https://github.com/oblank), 
> [Cheng Gu](https://github.com/gucheen), 
> [NullMDR](https://github.com/NullMDR), 
> [ReadmeCritic](https://github.com/ReadmeCritic).
---

**Important:** If you want to build the app by yourself rather than download the release directly, please consider to use the source code from [the production branch](https://github.com/geeeeeeeeek/electronic-wechat/tree/production), the master branch is under development and we cannot guarantee it to be stable.

[![Gitter](https://badges.gitter.im/geeeeeeeeek/electronic-wechat.svg)](https://gitter.im/geeeeeeeeek/electronic-wechat?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=body_badge)
[![Build Status](https://travis-ci.org/geeeeeeeeek/electronic-wechat.svg?branch=master)](https://travis-ci.org/geeeeeeeeek/electronic-wechat)
[![Build Status](https://img.shields.io/github/stars/geeeeeeeeek/electronic-wechat.svg)](https://github.com/geeeeeeeeek/electronic-wechat)
[![Build Status](https://img.shields.io/github/forks/geeeeeeeeek/electronic-wechat.svg)](https://github.com/geeeeeeeeek/electronic-wechat)
[![Build Status](https://img.shields.io/badge/README-切换语言-yellow.svg)](README_zh.md)

![qq20160428-0 2x](https://cloud.githubusercontent.com/assets/7262715/14876747/ff691ade-0d49-11e6-8435-cb1fac91b3c2.png)

## Features ([CHANGELOG](CHANGELOG.md))

- **Modern UI and all features from Web WeChat.**
- **Block message recall.**
- **Stickers showing support.** [[?]](https://github.com/geeeeeeeeek/electronic-wechat/issues/2)
- Share subscribed passages on Weibo, Qzone, Facebook, Twitter, Evernote, and email.
- Mention users in a group chat.
- Drag and drop to send photos.
- Behaves like a native app, based on dozens of optimization.
- Removes URL link redirects and takes you directly to blocked websites (e.g. taobao.com).

## How To Use

To clone and run this repository you'll need [Git](https://git-scm.com) and [Node.js](https://nodejs.org/en/download/) (which comes with [npm](https://www.npmjs.com/)) installed on your computer. From your command line:

``` bash
# Clone this repository
git clone https://github.com/geeeeeeeeek/electronic-wechat.git
# Go into the repository
cd electronic-wechat
# Install dependencies and run the app
npm install && npm start
```

To pack into an app, simply type one of these:

``` shell
npm run build:osx
npm run build:linux
npm run build:win32
npm run build:win64
```

**New:** Install with your familiar package manager. Check out [images maintained by the community](https://github.com/geeeeeeeeek/electronic-wechat/wiki/System-Support-Matrix#%E7%A4%BE%E5%8C%BA%E8%B4%A1%E7%8C%AE%E7%9A%84%E5%AE%89%E8%A3%85%E5%8C%85)!

**New:** Or, with homebrew!

```bash
brew cask install electronic-wechat
```

#### [Download Released App](https://github.com/geeeeeeeeek/electronic-wechat/releases)

#### License [MIT](LICENSE.md)

*Electronic WeChat* is released by this open source project. While Web WeChat is a major component  in the app, it should be noted that this is a community release and not an official WeChat release.


================================================
FILE: README_zh.md
================================================
<img src="assets/icon.png" alt="logo" height="120" align="right" />

# Electronic WeChat

[![Gitter](https://badges.gitter.im/geeeeeeeeek/electronic-wechat.svg)](https://gitter.im/geeeeeeeeek/electronic-wechat?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=body_badge)  [![Build Status](https://travis-ci.org/geeeeeeeeek/electronic-wechat.svg?branch=master)](https://travis-ci.org/geeeeeeeeek/electronic-wechat)  [English](README.md)

**Mac OS X 和 Linux 下更好用的微信客户端. 更多功能, 更少bug. 使用[Electron](https://github.com/atom/electron)构建.** 

**Important:** 如果你希望在自己的电脑上构建 Electronic WeChat,请使用 [production branch](https://github.com/geeeeeeeeek/electronic-wechat/tree/production),master branch 包含正在开发的部分,并且不能保证是稳定的版本——尽管 production 版本也有bug :D 

![qq20160428-0 2x](https://cloud.githubusercontent.com/assets/7262715/14876747/ff691ade-0d49-11e6-8435-cb1fac91b3c2.png)

## 应用特性 ([更新日志](CHANGELOG.md))

-  **来自网页版微信的更现代的界面和更丰富的功能**
-  **阻止消息撤回**
-  **显示表情贴纸** [[?]](https://github.com/geeeeeeeeek/electronic-wechat/issues/2)
-  公众号文章支持一键分享到微博、QQ 空间、Facebook、Twitter、Evernote 和邮件
-  拖入图片、文件即可发送
-  群聊 @ 提及成员
-  原生应用体验,未读消息小红点、消息通知等数十项优化
-  去除外链重定向,直接打开淘宝等网站
-  没有原生客户端万年不修复的bug

## 如何使用

在下载和运行这个项目之前,你需要在电脑上安装 [Git](https://git-scm.com) 和 [Node.js](https://nodejs.org/en/download/) (来自 [npm](https://www.npmjs.com/))。在命令行中输入:

``` bash
# 下载仓库
git clone https://github.com/geeeeeeeeek/electronic-wechat.git
# 进入仓库
cd electronic-wechat
# 安装依赖, 运行应用
npm install && npm start
```

根据你的平台打包应用:

``` shell
npm run build:osx
npm run build:linux
npm run build:win
```

**提示:** 如果 `npm install` 下载缓慢,你可以使用 [淘宝镜像(cnpm)](http://npm.taobao.org/) 替代 npm 。

**新渠道:** 使用你熟悉的包管理工具安装。请查看 [社区贡献的镜像](https://github.com/geeeeeeeeek/electronic-wechat/wiki/System-Support-Matrix#%E7%A4%BE%E5%8C%BA%E8%B4%A1%E7%8C%AE%E7%9A%84%E5%AE%89%E8%A3%85%E5%8C%85) 。

**新渠道:** homebrew 安装也已支持 (更新至 electronic-wechat v1.2.0)!

```bash
brew cask install electronic-wechat
```

#### [下载开箱即用的稳定版应用](https://github.com/geeeeeeeeek/electronic-wechat/releases)

#### 项目使用 [MIT](LICENSE.md) 许可

*Electronic WeChat* 是这个开源项目发布的产品。网页版微信是其中重要的一部分,但请注意这是一个社区发布的产品,而 *不是* 官方微信团队发布的产品。


================================================
FILE: config.json
================================================
{
  "osx" : {
    "title": "Electronic Wechat",
    "background": "icon.png",
    "icon": "icon.icns",
    "icon-size": 80,
    "contents": [
      { "x": 438, "y": 344, "type": "link", "path": "/Applications" },
      { "x": 192, "y": 344, "type": "file" }
    ]
  }
}


================================================
FILE: package.json
================================================
{
  "name": "electronic-wechat",
  "version": "2.0.0",
  "description": "An Electron application for WeChat",
  "main": "src/main.js",
  "scripts": {
    "start": "electron src/main.js",
    "build": "./scripts/build-all.sh",
    "build:osx": "./scripts/build.sh darwin x64",
    "build:osx64": "./scripts/build.sh darwin x64",
    "build:linux32": "./scripts/build.sh linux ia32",
    "build:linux": "./scripts/build.sh linux x64",
    "build:linux64": "./scripts/build.sh linux x64",
    "build:win": ".\\scripts\\build-win32.bat win32 ia32",
    "build:win32": ".\\scripts\\build-win32.bat win32 ia32",
    "build:win64": ".\\scripts\\build-win32.bat win32 x64"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/geeeeeeeeek/wechat-electron.git"
  },
  "keywords": [
    "Electron",
    "WeChat",
    "微信",
    "Web"
  ],
  "author": "Zhongyi Tong",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/geeeeeeeeek/wechat-electron/issues"
  },
  "homepage": "https://github.com/geeeeeeeeek/wechat-electron/",
  "dependencies": {
    "electron": "1.4.15",
    "electron-packager": "^8.5.1",
    "nconf": "^0.8.4",
    "pinyin": "^2.8.0",
    "emojione": "^2.2.7",
    "electron-localshortcut": "1.1.0",
    "is-xfce": "^1.0.2"
  },
  "devDependencies": {
    "babel-eslint": "^7.1.1",
    "eslint": "^3.15.0",
    "eslint-config-airbnb": "^14.1.0",
    "eslint-plugin-import": "^2.2.0",
    "eslint-plugin-jsx-a11y": "^4.0.0",
    "eslint-plugin-react": "^6.9.0"
  }
}


================================================
FILE: scripts/build-all.sh
================================================
#!/bin/bash

if ! hash electron-packager 2>/dev/null; then
  RED='\033[0;31m'
  NC='\033[0m'
  echo "${RED}Error${NC}: you need to npm install electron-packager. Aborting."
  exit 1
fi

function build() {
	./scripts/build.sh $@
}

build darwin x64
build linux ia32
build linux x64
#build win32 ia32


================================================
FILE: scripts/build-win32.bat
================================================
set PLATFORM=%1%
set ARCH=%2%
set APP_NAME="Electronic WeChat"

set ignore_list="dist|scripts|\.idea|.*\.md|.*\.yml|node_modules/nodejieba"

electron-packager . "%APP_NAME%" --platform=%PLATFORM% --arch=%ARCH% --electronVersion=1.4.15  --app-version=1.4.0 --asar --icon=assets\icon.png --overwrite --out=.\dist --ignore=%ignore_list%


================================================
FILE: scripts/build.sh
================================================
#!/bin/bash

if ! hash electron-packager 2>/dev/null; then
  RED='\033[0;31m'
  NC='\033[0m'
  echo "${RED}Error${NC}: you need to npm install electron-packager. Aborting."
  exit 1
fi

if [ "$#" -ne 2 ]; then
  echo -e "Usage: ./script/build.sh <platform> <arch>"
  echo -e "	platform:	darwin, linux, win32"
  echo -e "	arch:		ia32, x64"
  exit 1
fi

PLATFORM=$1
ARCH=$2

echo "Start packaging for $PLATFORM $ARCH."

if [ $PLATFORM = "linux" ]; then
    APP_NAME="electronic-wechat"
else
    APP_NAME="Electronic WeChat"
fi

ignore_list="dist|scripts|\.idea|.*\.md|.*\.yml|node_modules/nodejieba"

electron-packager . "${APP_NAME}" --platform=$PLATFORM --arch=$ARCH --electronVersion=1.4.15 --app-version=1.4.0 --asar --icon=assets/icon.icns --overwrite --out=./dist --ignore=${ignore_list}

if [ $? -eq 0 ]; then
  echo -e "$(tput setaf 2)Packaging for $PLATFORM $ARCH succeeded.$(tput sgr0)\n"
fi

if [ $PLATFORM = "darwin" ]; then
    ditto -rsrcFork ./dist/Electronic\ WeChat-darwin-x64/Electronic\ WeChat.app /Applications/Electronic\ WeChat.app
    echo "$(tput setaf 3)App copied to /Applications. You can open Electronic WeChat there or from Spotlight.$(tput sgr0)"
fi


================================================
FILE: scripts/qiniu.sh
================================================
#!/bin/bash

case "$(uname -s)" in

    Linux*)
        wget http://devtools.qiniu.com/qiniu-devtools-linux_amd64-current.tar.gz -O dist/qiniu-devtools.tar.gz
        ;;

    Darwin)
        wget http://devtools.qiniu.io/qiniu-devtools-darwin_amd64-current.tar.gz -O dist/qiniu-devtools.tar.gz
        ;;

    *)
        ;;

esac

mkdir dist/qiniu-devtools
tar -xvf dist/qiniu-devtools.tar.gz -C dist/qiniu-devtools
rm -rf /tmp/qiniu
mkdir /tmp/qiniu
cp dist/mac-osx.tar.gz /tmp/qiniu
cp dist/linux-x64.tar.gz /tmp/qiniu
cp dist/linux-ia32.tar.gz /tmp/qiniu

echo '{
    "src": "/tmp/qiniu",
    "dest": "qiniu:access_key='$QINIU_ACCESS_KEY'&secret_key='$QINIU_SECRET_KEY'&bucket=flymeos-cancro",
    "debug_level": 1
}' > qiniu-config.json
./dist/qiniu-devtools/qrsync qiniu-config.json


================================================
FILE: scripts/tar-all.sh
================================================
#!/bin/bash

cd dist

echo 'Start compressing for Mac OS X.'
tar zcf 'mac-osx.tar.gz' 'Electronic WeChat-darwin-x64'
echo 'Compressing for Mac OS X succeed.'

echo 'Start compressing for Linux x64.'
tar zcf 'linux-x64.tar.gz' 'electronic-wechat-linux-x64'
echo 'Compressing for Linux x64 succeed.'

echo 'Start compressing for Linux ia32.'
tar zcf 'linux-ia32.tar.gz' 'electronic-wechat-linux-ia32'
echo 'Compressing for Linux ia32 succeed.'

cd ..


================================================
FILE: src/common.js
================================================
/**
 * Created by Zhongyi on 3/26/16.
 */

'use strict';

class Common {

}
Common.ELECTRON = 'Electron';
Common.ELECTRONIC_WECHAT = 'Electronic WeChat';
Common.DEBUG_MODE = false;
Common.WINDOW_SIZE = {
  width: 800,
  height: 600,
};
Common.WINDOW_SIZE_LOGIN = {
  width: 380,
  height: 540,
};
Common.WINDOW_SIZE_LOADING = {
  width: 380,
  height: 120,
};
Common.WINDOW_SIZE_SETTINGS = {
  width: 800,
  height: 600,
};

Common.USER_AGENT = {
  freebsd: 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36',
  sunos: 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36',
  win32: 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36',
  linux: 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36',
  darwin: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.1 Safari/537.36',
};

Common.WEB_WECHAT = 'https://wx.qq.com/?lang=en_US';
Common.GITHUB = 'https://github.com/geeeeeeeeek/electronic-wechat';
Common.GITHUB_RELEASES = 'https://github.com/geeeeeeeeek/electronic-wechat/releases';
Common.GITHUB_ISSUES = 'https://github.com/geeeeeeeeek/electronic-wechat/issues';
Common.GITHUB_API_HOST = 'api.github.com';
Common.GITHUB_API_RELEASE_LATEST_PATH = '/repos/geeeeeeeeek/electronic-wechat/releases/latest';

Common.UPDATE_ERROR_ELECTRON = `Failed to get the local version. If you are using debug mode(by \`npm start\`), this error would happen. Use packed app instead or manually check for updates.\n\n${Common.GITHUB_RELEASES}`;
Common.UPDATE_ERROR_EMPTY_RESPONSE = 'Failed to fetch release info.';
Common.UPDATE_ERROR_UNKNOWN = 'Something went wrong.';
Common.UPDATE_NA_TITLE = 'No Update Available';
Common.UPDATE_ERROR_NETWORK = 'Connection hang up unexpectedly. Check your network settings.';
Common.UPDATE_ERROR_LATEST = (version) => {
  return `You are using the latest version(${version}).`;
};

Common.MENTION_MENU_INITIAL_X = 300;
Common.MENTION_MENU_OFFSET_X = 30;
Common.MENTION_MENU_INITIAL_Y = 140;
Common.MENTION_MENU_OFFSET_Y = 45;
Common.MENTION_MENU_WIDTH = 120;
Common.MENTION_MENU_OPTION_HEIGHT = 30;
Common.MENTION_MENU_OPTION_DEFAULT_NUM = 4;
Common.MENTION_MENU_HINT_TEXT = 'Mention:';

Common.MESSAGE_PREVENT_RECALL = 'Blocked a message recall.';
Common.EMOJI_MAXIUM_SIZE = 120;

Common.languageTitle = 'Language(Need to Restart)';
Common.languageDesc = 'Select a default language for WeChat!';
Common.recallTitle = 'Prevent Message Recall';
Common.recallDesc = 'Message recall feature might be annoying';
Common.instanceTitle = 'Allow Multiple Instance';
Common.instanceDesc = 'Multiple instance can login with different accounts';
Common.iconTitle = 'File Path (In Development)';
Common.iconDesc = 'Set a default file path';
Common.trayTitle = 'Tray Icon color (Black/White)';
Common.trayDesc = 'Select a color to match your desktop theme';

Common.UPGRADE = 'UPGRADE';
Common.FEEDBACK = 'FEEDBACK';

Common.MENU = {
  about: 'About Electronic Wechat',
  service: 'Service',
  hide: 'Hide Application',
  hideOther: 'Hide Others',
  showAll: 'Show All',
  pref: 'Preference',
  quit: 'Quit',
  edit: 'Edit',
  undo: 'Undo',
  redo: 'Redo',
  cut: 'Cut',
  copy: 'Copy',
  paste: 'Paste',
  selectAll: 'Select All',
  view: 'View',
  reload: 'Reload This Window',
  toggleFullScreen: 'Toggle Full Screen',
  searchContacts: 'Search Contacts',
  devtool: 'Toggle DevTools',
  window: 'Window',
  min: 'Minimize',
  close: 'Close',
  allFront: 'Bring All to Front',
  help: 'Help',
  repo: 'GitHub Repository',
  feedback: 'Report Issue',
  checkRelease: 'Check for New Release',
};

module.exports = Common;


================================================
FILE: src/common_cn.js
================================================
/**
 * Created by Zhongyi on 3/26/16.
 */
'use strict';
class Common {

}
Common.ELECTRON = 'Electron';
Common.ELECTRONIC_WECHAT = 'Electronic WeChat';
Common.DEBUG_MODE = false;
Common.WINDOW_SIZE = {
  width: 800,
  height: 600,
};
Common.WINDOW_SIZE_LOGIN = {
  width: 380,
  height: 540,
};
Common.WINDOW_SIZE_LOADING = {
  width: 380,
  height: 120,
};
Common.WINDOW_SIZE_SETTINGS = {
  width: 800,
  height: 600,
};

Common.USER_AGENT = {
  'freebsd': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36',
  'sunos': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36',
  'win32': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36',
  'linux': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36',
  'darwin': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.1 Safari/537.36'
}

Common.WEB_WECHAT = 'https://wx.qq.com/?lang=zh_CN';
Common.GITHUB = 'https://github.com/geeeeeeeeek/electronic-wechat';
Common.GITHUB_RELEASES = 'https://github.com/geeeeeeeeek/electronic-wechat/releases';
Common.GITHUB_ISSUES = 'https://github.com/geeeeeeeeek/electronic-wechat/issues';
Common.GITHUB_API_HOST = 'api.github.com';
Common.GITHUB_API_RELEASE_LATEST_PATH = '/repos/geeeeeeeeek/electronic-wechat/releases/latest';

Common.UPDATE_ERROR_ELECTRON = 'Failed to get the local version. If you are using debug mode(by `npm start`), this error would happen. Use packed app instead or manually check for updates.\n\n' + Common.GITHUB_RELEASES;
Common.UPDATE_ERROR_EMPTY_RESPONSE = '没能获取最新的更新信息';
Common.UPDATE_ERROR_UNKNOWN = '不造什么出错了...';
Common.UPDATE_NA_TITLE = '没有可用的更新';
Common.UPDATE_ERROR_NETWORK = '网络连接出错,请检查你的网络';
Common.UPDATE_ERROR_LATEST = (version) => {
  return `已经在使用最新版 - (${version})`;
};

Common.MENTION_MENU_INITIAL_X = 300;
Common.MENTION_MENU_OFFSET_X = 30;
Common.MENTION_MENU_INITIAL_Y = 140;
Common.MENTION_MENU_OFFSET_Y = 45;
Common.MENTION_MENU_WIDTH = 120;
Common.MENTION_MENU_OPTION_HEIGHT = 30;
Common.MENTION_MENU_OPTION_DEFAULT_NUM = 4;

Common.MENTION_MENU_HINT_TEXT = '选择回复的人:';

Common.MESSAGE_PREVENT_RECALL = '阻止了一次撤回';

Common.EMOJI_MAXIUM_SIZE = 120;

Common.MENU = {
  about: '关于 Electronic Wechat',
  service: '服务',
  hide: '隐藏应用',
  hideOther: '隐藏其他窗口',
  showAll: '显示全部窗口',
  pref: '偏好',
  quit: '退出',
  edit: '编辑',
  undo: '撤销',
  redo: '取消撤销',
  cut: '剪切',
  copy: '复制',
  paste: '粘贴',
  selectAll: '选择全部',
  view: '视图',
  reload: '重新加载当前窗口',
  toggleFullScreen:'切换全屏',
  searchContacts:'搜索联系人',
  devtool: '开发者工具',
  window: '窗口',
  min: '最小化',
  close: '关闭',
  allFront: '全部打开',
  help: '帮助',
  repo: 'GitHub 目录',
  feedback: '联系我们',
  checkRelease: '检查更新',
};

module.exports = Common;


================================================
FILE: src/configuration.js
================================================
'use strict';

function getUserHome() {
  return process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME'];
}

const nconf = require('nconf').file({
  file: `${getUserHome()}/.ew.json`,
});

function saveSettings(settingKey, settingValue) {
  nconf.set(settingKey, settingValue);
  nconf.save();
}

function readSettings(settingKey) {
  nconf.load();
  return nconf.get(settingKey);
}

module.exports = {
  saveSettings,
  readSettings,
};


================================================
FILE: src/handlers/menu.js
================================================
'use strict';

const { remote, shell, ipcRenderer } = require('electron');
const AppConfig = require('../configuration');

const { Menu, app } = remote;

const lan = AppConfig.readSettings('language');
let Common;
if (lan === 'zh-CN') {
  Common = require('../common_cn');
} else {
  Common = require('../common');
}

class MenuHandler {
  create() {
    const template = this.getTemplate(remote.process.platform);
    if (template) {
      const menuFromTemplate = Menu.buildFromTemplate(template);
      Menu.setApplicationMenu(menuFromTemplate);
    }
  }

  getTemplate(platform) {
    const darwinTemplate = [
      {
        label: Common.ELECTRONIC_WECHAT,
        submenu: [
          {
            label: Common.MENU.about,
            selector: 'orderFrontStandardAboutPanel:',
          },
          {
            type: 'separator',
          },
          {
            label: Common.MENU.service,
            submenu: [],
          },
          {
            type: 'separator',
          },
          {
            label: Common.MENU.hide,
            accelerator: 'Command+H',
            selector: 'hide:',
          },
          {
            label: Common.MENU.hideOther,
            accelerator: 'Command+Alt+H',
            selector: 'hideOtherApplications:',
          },
          {
            label: Common.MENU.showAll,
            selector: 'unhideAllApplications:',
          },
          {
            type: 'separator',
          },
          {
            label: Common.MENU.pref,
            click: MenuHandler._preference,
          },
          {
            type: 'separator',
          },
          {
            label: Common.MENU.quit,
            accelerator: 'Command+Q',
            click: MenuHandler._quitApp,
          },
        ],
      },
      {
        label: Common.MENU.edit,
        submenu: [
          {
            label: Common.MENU.undo,
            accelerator: 'Command+Z',
            selector: 'undo:',
          },
          {
            label: Common.MENU.redo,
            accelerator: 'Shift+Command+Z',
            selector: 'redo:',
          },
          {
            type: 'separator',
          },
          {
            label: Common.MENU.cut,
            accelerator: 'Command+X',
            selector: 'cut:',
          },
          {
            label: Common.MENU.copy,
            accelerator: 'Command+C',
            selector: 'copy:',
          },
          {
            label: Common.MENU.paste,
            accelerator: 'Command+V',
            selector: 'paste:',
          },
          {
            label: Common.MENU.selectAll,
            accelerator: 'Command+A',
            selector: 'selectAll:',
          },
          {
            type: 'separator',
          },
          {
            label: Common.MENU.searchContacts,
            accelerator: 'Command+F',
            click: () => {
              $('#search_bar input')[0].focus();
            },
          },
        ],
      },
      {
        label: Common.MENU.view,
        submenu: [
          {
            label: Common.MENU.reload,
            accelerator: 'Command+R',
            click: MenuHandler._reload,
          },
          {
            label: Common.MENU.devtool,
            accelerator: 'Alt+Command+I',
            click: MenuHandler._devTools,
          },
        ],
      },
      {
        label: Common.MENU.window,
        submenu: [
          {
            label: Common.MENU.min,
            accelerator: 'Command+M',
            selector: 'performMiniaturize:',
          },
          {
            label: Common.MENU.close,
            accelerator: 'Command+W',
            selector: 'performClose:',
          },
          {
            label: Common.MENU.toggleFullScreen,
            accelerator: 'Ctrl+Command+F',
            click: (item, focusedWindow) => {
              if (focusedWindow) {
                focusedWindow.setFullScreen(!focusedWindow.isFullScreen());
              }
            },
          },
          {
            type: 'separator',
          },
          {
            label: Common.MENU.allFront,
            selector: 'arrangeInFront:',
          },
        ],
      },
      {
        label: Common.MENU.help,
        submenu: [
          {
            label: Common.MENU.repo,
            click: MenuHandler._github,
          },
          {
            type: 'separator',
          }, {
            label: Common.MENU.feedback,
            click: MenuHandler._githubIssues,
          }, {
            label: Common.MENU.checkRelease,
            click: MenuHandler._update,
          }],
      },
    ];
    const linuxTemplate = [
      {
        label: Common.MENU.window,
        submenu: [
          {
            label: Common.MENU.pref,
            click: MenuHandler._preference,
          },
          {
            label: Common.MENU.reload,
            accelerator: 'Ctrl+R',
            click: MenuHandler._reload,
          },
          {
            label: Common.MENU.toggleFullScreen,
            accelerator: 'F11',
            click: (item, focusedWindow) => {
              if (focusedWindow) {
                focusedWindow.setFullScreen(!focusedWindow.isFullScreen());
              }
            },
          },
          {
            type: 'separator',
          },
          {
            label: Common.MENU.searchContacts,
            accelerator: 'Ctrl+F',
            click: () => {
              $('#search_bar input')[0].focus();
            },
          },
          {
            label: Common.MENU.devtool,
            accelerator: 'Ctrl+Shift+I',
            click: MenuHandler._devTools,
          },
          {
            type: 'separator',
          },
          {
            label: Common.MENU.quit,
            accelerator: 'Ctrl+Q',
            click: MenuHandler._quitApp,
          },
        ],
      },
      {
        label: Common.MENU.help,
        submenu: [
          {
            label: Common.MENU.repo,
            click: MenuHandler._github,
          },
          {
            type: 'separator',
          }, {
            label: Common.MENU.feedback,
            click: MenuHandler._githubIssues,
          }, {
            label: Common.MENU.checkRelease,
            click: MenuHandler._update,
          }],
      },
    ];

    if (platform === 'darwin') {
      return darwinTemplate;
    } else if (platform === 'linux') {
      return linuxTemplate;
    }
  }

  static _quitApp() {
    app.exit(0);
  }

  static _reload() {
    ipcRenderer.send('reload');
  }

  static _devTools() {
    remote.getCurrentWindow().toggleDevTools();
  }

  static _github() {
    shell.openExternal(Common.GITHUB);
  }

  static _githubIssues() {
    shell.openExternal(Common.GITHUB_ISSUES);
  }

  static _update() {
    ipcRenderer.send('update');
  }

  static _preference() {
    ipcRenderer.send('open-settings-window');
  }
}
module.exports = MenuHandler;


================================================
FILE: src/handlers/message.js
================================================
'use strict';

const qs = require('querystring');
const url = require('url');

class MessageHandler {
  handleRedirectMessage(origin) {
    return qs.parse(url.parse(origin).query).requrl || origin;
  }
}

module.exports = MessageHandler;


================================================
FILE: src/handlers/update.js
================================================
/**
 * Created by Zhongyi on 3/25/16.
 */

'use strict';

const { dialog, shell, app, nativeImage } = require('electron');
const AppConfig = require('../configuration');
const https = require('https');
const path = require('path');

const lan = AppConfig.readSettings('language');
let Common;
if (lan === 'zh-CN') {
  Common = require('../common_cn');
} else {
  Common = require('../common');
}

class UpdateHandler {
  checkForUpdate(version, silent) {
    UpdateHandler.CHECKED = true;
    const promise = new Promise((res, rej) => {
      if (Common.ELECTRON === app.getName()) {
        rej(Common.UPDATE_ERROR_ELECTRON);
      }
      const req = https.get({
        host: Common.GITHUB_API_HOST,
        headers: { 'user-agent': Common.USER_AGENT },
        path: Common.GITHUB_API_RELEASE_LATEST_PATH,
      }, (response) => {
        let body = '';
        response.on('data', (d) => {
          body += d;
        });
        response.on('end', () => {
          this._parseUpdateData(body, version, res, rej);
        });
      });
      req.on('error', (err) => {
        rej(Common.UPDATE_ERROR_NETWORK);
      });
      req.end();
    }).then((fetched) => {
      this.showDialog(fetched.name, fetched.description, 'Update', (response) => {
        if (!response) return;
        shell.openExternal(fetched.url);
      });
    }).catch((message) => {
      if (silent) return;
      if (!message) {
        message = Common.UPDATE_ERROR_UNKNOWN;
      }
      this.showDialog(Common.UPDATE_NA_TITLE, message, 'OK');
    });
  }

  showDialog(message, detail, positiveButton, callback) {
    const iconImage = nativeImage.createFromPath(path.join(__dirname, '../assets/icon.png'));

    dialog.showMessageBox({
      type: 'info',
      buttons: ['Cancel', positiveButton],
      defaultId: 1,
      cancelId: 0,
      title: message,
      message,
      detail,
      icon: iconImage,
    }, callback);
  }

  _parseUpdateData(body, version, res, rej) {
    const data = JSON.parse(body);
    if (!data || !data.tag_name) rej(Common.UPDATE_ERROR_EMPTY_RESPONSE);
    const fetched = {
      version: data.tag_name,
      is_prerelease: data.prerelease,
      name: data.name,
      url: data.html_url,
      description: data.body,
    };

    const versionRegex = /^v[0-9]+\.[0-9]+\.*[0-9]*$/;
    if (versionRegex.test(fetched.version) && fetched.version > version && !fetched.is_prerelease) {
      res(fetched);
    } else {
      rej(Common.UPDATE_ERROR_LATEST(version));
    }
  }
}

UpdateHandler.CHECKED = false;

module.exports = UpdateHandler;


================================================
FILE: src/inject/badge_count.js
================================================
/**
 * Created by Zhongyi on 4/12/16.
 */
'use strict';
const { ipcRenderer } = require('electron');

class BadgeCount {
  static init() {
    setInterval(() => {
      let count = 0;
      $('.icon.web_wechat_reddot_middle').each(function () {
        count += parseInt(this.textContent, 10);
      });
      if (count > 0) {
        ipcRenderer.send('badge-changed', count.toString());
      } else {
        ipcRenderer.send('badge-changed', '');
      }
    }, 1500);
  }
}

module.exports = BadgeCount;


================================================
FILE: src/inject/css.js
================================================
/**
 * Created by Zhongyi on 2/23/16.
 */
'use strict';
const Common = require('../common');

class CSSInjector {
}

CSSInjector.commonCSS = `
    div.header, div.title_wrap {
        -webkit-app-region: drag;
    }
    div.title.poi {
        -webkit-app-region: no-drag;
    }
    div.header .avatar, div.header .info {
        -webkit-app-region: no-drag;
    }
    div.main {
      height: 100% !important;
      min-height: 0 !important;
      padding-top: 0 !important;
    }
    div.main_inner {
      max-width: none !important;
      min-width: 0 !important;
    }
    div.message_empty {
      margin-top: 50px;
    }
    div.img_preview_container div.img_opr_container {
      bottom: 50px !important;
    }
    p.copyright {
      display: none !important
    }
    a.web_wechat_screencut {
      display: none !important;
    }
    * {
      -webkit-user-select: none;
      cursor: default !important;
      -webkit-user-drag: none;
    }
    pre, input {
      -webkit-user-select: initial;
      cursor: initial !important;
    }
    html, body {
      width: 100%;
      height: 100%;
      overflow: hidden;
    }

    div.login_box {
      top: initial;
      left: initial;
      margin-left: initial;
      margin-top: initial;
      width: 100%;
      height: 100%;
    }
    div.login {
      min-width: 0;
      min-height: 0;
      width: 100%;
      height: 100%;
      overflow: hidden;
    }
    div.lang, div.copyright {
      display: none !important
    }
    /* Group mention: user selection box */
    div#userSelectionBox select option:hover {
      background: #eeeeee;
    }
    div#userSelectionBox select option {
      padding: 4px 10px;
      text-overflow: hidden;
      font-size: 14px;
    }
    .user_select_hint_text {
      padding: 4px 10px;
      font-size: 14px;
      background: #eeeeee;
    }
    div#userSelectionBox select {
      width: 120px;
      border: none;
      outline: none;
      height: inherit;
    }
    div#userSelectionBox {
      box-shadow: 1px 1px 10px #ababab;
      background: #fff;
      display: none;
      position: fixed;
      bottom: ${Common.MENTION_MENU_INITIAL_Y}px;
      left: ${Common.MENTION_MENU_INITIAL_X}px;
    }
    span.measure_text {
      padding-left: 20px;
      outline: 0;
      border: 0;
      font-size: 14px;
    }
    img.emojione {
      width: 20px;
      height: 20px;
    }
    @media (max-width: 512px) {
      .panel {
        width: 75px !important;
        transition: width .3s;
      }
      .panel .header,
      .chat_item {
        padding: 8px 16px !important;
      }
      .header,
      .panel .tab,
      .search_bar,
      .chat_item .info,
      .chat_item .ext {
        display: none !important
      }
      .nav_view {
        top: 36px !important
      }
      .chat_item.active {
        border-left: 2px solid #02b300 !important
      }
    }
  `;

CSSInjector.osxCSS = `
    div.header div.avatar img.img {
      width: 24px;
      height: 24px;
    }
    div.header {
      padding-top: 38px;
      padding-bottom: 8px;
    }
    span.display_name {
      width: 172px !important;
    }
    @media (max-width: 512px) {
      .nav_view {
        top: 36px !important
      }
    }
`;

module.exports = CSSInjector;


================================================
FILE: src/inject/emoji_parser.js
================================================
/**
 * Created by chenwl on 9/29/16.
 */

var emojione = require('emojione');

// <span class="emoji emoji1f471"></span>
const emojiSpanRegex = /<span class="emoji emoji([\da-f]+)"><\/span>/g;

function unicodeToString(point) {
    const offset = point - 0x10000;
    const lead = 0xd800 + (offset >> 10);
    const trail = 0xdc00 + (offset & 0x3ff);
    return String.fromCharCode(lead, trail);
}

class EmojiParser {
    static emojiSpanToString(str) {
        return str.replace(emojiSpanRegex, function(span, emojiHex) {
            const point = parseInt(emojiHex, 16);
            return unicodeToString(point);
        });
    }

    static emojiToImage(str) {
        return emojione.unicodeToImage(EmojiParser.emojiSpanToString(str));
    }
}

module.exports = EmojiParser;


================================================
FILE: src/inject/mention_menu.js
================================================
/**
 * Created by Zhongyi on 4/9/16.
 */

'use strict';
const Common = require('../common');
const pinyin = require('pinyin');

class MentionMenu {

  static init() {
    const $box = $('<div id="userSelectionBox"/>');

    const $div = $('<div/>');
    $div.html(Common.MENTION_MENU_HINT_TEXT);
    $div.addClass('user_select_hint_text');
    $box.append($div);

    const $select = $('<select multiple/>');
    $select.change(() => {
      const $editArea = $('#editArea');
      $editArea.focus();
      const newMessage = $editArea.html().replace(/@\S*$/ig, `@${$select.val()} `);
      $editArea.html('');
      $editArea.scope().insertToEditArea(newMessage);
      $box.css('display', 'none');
    });
    $box.append($select);
    $('body').append($box);
  }

  static inject($event) {
    const $editArea = $($event.currentTarget);
    const $box = $('#userSelectionBox');

    const $probe = $('<span id="probe"/>');
    $editArea.append($probe);
    const probePosition = $probe.position();
    $probe.remove();
    const menuPosition = MentionMenu.getMenuPosition($editArea, probePosition);

    const delayInjection = () => {
      const name = /@(\S*)$/.exec($editArea.html());
      if (!name) {
        $box.css('display', 'none');
        return;
      }
      const $scope = angular.element('#chatArea').scope();
      const $select = $box.children('select');
      $select.html('');
      $scope.currentContact.MemberList.map(m => {
        if (!MentionMenu.isValidNameHint(name, m.NickName)) return;

        const $option = MentionMenu.generateOptionFromMember($scope, m);
        if ($option) $select.append($option);
      });
      const membersCount = Math.min($select.children().length, Common.MENTION_MENU_OPTION_DEFAULT_NUM);
      if (membersCount > 0) {
        $select.val('');
        $box.css({
          display: 'block',
          height: `${(membersCount + 1) * Common.MENTION_MENU_OPTION_HEIGHT}px`,
        });
        if (name[1].length === 0) {
          $box.css({
            left: `${menuPosition.left}px`,
            bottom: `${menuPosition.bottom}px`,
          });
        }
        $select.css({
          height: `${membersCount * Common.MENTION_MENU_OPTION_HEIGHT}px`,
        });
        $box.focus();
      } else {
        $box.css('display', 'none');
      }
    };
    setTimeout(delayInjection, 0);
  }

  static getMenuPosition($editArea, probePosition) {
    const menuPosition = {};
    const mentionMenuRightBoundX = probePosition.left + Common.MENTION_MENU_WIDTH + Common.MENTION_MENU_OFFSET_X;

    if (!probePosition.left) {
      menuPosition.left = Common.MENTION_MENU_INITIAL_X + Common.MENTION_MENU_OFFSET_X;
    } else if (mentionMenuRightBoundX > $editArea.width()) {
      menuPosition.left = (Common.MENTION_MENU_INITIAL_X + $editArea.width()) - Common.MENTION_MENU_WIDTH;
    } else {
      menuPosition.left = probePosition.left + Common.MENTION_MENU_INITIAL_X;
    }
    menuPosition.bottom = (Common.MENTION_MENU_INITIAL_Y - probePosition.top) + Common.MENTION_MENU_OFFSET_Y;
    return menuPosition;
  }

  static isValidNameHint(nameHint, userName) {
    const pinyinRaw = pinyin(userName, {
      style: pinyin.STYLE_FIRST_LETTER,
    });

    let pinyinName = '';
    for (const py of pinyinRaw) {
      if (py[0] && py[0] !== ' ') {
        pinyinName += py[0];
      }
    }

    const nameRe = new RegExp(nameHint[1], 'ig');
    return nameRe.test(userName) || nameRe.test(pinyinName);
  }

  static generateOptionFromMember($scope, member) {
    const displayName = `${member.NickName}`;
    let actualName = displayName;

    if (member.DisplayName.length > 0) {
      actualName = member.DisplayName;
    } else {
      const userContact = $scope.getUserContact(member.UserName);
      if (!userContact) return null;
      if (userContact.NickName.length > 0) {
        actualName = userContact.NickName;
      }
    }

    const $option = $('<option/>');
    $option.val(actualName);
    $option.html(displayName);

    return $option;
  }
}

module.exports = MentionMenu;


================================================
FILE: src/inject/preload.js
================================================
'use strict';

const { ipcRenderer, webFrame } = require('electron');
const MenuHandler = require('../handlers/menu');
const ShareMenu = require('./share_menu');
const MentionMenu = require('./mention_menu');
const BadgeCount = require('./badge_count');
const Common = require('../common');
// const EmojiParser = require('./emoji_parser');
// const emojione = require('emojione');

const AppConfig = require('../configuration');

class Injector {
  init() {
    if (Common.DEBUG_MODE) {
      Injector.lock(window, 'console', window.console);
    }
    this.initInjectBundle();
    this.initAngularInjection();
    this.lastUser = null;
    this.initIPC();
    webFrame.setZoomLevelLimits(1, 1);

    new MenuHandler().create();
  }

  initAngularInjection() {
    const self = this;
    const angular = window.angular = {};
    let angularBootstrapReal;
    Object.defineProperty(angular, 'bootstrap', {
      get: () => angularBootstrapReal ? function (element, moduleNames) {
        const moduleName = 'webwxApp';
        if (moduleNames.indexOf(moduleName) < 0) return;
        let constants = null;
        angular.injector(['ng', 'Services']).invoke(['confFactory', (confFactory) => (constants = confFactory)]);
        angular.module(moduleName).config(['$httpProvider', ($httpProvider) => {
          $httpProvider.defaults.transformResponse.push((value) => {
            return self.transformResponse(value, constants);
          });
        },
        ]).run(['$rootScope', ($rootScope) => {
          ipcRenderer.send('wx-rendered', MMCgi.isLogin);

          $rootScope.$on('newLoginPage', () => {
            ipcRenderer.send('user-logged', '');
          });
          $rootScope.shareMenu = ShareMenu.inject;
          $rootScope.mentionMenu = MentionMenu.inject;
        }]);
        return angularBootstrapReal.apply(angular, arguments);
      } : angularBootstrapReal,
      set: (real) => (angularBootstrapReal = real),
    });
  }

  initInjectBundle() {
    const initModules = () => {
      if (!window.$) {
        return setTimeout(initModules, 3000);
      }

      MentionMenu.init();
      BadgeCount.init();
    };

    window.onload = () => {
      initModules();
      window.addEventListener('online', () => {
        ipcRenderer.send('reload', true);
      });
    };
  }

  transformResponse(value, constants) {
    if (!value) return value;

    switch (typeof value) {
      case 'object':
        /* Inject emoji stickers and prevent recalling. */
        return this.checkEmojiContent(value, constants);
      case 'string':
        /* Inject share sites to menu. */
        return this.checkTemplateContent(value);
    }
    return value;
  }

  static lock(object, key, value) {
    return Object.defineProperty(object, key, {
      get: () => value,
      set: () => {},
    });
  }

  checkEmojiContent(value, constants) {
    if (!(value.AddMsgList instanceof Array)) return value;
    value.AddMsgList.forEach((msg) => {
      switch (msg.MsgType) {
        // case constants.MSGTYPE_TEXT:
        //   msg.Content = EmojiParser.emojiToImage(msg.Content);
        //   break;
        case constants.MSGTYPE_EMOTICON:
          Injector.lock(msg, 'MMDigest', '[Emoticon]');
          Injector.lock(msg, 'MsgType', constants.MSGTYPE_EMOTICON);
          if (msg.ImgHeight >= Common.EMOJI_MAXIUM_SIZE) {
            Injector.lock(msg, 'MMImgStyle', { height: `${Common.EMOJI_MAXIUM_SIZE}px`, width: 'initial' });
          } else if (msg.ImgWidth >= Common.EMOJI_MAXIUM_SIZE) {
            Injector.lock(msg, 'MMImgStyle', { width: `${Common.EMOJI_MAXIUM_SIZE}px`, height: 'initial' });
          }
          break;
        case constants.MSGTYPE_RECALLED:
          if (AppConfig.readSettings('prevent-recall') === 'on') {
            Injector.lock(msg, 'MsgType', constants.MSGTYPE_SYS);
            Injector.lock(msg, 'MMActualContent', Common.MESSAGE_PREVENT_RECALL);
            Injector.lock(msg, 'MMDigest', Common.MESSAGE_PREVENT_RECALL);
          }
          break;
      }
    });
    return value;
  }

  checkTemplateContent(value) {
    const optionMenuReg = /optionMenu\(\);/;
    const messageBoxKeydownReg = /editAreaKeydown\(\$event\)/;
    if (optionMenuReg.test(value)) {
      value = value.replace(optionMenuReg, 'optionMenu();shareMenu();');
    } else if (messageBoxKeydownReg.test(value)) {
      value = value.replace(messageBoxKeydownReg, 'editAreaKeydown($event);mentionMenu($event);');
    }
    return value;
  }

  initIPC() {
    // clear currentUser to receive reddot of new messages from the current chat user
    ipcRenderer.on('hide-wechat-window', () => {
      this.lastUser = angular.element('#chatArea').scope().currentUser;
      angular.element('.chat_list').scope().itemClick("");
    });
    // recover to the last chat user
    ipcRenderer.on('show-wechat-window', () => {
      if (this.lastUser != null) {
        angular.element('.chat_list').scope().itemClick(this.lastUser);
      }
    });
  }
}

new Injector().init();


================================================
FILE: src/inject/share_menu.js
================================================
/**
 * Created by oBlank on 3/31/16.
 */
'use strict';

class ShareMenu {
  static inject() {
    const dropdownMenu = $('.reader_menu .dropdown_menu');
    const dropdownMenuItem = $('.reader_menu .dropdown_menu > li');
    if (dropdownMenuItem.length > ShareMenu.shareMenuItemsCount) return;

    ShareMenu.shareMenuItemsCount = dropdownMenuItem.length;
    const readItem = angular.element('.reader').scope().readItem;
    const menuHTML = ShareMenu.get({ url: readItem.Url, title: readItem.Title });
    dropdownMenu.prepend(menuHTML);
  }

  static get(link) {
    if (!link.url || !link.title) return '';

    link.url = encodeURIComponent(link.url);
    link.title = encodeURIComponent(link.title);

    const shareTargets = {
      weibo: {
        url: `http://service.weibo.com/share/share.php?url=${link.url}&title=${link.title}#&searchPic=yes`,
        text: '分享到微博',
      },
      qzone: {
        url: `http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url=${link.url}&title=${link.title}&pics=&summary=`,
        text: '分享到 QQ 空间',
      },
      facebook: {
        url: `https://www.facebook.com/sharer/sharer.php?s=100&p%5Btitle%5D=${link.title}&p%5Bsummary%5D=%21&p%5Burl%5D=${link.url}&p%5Bimages%5D=`,
        text: '分享到 Facebook',
      },
      evernote: {
        url: `https://www.evernote.com/clip.action?url=${link.url}&title=${link.title}`,
        text: '分享到 Evernote',
      },
      twitter: {
        url: `https://twitter.com/intent/tweet?text=${link.title}&url=${link.url}&original_referer=`,
        text: '分享到 Twitter',
      },
      email: {
        url: `mailto:?&subject=${link.title}&body=${link.title}%0A${link.url}`,
        text: '分享到邮件',
      },
    };


    let menuItemsTemplate = '';
    for (const target in shareTargets) {
      menuItemsTemplate += ShareMenu.genShareMenuItem(shareTargets[target]);
    }

    return menuItemsTemplate;
  }

  static genShareMenuItem(target) {
    return `
          <li>
            <a href="javascript:;" onclick="javascript:window.open('${target.url}', '_blank'); return;">
              <i class="menuicon_copylink"></i>
              ${target.text}
            </a>
          </li>
          `;
  }
}

ShareMenu.shareMenuItemsCount = 256;

module.exports = ShareMenu;


================================================
FILE: src/main.js
================================================
'use strict';

const path = require('path');
const {app, ipcMain} = require('electron');

const UpdateHandler = require('./handlers/update');
const Common = require('./common');
const AppConfig = require('./configuration');

const SplashWindow = require('./windows/controllers/splash');
const WeChatWindow = require('./windows/controllers/wechat');
const SettingsWindow = require('./windows/controllers/settings')
const AppTray = require('./windows/controllers/app_tray');

class ElectronicWeChat {
  constructor() {
    this.wechatWindow = null;
    this.splashWindow = null;
    this.settingsWindow = null;
    this.tray = null;
  }

  init() {
    if(this.checkInstance()) {
      this.initApp();
      this.initIPC();
    } else {
      app.quit();
    }
  }
  checkInstance() {
    if (AppConfig.readSettings('multi-instance') === 'on') return true;
    return !app.makeSingleInstance((commandLine, workingDirectory) => {
      if(this.splashWindow && this.splashWindow.isShown){
        this.splashWindow.show();
        return
      }
      if(this.wechatWindow){
        this.wechatWindow.show();
      }
      if(this.settingsWindow && this.settingsWindow.isShown){
        this.settingsWindow.show();
      }
    });

  }
  initApp() {
    app.on('ready', ()=> {
      this.createSplashWindow();
      this.createWeChatWindow();
      this.createTray();

      if (!AppConfig.readSettings('language')) {
        AppConfig.saveSettings('language', 'en');
        AppConfig.saveSettings('prevent-recall', 'on');
        AppConfig.saveSettings('icon', 'black');
        AppConfig.saveSettings('multi-instance','on');
      }
    });

    app.on('activate', () => {
      if (this.wechatWindow == null) {
        this.createWeChatWindow();
      } else {
        this.wechatWindow.show();
      }
    });
  };

  initIPC() {
    ipcMain.on('badge-changed', (event, num) => {
      if (process.platform == "darwin") {
        app.dock.setBadge(num);
        if (num) {
          this.tray.setTitle(` ${num}`);
        } else {
          this.tray.setTitle('');
        }
      } else if (process.platform === "linux" || process.platform === "win32") {
          app.setBadgeCount(num * 1);
          this.tray.setUnreadStat((num * 1 > 0)? 1 : 0);
      }
    });

    ipcMain.on('user-logged', () => {
      this.wechatWindow.resizeWindow(true, this.splashWindow)
    });

    ipcMain.on('wx-rendered', (event, isLogged) => {
      this.wechatWindow.resizeWindow(isLogged, this.splashWindow)
    });

    ipcMain.on('log', (event, message) => {
      console.log(message);
    });

    ipcMain.on('reload', (event, repetitive) => {
      if (repetitive) {
        this.wechatWindow.loginState.current = this.wechatWindow.loginState.NULL;
        this.wechatWindow.connectWeChat();
      } else {
        this.wechatWindow.loadURL(Common.WEB_WECHAT);
      }
    });

    ipcMain.on('update', (event, message) => {
      let updateHandler = new UpdateHandler();
      updateHandler.checkForUpdate(`v${app.getVersion()}`, false);
    });

    ipcMain.on('open-settings-window', (event, message) => {
      if (this.settingsWindow) {
        this.settingsWindow.show();
      } else {
        this.createSettingsWindow();
        this.settingsWindow.show();
      }
    });

    ipcMain.on('close-settings-window', (event, messgae) => {
      this.settingsWindow.close();
      this.settingsWindow = null;
    })
  };

  createTray() {
    this.tray = new AppTray(this.splashWindow, this.wechatWindow);
  }

  createSplashWindow() {
    this.splashWindow = new SplashWindow();
    this.splashWindow.show();
  }

  createWeChatWindow() {
    this.wechatWindow = new WeChatWindow();
  }

  createSettingsWindow() {
    this.settingsWindow = new SettingsWindow();
  }

}

new ElectronicWeChat().init();


================================================
FILE: src/windows/controllers/app_tray.js
================================================
/**
 * Created by Zhongyi on 5/2/16.
 */

'use strict';

const path = require('path');
const { app, Menu, nativeImage, Tray, ipcMain } = require('electron');

const AppConfig = require('../../configuration');

const lan = AppConfig.readSettings('language');

const assetsPath = path.join(__dirname, '../../../assets');

let Common;
if (lan === 'zh-CN') {
  Common = require('../../common_cn');
} else {
  Common = require('../../common');
}

class AppTray {
  constructor(splashWindow, wechatWindow) {
    this.splashWindow = splashWindow;
    this.wechatWindow = wechatWindow;
    this.lastUnreadStat = 0;
    const trayColor = AppConfig.readSettings('tray-color');
    if (trayColor === 'white' || trayColor === 'black') {
      this.trayColor = trayColor;
    } else {
      this.trayColor = 'white';
      AppConfig.saveSettings('tray-color', this.trayColor);
    }
    this.createTray();
  }

  createTray() {
    let image;
    if (process.platform === 'linux' || process.platform === 'win32') {
      image = nativeImage.createFromPath(path.join(assetsPath, `tray_${this.trayColor}.png`));
      this.trayIcon = image;
      this.trayIconUnread = nativeImage.createFromPath(path.join(assetsPath, `tray_unread_${this.trayColor}.png`));
    } else {
      image = nativeImage.createFromPath(path.join(assetsPath, 'status_bar.png'));
    }
    image.setTemplateImage(true);

    this.tray = new Tray(image);
    this.tray.setToolTip(Common.ELECTRONIC_WECHAT);

    ipcMain.on('refreshIcon', () => this.refreshIcon());

    if (process.platform === 'linux' || process.platform === 'win32') {
      const contextMenu = Menu.buildFromTemplate([
        { label: 'Show', click: () => this.hideSplashAndShowWeChat() },
        { label: 'Exit', click: () => app.exit(0) },
      ]);
      this.tray.setContextMenu(contextMenu);
    }
    this.tray.on('click', () => this.hideSplashAndShowWeChat());
  }

  setTitle(title) {
    this.tray.setTitle(title);
  }

  hideSplashAndShowWeChat() {
    if (this.splashWindow.isShown) return;
    this.wechatWindow.show();
  }

  refreshIcon() {
    this.trayColor = AppConfig.readSettings('tray-color');
    this.trayIcon = nativeImage.createFromPath(path.join(assetsPath, `tray_${this.trayColor}.png`));
    this.trayIconUnread = nativeImage.createFromPath(path.join(assetsPath, `tray_unread_${this.trayColor}.png`));
    if (this.lastUnreadStat === 0) {
      this.tray.setImage(this.trayIcon);
    } else {
      this.tray.setImage(this.trayIconUnread);
    }
  }

  setUnreadStat(stat) {
    if (stat === this.lastUnreadStat) return;
    this.lastUnreadStat = stat;
    if (stat === 0) {
      this.tray.setImage(this.trayIcon);
    } else {
      this.tray.setImage(this.trayIconUnread);
    }
  }
}

module.exports = AppTray;


================================================
FILE: src/windows/controllers/settings.js
================================================
/**
 * Created by Ji on 9/15/16.
 */

'use strict';

const path = require('path');
const { BrowserWindow } = require('electron');
const electronLocalShortcut = require('electron-localshortcut');

const AppConfig = require('../../configuration');

const lan = AppConfig.readSettings('language');

let Common;
if (lan === 'zh-CN') {
  Common = require('../../common_cn');
} else {
  Common = require('../../common');
}

class SettingsWindow {
  constructor() {
    this.settingsWindow = null;
    this.createSettingsWindow();
  }

  createSettingsWindow() {
    this.settingsWindow = new BrowserWindow({
      width: Common.WINDOW_SIZE_SETTINGS.width,
      height: Common.WINDOW_SIZE_SETTINGS.height * 0.9,
      resizable: false,
      fullscreenable: false,
      show: false,
      frame: true,
      alwaysOnTop: true,
      icon: 'assets/icon.png',
      titleBarStyle: 'hidden',
    });

    this.initWindowEvents();
    this.initSettingsWindowShortcut();

    this.settingsWindow.loadURL(`file://${path.join(__dirname, '/../views/settings.html')}`);
  }

  initWindowEvents() {
    this.settingsWindow.on('close', () => {
      this.unregisterLocalShortCut();
      this.settingsWindow = null;
      this.isShown = false;
    });
    this.settingsWindow.once('ready-to-show', () => {
      this.settingsWindow.show();
    });
  }

  show() {
    if (!this.settingsWindow) {
      this.createSettingsWindow();
    }
    this.settingsWindow.show();
    this.isShown = true;
  }

  hide() {
    this.settingsWindow.hide();
    this.isShown = false;
  }

  registerLocalShortcut() {
    electronLocalShortcut.register(this.settingsWindow, 'Esc', () => {
      this.settingsWindow.close();
    });
  }

  unregisterLocalShortCut() {
    electronLocalShortcut.unregisterAll(this.settingsWindow);
  }

  initSettingsWindowShortcut() {
    this.registerLocalShortcut();
  }
}

module.exports = SettingsWindow;


================================================
FILE: src/windows/controllers/splash.js
================================================
/**
 * Created by Zhongyi on May 1, 2016
 */

'use strict';

const path = require('path');
const { BrowserWindow } = require('electron');

const AppConfig = require('../../configuration');

const lan = AppConfig.readSettings('language');

let Common;
if (lan === 'zh-CN') {
  Common = require('../../common_cn');
} else {
  Common = require('../../common');
}

class SplashWindow {
  constructor() {
    this.splashWindow = new BrowserWindow({
      width: Common.WINDOW_SIZE_LOADING.width,
      height: Common.WINDOW_SIZE_LOADING.height,
      title: Common.ELECTRONIC_WECHAT,
      resizable: false,
      center: true,
      show: true,
      frame: false,
      autoHideMenuBar: true,
      alwaysOnTop: true,
      icon: 'assets/icon.png',
      titleBarStyle: 'hidden',
    });

    this.splashWindow.loadURL(`file://${path.join(__dirname, '/../views/splash.html')}`);
    this.isShown = false;
  }

  show() {
    this.splashWindow.show();
    this.isShown = true;
  }

  hide() {
    this.splashWindow.hide();
    this.isShown = false;
  }
}

module.exports = SplashWindow;


================================================
FILE: src/windows/controllers/wechat.js
================================================
/**
 * Created by Zhongyi on 5/2/16.
 */

'use strict';

const path = require('path');
const isXfce = require('is-xfce');
const { app, shell, BrowserWindow } = require('electron');
const electronLocalShortcut = require('electron-localshortcut');

const AppConfig = require('../../configuration');

const CSSInjector = require('../../inject/css');
const MessageHandler = require('../../handlers/message');
const UpdateHandler = require('../../handlers/update');

const lan = AppConfig.readSettings('language');

let Common;
if (lan === 'zh-CN') {
  Common = require('../../common_cn');
} else {
  Common = require('../../common');
}

class WeChatWindow {
  constructor() {
    this.isShown = false;
    this.loginState = { NULL: -2, WAITING: -1, YES: 1, NO: 0 };
    this.loginState.current = this.loginState.NULL;
    this.inervals = {};
    this.createWindow();
    this.initWechatWindowShortcut();
    this.initWindowEvents();
    this.initWindowWebContent();
  }

  resizeWindow(isLogged, splashWindow) {
    const size = isLogged ? Common.WINDOW_SIZE : Common.WINDOW_SIZE_LOGIN;

    this.wechatWindow.setResizable(isLogged);
    this.wechatWindow.setSize(size.width, size.height);
    if (this.loginState.current === 1 - isLogged || this.loginState.current === this.loginState.WAITING) {
      splashWindow.hide();
      this.show();
      this.wechatWindow.center();
      this.loginState.current = isLogged;
    }
  }

  createWindow() {
    this.wechatWindow = new BrowserWindow({
      title: Common.ELECTRONIC_WECHAT,
      resizable: true,
      center: true,
      show: false,
      frame: true,
      autoHideMenuBar: true,
      icon: path.join(__dirname, '../../../assets/icon.png'),
      titleBarStyle: 'hidden-inset',
      webPreferences: {
        javascript: true,
        plugins: true,
        nodeIntegration: false,
        webSecurity: false,
        preload: path.join(__dirname, '../../inject/preload.js'),
      },
    });

    /* menu is always visible on xfce session */
    isXfce().then(data => {
      if(data) {
        this.wechatWindow.setMenuBarVisibility(true);
        this.wechatWindow.setAutoHideMenuBar(false);
      }
    });
  }

  loadURL(url) {
    this.wechatWindow.loadURL(url);
  }

  show() {
    this.wechatWindow.show();
    this.wechatWindow.focus();
    this.wechatWindow.webContents.send('show-wechat-window');
    this.isShown = true;
  }

  hide() {
    this.wechatWindow.hide();
    this.wechatWindow.webContents.send('hide-wechat-window');
    this.isShown = false;
  }

  connectWeChat() {
    Object.keys(this.inervals).forEach((key, index) => {
      clearInterval(key);
      delete this.inervals[key];
    });

    this.loadURL(Common.WEB_WECHAT);
    const int = setInterval(() => {
      if (this.loginState.current === this.loginState.NULL) {
        this.loadURL(Common.WEB_WECHAT);
        console.log('Reconnect.');
      }
    }, 5000);
    this.inervals[int] = true;
  }

  initWindowWebContent() {
    this.wechatWindow.webContents.setUserAgent(Common.USER_AGENT[process.platform]);
    if (Common.DEBUG_MODE) {
      this.wechatWindow.webContents.openDevTools();
    }

    this.connectWeChat();

    this.wechatWindow.webContents.on('will-navigate', (ev, url) => {
      if (/(.*wx.*\.qq\.com.*)|(web.*\.wechat\.com.*)/.test(url)) return;
      ev.preventDefault();
    });

    this.wechatWindow.webContents.on('dom-ready', () => {
      this.wechatWindow.webContents.insertCSS(CSSInjector.commonCSS);
      if (process.platform === 'darwin') {
        this.wechatWindow.webContents.insertCSS(CSSInjector.osxCSS);
      }

      if (!UpdateHandler.CHECKED) {
        new UpdateHandler().checkForUpdate(`v${app.getVersion()}`, true);
      }
    });

    this.wechatWindow.webContents.on('new-window', (event, url) => {
      event.preventDefault();
      shell.openExternal(new MessageHandler().handleRedirectMessage(url));
    });

    this.wechatWindow.webContents.on('will-navigate', (event, url) => {
      if (url.endsWith('/fake')) event.preventDefault();
    });
  }

  initWindowEvents() {
    this.wechatWindow.on('close', (e) => {
      if (this.wechatWindow.isVisible()) {
        e.preventDefault();
        this.hide();
      }
      this.unregisterLocalShortCut();
    });

    this.wechatWindow.on('page-title-updated', (ev) => {
      if (this.loginState.current === this.loginState.NULL) {
        this.loginState.current = this.loginState.WAITING;
      }
      ev.preventDefault();
    });

    this.wechatWindow.on('show', () => {
      this.registerLocalShortcut();
    });
  }

  registerLocalShortcut() {
    electronLocalShortcut.register(this.wechatWindow, 'CommandOrControl + H', () => {
      this.wechatWindow.hide();
    });
  }

  unregisterLocalShortCut() {
    electronLocalShortcut.unregisterAll(this.wechatWindow);
  }

  initWechatWindowShortcut() {
    this.registerLocalShortcut();
  }
}

module.exports = WeChatWindow;


================================================
FILE: src/windows/styles/settings.css
================================================
* {
  -webkit-user-select: none;
  cursor: default !important;
  -webkit-user-drag: none;
}

body {
  margin: 0;
  padding: 0;
  color: #364854;
  font-family: "Microsoft Yahei", "微软雅黑", STXihei, "华文细黑", sans-serif;
  background-color: #F3F3F3;
}

div {
  margin: 0;
  padding: 0;
}

ul {
  list-style: none;
}

h1 {
  color: #364854;
}

section {
  position: relative;
  width: 75%;
  left: 12.5%;
  border-bottom: 1px solid gray;
  overflow: hidden;
}

.page {
  min-width: 500px;
  min-height: 350px;
}

.setting-menu {
  padding-top: 5px;
}

.menu-title {
  position: relative;
  left: 20%;
}

.menu-desc {
  position: relative;
  left: 20%;
}

.menu-button {
  position: relative;
  left: 20%;
}

.setting-top-bar {
  padding: 0;
  margin: 0 0 10px 0;
  border: none;
  height: 140px;
  width: 100%;
  overflow: hidden;
  background-color: #CCC;
  box-shadow: 0px 5px 5px #CCC;
}

.title-list {
  padding-top: 1px;
}

.top-bar-icon {
  width: 100px;
  height: 100px;
  float: left;
  margin: 15px;
  margin-left: 30px;
}

.top-bar-left {
  float: left;
  width: 12%;
  padding: 1%;
}

.top-bar-middle {
  text-align: center;
}

.top-bar-right {
  text-align: center;
  float: right;
  width: 18%;
  margin-right: 40px;
  padding-top: 20px;
}

.upgrade-btn {
  border-radius: 15px;
  margin-bottom: 10px;
  color: #c9c9c9;
  font-size: 16px;
  background: #364854;
  padding: 10px 20px 10px 20px;
  text-decoration: none;
  width: 125px;
}


================================================
FILE: src/windows/styles/splash.css
================================================
* {
  -webkit-user-select: none;
  cursor: default !important;
  -webkit-user-drag: none;
}
body {
  overflow: hidden;
  margin: 0;
  background: #ECEFF1;
}
#splash_container {
  margin: 10px 20px;
}
#splash_text {
  font-family: sans-serif;
  font-size: 40px;
  color: #666;
  vertical-align: top;
  line-height: 100px;
  animation: fadein 0.75s ease-out;
}
#splash_loading_img {
  width: 100px;
  margin: 15px -10px;
  display: inline-block;
  vertical-align: middle;
  animation: increase 0.5s ease-out;
}
@keyframes fadein {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
@keyframes increase {
  from {
    opacity: 0;
    width: 0;
    margin: 52px 40px;
  }
  to {
    opacity: 1;
    width: 100px;
    margin: 15px -10px;
  }
}


================================================
FILE: src/windows/views/settings.html
================================================
<!DOCTYPE html>
<html lang="en">

<head>
  <link href="../styles/settings.css" rel="stylesheet">
  <meta charset="UTF-8">
  <title>Settings</title>
</head>

<body class="page">
  <div class="setting-top-bar">
    <div class="top-bar-left">
      <img class="top-bar-icon" src="../../../assets/icon.png">
    </div>
    <div class="top-bar-right">
      <button type="button" class="upgrade-btn" id="upgrade-btn" onclick="upgrade()">检查更新</button>
      <button type="button" class="upgrade-btn" id="feedback-btn" onclick="feedback()">联系我们</button>
    </div>
    <div class="top-bar-middle">
      <ul class="title-list">
        <li>
          <h1>Electronic Wechat V2.0.0</h1></li>
        <li>
          <h1 style="font-size:95%;">Powered by Electron V<span id="top-title-electron-ver">process.versions.electron</span></h1></li>
      </ul>
    </div>
  </div>
  <div class="setting-menu">
    <section>
      <ul>
        <li class="menu-title">
          <h3 id="app-language-title">语言(重启生效)</h3>
        </li>
        <li class="menu-desc">
          <h4 id="app-language-desc">选择你希望使用的默认语言</h4>
        </li>
        <li class="menu-button">
          <select class="" id="app-language-select" required>
            <option value="en">English</option>
            <option value="zh-CN">简体中文</option>
          </select>
        </li>
      </ul>
    </section>
    <section>
      <ul>
        <li class="menu-title">
          <h3 id="app-recall-title">阻止消息撤回</h3>
        </li>
        <li class="menu-desc">
          <h4 id="app-recall-desc">选择是否阻止微信的消息撤回功能</h4>
        </li>
        <li class="menu-button">
          <select class="" id="app-recall-select">
            <option value="on">On</option>
            <option value="off">Off</option>
          </select>
        </li>
      </ul>
    </section>
    <section>
      <ul>
        <li class="menu-title">
          <h3 id="app-instance-title">是否允许开启多个实例</h3>
        </li>
        <li class="menu-desc">
          <h4 id="app-instance-desc">多个实例可以同时登录不同帐号</h4>
        </li>
        <li class="menu-button">
          <select id="app-instance-select">
            <option value="on">On</option>
            <option value="off">Off</option>
          </select>
        </li>
      </ul>
    </section>
    <section>
      <ul>
        <li class="menu-title">
          <h3 id="app-icon-title">Flash 路径 (即将上线)</h3>
        </li>
        <li class="menu-desc">
          <h4 id="app-icon-desc">默认路径</h4>
        </li>
        <li class="menu-button">
          <input type="text" placeholder="File Path...">
        </li>
      </ul>
    </section>
    <section id="app-tray">
      <ul>
        <li class="menu-title">
          <h3 id="app-tray-title">托盘图标颜色(黑/白)</h3>
        </li>
        <li class="menu-desc">
          <h4 id="app-tray-desc">选择一个适合当前主题的颜色</h4>
        </li>
        <li class="menu-button">
          <select id="app-tray-select">
            <option value="black">◆</option>
            <option value="white">◇</option>
          </select>
        </li>
      </ul>
    </section>
  </div>

  <script>
    const AppConfig = require('../../configuration');
    const {
      remote,
      shell,
      ipcRenderer
    } = require('electron');

    const lan = AppConfig.readSettings('language');
    const recall = AppConfig.readSettings('prevent-recall');
    const instance = AppConfig.readSettings('multi-instance');
    const trayColor = AppConfig.readSettings('tray-color');

    const lanSelect = $('app-language-select');
    const recallSelect = $('app-recall-select');
    const instanceSelect = $('app-instance-select');
    const trayColorSelect = $('app-tray-select');

    function $(id) {
      return document.getElementById(id);
    }
    
    if(process.platform === 'darwin') {
      $('process.platform').style.display = 'none';
    }

    $('top-title-electron-ver').innerText = process.versions.electron;
    setConfig();
    setListeners()

    let Common;
    if (lan === 'zh-CN') {
      Common = require('../../common_cn');
    } else {
      Common = require('../../common');
      setLocale();
    }

    function setListeners() {
      lanSelect.addEventListener('change', function() {
        AppConfig.saveSettings('language', lanSelect.value)
      })
      recallSelect.addEventListener('change', function() {
        AppConfig.saveSettings('prevent-recall', recallSelect.value)
      })
      instanceSelect.addEventListener('change', function() {
        AppConfig.saveSettings('multi-instance', instanceSelect.value)
      })
      trayColorSelect.addEventListener('change', function() {
        AppConfig.saveSettings('tray-color', trayColorSelect.value)
        ipcRenderer.send('refreshIcon')
      })
    }

    function setConfig() {
      $('app-language-select').value = lan;
      $('app-recall-select').value = recall;
      $('app-instance-select').value = instance;
      $('app-tray-select').value = trayColor;
    }

    function setLocale() {
      $('app-language-title').innerHTML = Common.languageTitle;
      $('app-language-desc').innerHTML = Common.languageDesc;
      $('app-recall-title').innerHTML = Common.recallTitle;
      $('app-recall-desc').innerHTML = Common.recallDesc;
      $('app-instance-title').innerHTML = Common.instanceTitle;
      $('app-instance-desc').innerHTML = Common.instanceDesc;
      $('app-icon-title').innerHTML = Common.iconTitle;
      $('app-icon-desc').innerHTML = Common.iconDesc;
      $('app-tray-title').innerHTML = Common.trayTitle;
      $('app-tray-desc').innerHTML = Common.trayDesc;
      $('upgrade-btn').innerHTML = Common.UPGRADE;
      $('feedback-btn').innerHTML = Common.FEEDBACK;
    }

    function feedback() {
      shell.openExternal(Common.GITHUB_ISSUES);
    }

    function upgrade() {
      ipcRenderer.send('update');
    }

    function KeyDownFn(evt) {
      if (evt.keyCode == 73 && evt.ctrlKey && evt.shiftKey) evt.preventDefault();
    }

  </script>
</body>

</html>


================================================
FILE: src/windows/views/splash.html
================================================
<!DOCTYPE html>
<html lang="en">

<head>
  <link href="../styles/splash.css" rel="stylesheet">
  <meta charset="UTF-8">
  <title>Starting App</title>
</head>

<body>
  <div id="splash_container">
    <img id="splash_loading_img" src="../../../assets/loading.gif">
    <span id="splash_text">Starting App</span>
  </div>
</body>

</html>
Download .txt
gitextract_2blxg1ih/

├── .eslintrc
├── .gitignore
├── .travis.yml
├── CHANGELOG.md
├── CONTRIBUTING.md
├── ISSUE_TEMPLATE.md
├── LICENSE.md
├── README.md
├── README_zh.md
├── assets/
│   └── icon.icns
├── config.json
├── package.json
├── scripts/
│   ├── build-all.sh
│   ├── build-win32.bat
│   ├── build.sh
│   ├── qiniu.sh
│   └── tar-all.sh
└── src/
    ├── common.js
    ├── common_cn.js
    ├── configuration.js
    ├── handlers/
    │   ├── menu.js
    │   ├── message.js
    │   └── update.js
    ├── inject/
    │   ├── badge_count.js
    │   ├── css.js
    │   ├── emoji_parser.js
    │   ├── mention_menu.js
    │   ├── preload.js
    │   └── share_menu.js
    ├── main.js
    └── windows/
        ├── controllers/
        │   ├── app_tray.js
        │   ├── settings.js
        │   ├── splash.js
        │   └── wechat.js
        ├── styles/
        │   ├── settings.css
        │   └── splash.css
        └── views/
            ├── settings.html
            └── splash.html
Download .txt
SYMBOL INDEX (90 symbols across 17 files)

FILE: src/common.js
  class Common (line 7) | class Common {

FILE: src/common_cn.js
  class Common (line 5) | class Common {

FILE: src/configuration.js
  function getUserHome (line 3) | function getUserHome() {
  function saveSettings (line 11) | function saveSettings(settingKey, settingValue) {
  function readSettings (line 16) | function readSettings(settingKey) {

FILE: src/handlers/menu.js
  class MenuHandler (line 16) | class MenuHandler {
    method create (line 17) | create() {
    method getTemplate (line 25) | getTemplate(platform) {
    method _quitApp (line 260) | static _quitApp() {
    method _reload (line 264) | static _reload() {
    method _devTools (line 268) | static _devTools() {
    method _github (line 272) | static _github() {
    method _githubIssues (line 276) | static _githubIssues() {
    method _update (line 280) | static _update() {
    method _preference (line 284) | static _preference() {

FILE: src/handlers/message.js
  class MessageHandler (line 6) | class MessageHandler {
    method handleRedirectMessage (line 7) | handleRedirectMessage(origin) {

FILE: src/handlers/update.js
  class UpdateHandler (line 20) | class UpdateHandler {
    method checkForUpdate (line 21) | checkForUpdate(version, silent) {
    method showDialog (line 58) | showDialog(message, detail, positiveButton, callback) {
    method _parseUpdateData (line 73) | _parseUpdateData(body, version, res, rej) {

FILE: src/inject/badge_count.js
  class BadgeCount (line 7) | class BadgeCount {
    method init (line 8) | static init() {

FILE: src/inject/css.js
  class CSSInjector (line 7) | class CSSInjector {

FILE: src/inject/emoji_parser.js
  function unicodeToString (line 10) | function unicodeToString(point) {
  class EmojiParser (line 17) | class EmojiParser {
    method emojiSpanToString (line 18) | static emojiSpanToString(str) {
    method emojiToImage (line 25) | static emojiToImage(str) {

FILE: src/inject/mention_menu.js
  class MentionMenu (line 9) | class MentionMenu {
    method init (line 11) | static init() {
    method inject (line 32) | static inject($event) {
    method getMenuPosition (line 81) | static getMenuPosition($editArea, probePosition) {
    method isValidNameHint (line 96) | static isValidNameHint(nameHint, userName) {
    method generateOptionFromMember (line 112) | static generateOptionFromMember($scope, member) {

FILE: src/inject/preload.js
  class Injector (line 14) | class Injector {
    method init (line 15) | init() {
    method initAngularInjection (line 28) | initAngularInjection() {
    method initInjectBundle (line 58) | initInjectBundle() {
    method transformResponse (line 76) | transformResponse(value, constants) {
    method lock (line 90) | static lock(object, key, value) {
    method checkEmojiContent (line 97) | checkEmojiContent(value, constants) {
    method checkTemplateContent (line 125) | checkTemplateContent(value) {
    method initIPC (line 136) | initIPC() {

FILE: src/inject/share_menu.js
  class ShareMenu (line 6) | class ShareMenu {
    method inject (line 7) | static inject() {
    method get (line 18) | static get(link) {
    method genShareMenuItem (line 60) | static genShareMenuItem(target) {

FILE: src/main.js
  class ElectronicWeChat (line 15) | class ElectronicWeChat {
    method constructor (line 16) | constructor() {
    method init (line 23) | init() {
    method checkInstance (line 31) | checkInstance() {
    method initApp (line 47) | initApp() {
    method initIPC (line 70) | initIPC() {
    method createTray (line 126) | createTray() {
    method createSplashWindow (line 130) | createSplashWindow() {
    method createWeChatWindow (line 135) | createWeChatWindow() {
    method createSettingsWindow (line 139) | createSettingsWindow() {

FILE: src/windows/controllers/app_tray.js
  class AppTray (line 23) | class AppTray {
    method constructor (line 24) | constructor(splashWindow, wechatWindow) {
    method createTray (line 38) | createTray() {
    method setTitle (line 64) | setTitle(title) {
    method hideSplashAndShowWeChat (line 68) | hideSplashAndShowWeChat() {
    method refreshIcon (line 73) | refreshIcon() {
    method setUnreadStat (line 84) | setUnreadStat(stat) {

FILE: src/windows/controllers/settings.js
  class SettingsWindow (line 22) | class SettingsWindow {
    method constructor (line 23) | constructor() {
    method createSettingsWindow (line 28) | createSettingsWindow() {
    method initWindowEvents (line 47) | initWindowEvents() {
    method show (line 58) | show() {
    method hide (line 66) | hide() {
    method registerLocalShortcut (line 71) | registerLocalShortcut() {
    method unregisterLocalShortCut (line 77) | unregisterLocalShortCut() {
    method initSettingsWindowShortcut (line 81) | initSettingsWindowShortcut() {

FILE: src/windows/controllers/splash.js
  class SplashWindow (line 21) | class SplashWindow {
    method constructor (line 22) | constructor() {
    method show (line 41) | show() {
    method hide (line 46) | hide() {

FILE: src/windows/controllers/wechat.js
  class WeChatWindow (line 27) | class WeChatWindow {
    method constructor (line 28) | constructor() {
    method resizeWindow (line 39) | resizeWindow(isLogged, splashWindow) {
    method createWindow (line 52) | createWindow() {
    method loadURL (line 80) | loadURL(url) {
    method show (line 84) | show() {
    method hide (line 91) | hide() {
    method connectWeChat (line 97) | connectWeChat() {
    method initWindowWebContent (line 113) | initWindowWebContent() {
    method initWindowEvents (line 147) | initWindowEvents() {
    method registerLocalShortcut (line 168) | registerLocalShortcut() {
    method unregisterLocalShortCut (line 174) | unregisterLocalShortCut() {
    method initWechatWindowShortcut (line 178) | initWechatWindowShortcut() {
Condensed preview — 38 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (81K chars).
[
  {
    "path": ".eslintrc",
    "chars": 646,
    "preview": "{\n  \"parser\": \"babel-eslint\",\n  \"extends\": \"airbnb/base\",\n  \"rules\": {\n      \"strict\": \"off\",\n      \"max-len\": \"off\",\n  "
  },
  {
    "path": ".gitignore",
    "chars": 115,
    "preview": ".DS_Store\n/dist\nnpm-debug.log*\n.idea\n\n# Dependency directories\nnode_modules\n\n*.sublime-project\n*.sublime-workspace\n"
  },
  {
    "path": ".travis.yml",
    "chars": 1449,
    "preview": "language: node_js\nsudo: required\nnode_js:\n- '5.2'\nbranches:\n  only:\n  - master\n  - production\nbefore_script:\n- npm insta"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 2985,
    "preview": "# CHANGELOG\n\n**v2.0 (2017.02.13) CN**\n\n1. 升级 **Electron** 至 **V1.4.15**,**Chromium** 至 **54**\n2. 增加了**偏好设置**(感谢设计建议 @**["
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 747,
    "preview": "# Contributing to Electronic WeChat\n\nFirst of all, thanks for contributing to this project. It would be appreciated if y"
  },
  {
    "path": "ISSUE_TEMPLATE.md",
    "chars": 583,
    "preview": "#### Description\n\nFirst of all, thanks for your attention to open an issue for this project.\nPlease notice that if you a"
  },
  {
    "path": "LICENSE.md",
    "chars": 1079,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2017 Zhongyi Tong\n\nPermission is hereby granted, free of charge, to any person obta"
  },
  {
    "path": "README.md",
    "chars": 5182,
    "preview": "<img src=\"assets/icon.png\" alt=\"logo\" height=\"120\" align=\"right\" />\n\n# Electronic WeChat\n\n*A better WeChat on macOS and "
  },
  {
    "path": "README_zh.md",
    "chars": 2145,
    "preview": "<img src=\"assets/icon.png\" alt=\"logo\" height=\"120\" align=\"right\" />\n\n# Electronic WeChat\n\n[![Gitter](https://badges.gitt"
  },
  {
    "path": "config.json",
    "chars": 270,
    "preview": "{\n  \"osx\" : {\n    \"title\": \"Electronic Wechat\",\n    \"background\": \"icon.png\",\n    \"icon\": \"icon.icns\",\n    \"icon-size\": "
  },
  {
    "path": "package.json",
    "chars": 1503,
    "preview": "{\n  \"name\": \"electronic-wechat\",\n  \"version\": \"2.0.0\",\n  \"description\": \"An Electron application for WeChat\",\n  \"main\": "
  },
  {
    "path": "scripts/build-all.sh",
    "chars": 299,
    "preview": "#!/bin/bash\n\nif ! hash electron-packager 2>/dev/null; then\n  RED='\\033[0;31m'\n  NC='\\033[0m'\n  echo \"${RED}Error${NC}: y"
  },
  {
    "path": "scripts/build-win32.bat",
    "chars": 334,
    "preview": "set PLATFORM=%1%\nset ARCH=%2%\nset APP_NAME=\"Electronic WeChat\"\n\nset ignore_list=\"dist|scripts|\\.idea|.*\\.md|.*\\.yml|node"
  },
  {
    "path": "scripts/build.sh",
    "chars": 1178,
    "preview": "#!/bin/bash\n\nif ! hash electron-packager 2>/dev/null; then\n  RED='\\033[0;31m'\n  NC='\\033[0m'\n  echo \"${RED}Error${NC}: y"
  },
  {
    "path": "scripts/qiniu.sh",
    "chars": 788,
    "preview": "#!/bin/bash\n\ncase \"$(uname -s)\" in\n\n    Linux*)\n        wget http://devtools.qiniu.com/qiniu-devtools-linux_amd64-curren"
  },
  {
    "path": "scripts/tar-all.sh",
    "chars": 449,
    "preview": "#!/bin/bash\n\ncd dist\n\necho 'Start compressing for Mac OS X.'\ntar zcf 'mac-osx.tar.gz' 'Electronic WeChat-darwin-x64'\nech"
  },
  {
    "path": "src/common.js",
    "chars": 3791,
    "preview": "/**\n * Created by Zhongyi on 3/26/16.\n */\n\n'use strict';\n\nclass Common {\n\n}\nCommon.ELECTRON = 'Electron';\nCommon.ELECTRO"
  },
  {
    "path": "src/common_cn.js",
    "chars": 2883,
    "preview": "/**\n * Created by Zhongyi on 3/26/16.\n */\n'use strict';\nclass Common {\n\n}\nCommon.ELECTRON = 'Electron';\nCommon.ELECTRONI"
  },
  {
    "path": "src/configuration.js",
    "chars": 451,
    "preview": "'use strict';\n\nfunction getUserHome() {\n  return process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME'];\n}"
  },
  {
    "path": "src/handlers/menu.js",
    "chars": 6929,
    "preview": "'use strict';\n\nconst { remote, shell, ipcRenderer } = require('electron');\nconst AppConfig = require('../configuration')"
  },
  {
    "path": "src/handlers/message.js",
    "chars": 239,
    "preview": "'use strict';\n\nconst qs = require('querystring');\nconst url = require('url');\n\nclass MessageHandler {\n  handleRedirectMe"
  },
  {
    "path": "src/handlers/update.js",
    "chars": 2569,
    "preview": "/**\n * Created by Zhongyi on 3/25/16.\n */\n\n'use strict';\n\nconst { dialog, shell, app, nativeImage } = require('electron'"
  },
  {
    "path": "src/inject/badge_count.js",
    "chars": 508,
    "preview": "/**\n * Created by Zhongyi on 4/12/16.\n */\n'use strict';\nconst { ipcRenderer } = require('electron');\n\nclass BadgeCount {"
  },
  {
    "path": "src/inject/css.js",
    "chars": 3251,
    "preview": "/**\n * Created by Zhongyi on 2/23/16.\n */\n'use strict';\nconst Common = require('../common');\n\nclass CSSInjector {\n}\n\nCSS"
  },
  {
    "path": "src/inject/emoji_parser.js",
    "chars": 783,
    "preview": "/**\n * Created by chenwl on 9/29/16.\n */\n\nvar emojione = require('emojione');\n\n// <span class=\"emoji emoji1f471\"></span>"
  },
  {
    "path": "src/inject/mention_menu.js",
    "chars": 4058,
    "preview": "/**\n * Created by Zhongyi on 4/9/16.\n */\n\n'use strict';\nconst Common = require('../common');\nconst pinyin = require('pin"
  },
  {
    "path": "src/inject/preload.js",
    "chars": 5013,
    "preview": "'use strict';\n\nconst { ipcRenderer, webFrame } = require('electron');\nconst MenuHandler = require('../handlers/menu');\nc"
  },
  {
    "path": "src/inject/share_menu.js",
    "chars": 2268,
    "preview": "/**\n * Created by oBlank on 3/31/16.\n */\n'use strict';\n\nclass ShareMenu {\n  static inject() {\n    const dropdownMenu = $"
  },
  {
    "path": "src/main.js",
    "chars": 3802,
    "preview": "'use strict';\n\nconst path = require('path');\nconst {app, ipcMain} = require('electron');\n\nconst UpdateHandler = require("
  },
  {
    "path": "src/windows/controllers/app_tray.js",
    "chars": 2771,
    "preview": "/**\n * Created by Zhongyi on 5/2/16.\n */\n\n'use strict';\n\nconst path = require('path');\nconst { app, Menu, nativeImage, T"
  },
  {
    "path": "src/windows/controllers/settings.js",
    "chars": 1908,
    "preview": "/**\n * Created by Ji on 9/15/16.\n */\n\n'use strict';\n\nconst path = require('path');\nconst { BrowserWindow } = require('el"
  },
  {
    "path": "src/windows/controllers/splash.js",
    "chars": 1083,
    "preview": "/**\n * Created by Zhongyi on May 1, 2016\n */\n\n'use strict';\n\nconst path = require('path');\nconst { BrowserWindow } = req"
  },
  {
    "path": "src/windows/controllers/wechat.js",
    "chars": 4935,
    "preview": "/**\n * Created by Zhongyi on 5/2/16.\n */\n\n'use strict';\n\nconst path = require('path');\nconst isXfce = require('is-xfce')"
  },
  {
    "path": "src/windows/styles/settings.css",
    "chars": 1444,
    "preview": "* {\n  -webkit-user-select: none;\n  cursor: default !important;\n  -webkit-user-drag: none;\n}\n\nbody {\n  margin: 0;\n  paddi"
  },
  {
    "path": "src/windows/styles/splash.css",
    "chars": 746,
    "preview": "* {\n  -webkit-user-select: none;\n  cursor: default !important;\n  -webkit-user-drag: none;\n}\nbody {\n  overflow: hidden;\n "
  },
  {
    "path": "src/windows/views/settings.html",
    "chars": 5981,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n  <link href=\"../styles/settings.css\" rel=\"stylesheet\">\n  <meta charset=\"UTF-8\""
  },
  {
    "path": "src/windows/views/splash.html",
    "chars": 337,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n  <link href=\"../styles/splash.css\" rel=\"stylesheet\">\n  <meta charset=\"UTF-8\">\n"
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the zhongyi-tong/electronic-wechat GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 38 files (73.7 KB), approximately 22.0k tokens, and a symbol index with 90 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!