完成新版
parent
ad3a1d37d7
commit
c4da229ad0
|
@ -0,0 +1,7 @@
|
||||||
|
node_modules/
|
||||||
|
build/
|
||||||
|
icons/
|
||||||
|
package-lock.json
|
||||||
|
|
||||||
|
|
||||||
|
.D_Store
|
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Debug Main Process",
|
||||||
|
"type": "node",
|
||||||
|
"request": "launch",
|
||||||
|
"cwd": "${workspaceRoot}",
|
||||||
|
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron",
|
||||||
|
"windows": {
|
||||||
|
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron.cmd"
|
||||||
|
},
|
||||||
|
"args": ["."]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
25
Readme.md
25
Readme.md
|
@ -1,17 +1,30 @@
|
||||||
# 钉钉App - Linux版
|
# 钉钉App - Linux版
|
||||||
> `非官方版`
|
> `非官方版`
|
||||||
|
|
||||||
> 该版本用nwjs基于网页版钉钉封装而成, 通过js注入的方式,实现记住密码(自动登录)功能,
|
> 最新的3.8.7改用electron封装。
|
||||||
> 关闭驻留,最小化到托盘等实用功能。
|
>> 因为最近钉钉取消了账号登录, 所以移除了之前记住账号的 注入脚本。
|
||||||
|
>> 注入改为缓存登录token, 然后在下次启动时,把token放出来, 以达到自动登录的效果。(token的有效期为15天, 这是钉钉自己设置的, 项目没有对它进行任何修改)
|
||||||
|
>> **`注意: 该注入不一定能用。`**
|
||||||
|
|
||||||
该修改版并不对钉钉现有功能进行任何的修改,也不收集任何信息。
|
该修改版并不对钉钉现有功能进行任何的修改,也不收集任何信息。
|
||||||
代码量很少, 而且完全开源, 请放心使用。
|
代码量很少, 而且完全开源, 请放心使用。
|
||||||
|
|
||||||
|
|
||||||
## 使用方法
|
|
||||||
> 下载nwjs,编译运行,或直接使用nwjs运行。
|
![preview](./preview.png)
|
||||||
> nwjs具体方法请自行"网上搜索答案"
|
|
||||||
|
|
||||||
|
## 打包好的安装包
|
||||||
|
请进入`release`页面下载.
|
||||||
|
|
||||||
|
|
||||||
|
## 自行打包
|
||||||
|
```bash
|
||||||
|
# 下载源码, 进入源码目录
|
||||||
|
npm i
|
||||||
|
npm run pack
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
15
blank.html
15
blank.html
|
@ -1,15 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
|
||||||
<link rel="stylesheet" type="text/css" href="/css/base.css">
|
|
||||||
<style type="text/css">
|
|
||||||
body {overflow:hidden;position:absolute;width:100%;height:100%;}
|
|
||||||
.webview {display:block;width:100%;height:100%;}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
47
css/base.css
47
css/base.css
|
@ -1,47 +0,0 @@
|
||||||
@charset "UTF-8";
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @authors yutent (yutent@doui.cc)
|
|
||||||
* @date 2014-10-10 00:45:09
|
|
||||||
*
|
|
||||||
* doui的CSS规范
|
|
||||||
*
|
|
||||||
* 不能出现大写,以连字符风格命名
|
|
||||||
* 表示状态的应该用do-st-*命名
|
|
||||||
* 表示功能的应该用do-fn-*命名
|
|
||||||
* 表示页面模块的应该用do-mod-modname 命名
|
|
||||||
* 表示UI组件的应该用do-uiname命名, 它的子元素应该全部包在 .do-uiname这个根类下
|
|
||||||
* 如 .do-layer .body { ... }
|
|
||||||
*
|
|
||||||
* 样式规则的出现顺序
|
|
||||||
* 1 display float position overflow z-index 表示定位/布局的属性
|
|
||||||
* 2 width height margin padding border 表示盒子模型的属性
|
|
||||||
* 3 line-height font-size vertical-align text-align user-select outline ....排版相关的属性
|
|
||||||
* 4 color background opacity cursor ...表示装饰相关的属性
|
|
||||||
* 5 content list-style quotes ... 内容生成相关的属性
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
* {margin: 0;padding: 0;vertical-align: baseline;box-sizing:border-box;}
|
|
||||||
|
|
||||||
/* HTML5 display-role reset for older browsers */
|
|
||||||
article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section,content {display: block;}
|
|
||||||
img {border:0;display:inline-block;}
|
|
||||||
ol, ul {list-style: none;}
|
|
||||||
blockquote, q {quotes: none;}
|
|
||||||
blockquote:before, blockquote:after,
|
|
||||||
q:before, q:after {content: '';content: none;}
|
|
||||||
table {border-collapse: collapse;border-spacing: 0;}
|
|
||||||
|
|
||||||
.do-fn-cl { *zoom: 1; }
|
|
||||||
.do-fn-cl:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; overflow:hidden;}
|
|
||||||
.do-fn-clear {clear:both;display:inline;}
|
|
||||||
|
|
||||||
.do-fn-show{display:block;}
|
|
||||||
.do-fn-hide{display:none;}
|
|
||||||
.do-fn-fl{float:left;}
|
|
||||||
.do-fn-fr{float:right;}
|
|
||||||
.do-fn-noselect {-webkit-touch-callout: none;-webkit-user-select: none;-moz-user-select: none;user-select: none;}
|
|
||||||
.do-fn-noselect img, .do-fn-noselect a {-webkit-user-drag:none;}
|
|
||||||
.do-fn-ell {overflow:hidden; white-space:nowrap; text-overflow:ellipsis }
|
|
||||||
.do-st-thin {-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;}
|
|
||||||
.do-st-hand {cursor:pointer;}
|
|
Binary file not shown.
After Width: | Height: | Size: 8.7 KiB |
122
index.html
122
index.html
|
@ -1,122 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
|
||||||
<link rel="stylesheet" type="text/css" href="/css/base.css">
|
|
||||||
<style type="text/css">
|
|
||||||
body {overflow:hidden;position:absolute;width:1000px;height:662px;}
|
|
||||||
.webview {display:block;width:1000px;height:602px;}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<webview class="webview" src="https://im.dingtalk.com" partition="persist:googlepluswidgets"></webview>
|
|
||||||
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
let win = nw.Window.get();
|
|
||||||
let $wv = document.querySelector('.webview');
|
|
||||||
let tray = new nw.Tray({ title: '钉钉', icon: 'icon.png' });
|
|
||||||
let menu = new nw.Menu();
|
|
||||||
let show = new nw.MenuItem({label: '显示钉钉'})
|
|
||||||
let quit = new nw.MenuItem({label: '退出钉钉'})
|
|
||||||
show.click = function(){
|
|
||||||
win.show()
|
|
||||||
}
|
|
||||||
quit.click = function(){
|
|
||||||
win.close(true)
|
|
||||||
}
|
|
||||||
menu.append(show)
|
|
||||||
menu.append(quit)
|
|
||||||
tray.menu = menu
|
|
||||||
|
|
||||||
tray.on('click', function(){
|
|
||||||
win.show()
|
|
||||||
})
|
|
||||||
|
|
||||||
$wv.addEventListener('permissionrequest', function(ev) {
|
|
||||||
ev.request.allow();
|
|
||||||
});
|
|
||||||
|
|
||||||
function dialog(o, ev){
|
|
||||||
let res = o[ev.messageType](ev.messageText)
|
|
||||||
if(ev.messageType === 'confirm' || ev.messageType === 'prompt'){
|
|
||||||
if(res){
|
|
||||||
ev.dialog.ok(res);
|
|
||||||
}else{
|
|
||||||
ev.dialog.cancel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$wv.addEventListener('dialog', function(ev) {
|
|
||||||
dialog(window, ev)
|
|
||||||
});
|
|
||||||
|
|
||||||
$wv.addEventListener('newwindow', function(ev){
|
|
||||||
|
|
||||||
ev.preventDefault();
|
|
||||||
|
|
||||||
if(ev.targetUrl !== 'about:blank'){
|
|
||||||
nw.Window.open(ev.targetUrl, {width: 1200, height: 700, resizable: true})
|
|
||||||
}else{
|
|
||||||
let elem = document.createElement('webview');
|
|
||||||
elem.className = 'webview';
|
|
||||||
elem.addEventListener('permissionrequest', function(ev) {
|
|
||||||
ev.request.allow();
|
|
||||||
});
|
|
||||||
elem.setAttribute('partition', 'persist:googlepluswidgets')
|
|
||||||
ev.window.attach(elem)
|
|
||||||
nw.Window.open('blank.html', {width: 1200, height: 700, resizable: true, title: '钉钉邮箱'}, function(w){
|
|
||||||
elem.addEventListener('dialog', function(ev) {
|
|
||||||
dialog(w.window, ev)
|
|
||||||
});
|
|
||||||
w.window.addEventListener('load', function(){
|
|
||||||
w.window.document.body.appendChild(elem)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
$wv.addEventListener('contentload', function(ev){
|
|
||||||
$wv.executeScript({ code: `
|
|
||||||
nw.gui = nw.gui || nw;
|
|
||||||
let pwd = localStorage.getItem("pwd") || ''
|
|
||||||
localStorage.setItem("isBeepOpen", "true");
|
|
||||||
localStorage.setItem("notification", "true");
|
|
||||||
localStorage.setItem("newUserState", "secTip");
|
|
||||||
|
|
||||||
|
|
||||||
document.querySelectorAll('.tab-items li')[1].click()
|
|
||||||
|
|
||||||
let $form = document.querySelector('form[name=passwordForm]'), $pwd;
|
|
||||||
for(let i = 0,el;el = $form.elements[i++];){
|
|
||||||
if(el.type === 'password'){
|
|
||||||
$pwd = el;
|
|
||||||
el.value = pwd;
|
|
||||||
if(el.value){
|
|
||||||
let ev = document.createEvent('Event')
|
|
||||||
ev.initEvent('change', false, false)
|
|
||||||
el.dispatchEvent(ev);
|
|
||||||
}
|
|
||||||
|
|
||||||
}else if(el.type === 'submit'){
|
|
||||||
el.onclick = function(){
|
|
||||||
localStorage.setItem('pwd', $pwd.value)
|
|
||||||
}
|
|
||||||
// el.click()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`});
|
|
||||||
})
|
|
||||||
|
|
||||||
win.on('close', function(ev){
|
|
||||||
this.hide()
|
|
||||||
})
|
|
||||||
win.on('maximize', function(ev){
|
|
||||||
this.restore()
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
67
package.json
67
package.json
|
@ -1,28 +1,43 @@
|
||||||
{
|
{
|
||||||
"name": "dtalk",
|
"name": "dtalk",
|
||||||
"main": "index.html",
|
"version": "3.8.7",
|
||||||
"domain": "localhost",
|
"description": "钉钉-Linux版",
|
||||||
"version": "3.2.3",
|
"main": "src/main.js",
|
||||||
"description": "钉钉-Linux版",
|
"scripts": {
|
||||||
"window": {
|
"start": "electron .",
|
||||||
"title": "钉钉-Linux版",
|
"pack": "electron-builder"
|
||||||
"width": 1000,
|
},
|
||||||
"height": 602,
|
"author": {
|
||||||
"max_width": 1000,
|
"name": "yutent",
|
||||||
"max_height": 602,
|
"email": "yutent@doui.cc"
|
||||||
"min_width": 1000,
|
},
|
||||||
"min_height": 602,
|
"devDependencies": {
|
||||||
"as_desktop": true,
|
"electron": "^6.0.0",
|
||||||
"resizable": false,
|
"electron-builder": "^21.2.0"
|
||||||
"show_in_taskbar": true,
|
},
|
||||||
"icon": "icon.png"
|
"build": {
|
||||||
|
"appId": "cc.doui.dtalk",
|
||||||
|
"productName": "DingDing",
|
||||||
|
"copyright": "Copyright © 2019 ${author}",
|
||||||
|
"directories": {
|
||||||
|
"buildResources": "icons",
|
||||||
|
"output": "build"
|
||||||
},
|
},
|
||||||
"webview": {
|
"files": ["src/**/*"],
|
||||||
"partitions": [
|
"linux": {
|
||||||
{
|
"category": "Network;Chat",
|
||||||
"name": "trusted",
|
"target": [
|
||||||
"accessible_resources": [ "<all_urls>" ]
|
{
|
||||||
}
|
"target": "deb",
|
||||||
]
|
"arch": "x64"
|
||||||
}
|
},
|
||||||
}
|
{
|
||||||
|
"target": "AppImage",
|
||||||
|
"arch": "x64"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"icon": "./icons/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dependencies": {}
|
||||||
|
}
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 475 KiB |
Binary file not shown.
After Width: | Height: | Size: 8.7 KiB |
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
Binary file not shown.
After Width: | Height: | Size: 3.6 KiB |
|
@ -0,0 +1,31 @@
|
||||||
|
/* app */
|
||||||
|
const { app, session, Menu } = require('electron')
|
||||||
|
const path = require('path')
|
||||||
|
|
||||||
|
const log = console.log
|
||||||
|
|
||||||
|
const createTray = require('./tools/tray')
|
||||||
|
const { createMainWindow } = require('./tools/windows')
|
||||||
|
|
||||||
|
const ROOT = __dirname
|
||||||
|
|
||||||
|
/* ----------------------------------------------------- */
|
||||||
|
|
||||||
|
app.commandLine.appendSwitch('lang', 'zh-CN')
|
||||||
|
app.commandLine.appendSwitch('autoplay-policy', 'no-user-gesture-required')
|
||||||
|
|
||||||
|
Menu.setApplicationMenu(null)
|
||||||
|
|
||||||
|
/* ----------------------------------------------------- */
|
||||||
|
|
||||||
|
// 初始化应用
|
||||||
|
app.once('ready', () => {
|
||||||
|
// 修改app的UA
|
||||||
|
session.defaultSession.setUserAgent(
|
||||||
|
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36'
|
||||||
|
)
|
||||||
|
|
||||||
|
let win = createMainWindow(path.join(ROOT, './images/app.png'))
|
||||||
|
|
||||||
|
createTray(win)
|
||||||
|
})
|
|
@ -0,0 +1,35 @@
|
||||||
|
/**
|
||||||
|
* 托盘
|
||||||
|
* @author yutent<yutent@doui.cc>
|
||||||
|
* @date 2019/01/21 20:42:07
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
const { app, Tray, Menu } = require('electron')
|
||||||
|
const path = require('path')
|
||||||
|
const ROOT = __dirname
|
||||||
|
|
||||||
|
module.exports = function(win) {
|
||||||
|
app.__TRAY__ = new Tray(path.join(ROOT, '../images/tray.png'))
|
||||||
|
let menuList = Menu.buildFromTemplate([
|
||||||
|
{
|
||||||
|
label: '显示主窗口',
|
||||||
|
click() {
|
||||||
|
win.show()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ type: 'separator' },
|
||||||
|
{
|
||||||
|
label: '退出',
|
||||||
|
click() {
|
||||||
|
win.destroy()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
])
|
||||||
|
app.__TRAY__.on('click', _ => {
|
||||||
|
win.show()
|
||||||
|
})
|
||||||
|
|
||||||
|
app.__TRAY__.setContextMenu(menuList)
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
/**
|
||||||
|
* 各种窗口创建
|
||||||
|
* @author yutent<yutent@doui.cc>
|
||||||
|
* @date 2019/01/26 18:28:22
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
const { BrowserWindow } = require('electron')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用主窗口
|
||||||
|
*/
|
||||||
|
exports.createMainWindow = function(icon) {
|
||||||
|
// 创建浏览器窗口
|
||||||
|
let win = new BrowserWindow({
|
||||||
|
title: '钉钉-electron版',
|
||||||
|
width: 1000,
|
||||||
|
height: 602,
|
||||||
|
resizable: false,
|
||||||
|
// frame: false,
|
||||||
|
icon,
|
||||||
|
webPreferences: {
|
||||||
|
webSecurity: false,
|
||||||
|
experimentalFeatures: true
|
||||||
|
// webviewTag: true,
|
||||||
|
// nodeIntegration: true
|
||||||
|
},
|
||||||
|
show: false
|
||||||
|
})
|
||||||
|
|
||||||
|
// 然后加载应用的 index.html。
|
||||||
|
|
||||||
|
// win.loadURL('app://local/index.html')
|
||||||
|
win.loadURL('https://im.dingtalk.com')
|
||||||
|
|
||||||
|
win.on('ready-to-show', _ => {
|
||||||
|
win.show()
|
||||||
|
|
||||||
|
// win.openDevTools()
|
||||||
|
})
|
||||||
|
|
||||||
|
win.webContents.on('dom-ready', ev => {
|
||||||
|
win.webContents.executeJavaScript(
|
||||||
|
`
|
||||||
|
|
||||||
|
const shell = require('electron').shell;
|
||||||
|
|
||||||
|
// assuming $ is jQuery
|
||||||
|
$(document).on('click', 'a[href^="http"]', function(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
shell.openExternal(this.href);
|
||||||
|
});
|
||||||
|
|
||||||
|
localStorage.setItem("isBeepOpen", "true");
|
||||||
|
localStorage.setItem("notification", "true");
|
||||||
|
localStorage.setItem("newUserState", "secTip");
|
||||||
|
localStorage.setItem("latest_lang_info", "zh_CN");
|
||||||
|
|
||||||
|
if(localStorage.getItem('fuck2')){
|
||||||
|
|
||||||
|
sessionStorage.setItem('wk_device_id', localStorage.getItem('fuck1'))
|
||||||
|
sessionStorage.setItem('wk_token', localStorage.getItem('fuck2'))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!sessionStorage.getItem('first_in')){
|
||||||
|
sessionStorage.setItem('first_in', 1)
|
||||||
|
location.reload()
|
||||||
|
}
|
||||||
|
|
||||||
|
`,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
win.on('close', ev => {
|
||||||
|
ev.preventDefault()
|
||||||
|
win.webContents.executeJavaScript(
|
||||||
|
`
|
||||||
|
if(sessionStorage.getItem('wk_token')){
|
||||||
|
|
||||||
|
localStorage.setItem('fuck1', sessionStorage.getItem('wk_device_id'))
|
||||||
|
|
||||||
|
localStorage.setItem('fuck2', sessionStorage.getItem('wk_token'))
|
||||||
|
}
|
||||||
|
|
||||||
|
`,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
win.hide()
|
||||||
|
})
|
||||||
|
|
||||||
|
win.on('page-title-updated', ev => {
|
||||||
|
ev.preventDefault()
|
||||||
|
})
|
||||||
|
|
||||||
|
return win
|
||||||
|
}
|
Reference in New Issue