├── .gitattributes
├── README.md
├── release
├── myNewTabWE-1.0.xpi
├── myNewTabWE-1.1.xpi
├── myNewTabWE-1.10.xpi
├── myNewTabWE-1.11.1.xpi
├── myNewTabWE-1.11.xpi
├── myNewTabWE-1.2.1.xpi
├── myNewTabWE-1.2.xpi
├── myNewTabWE-1.3.xpi
├── myNewTabWE-1.4.xpi
├── myNewTabWE-1.5.xpi
├── myNewTabWE-1.6.1.xpi
├── myNewTabWE-1.6.xpi
├── myNewTabWE-1.7.xpi
├── myNewTabWE-1.8.1.xpi
├── myNewTabWE-1.8.xpi
├── myNewTabWE-1.9.1.xpi
├── myNewTabWE-1.9.xpi
└── updates.json
└── src
├── css
├── customize.css
├── index.css
├── options.css
└── weather.css
├── html
├── customize.html
├── index.html
└── options.html
├── image
├── change.svg
├── config.svg
├── default.svg
├── download.svg
└── home.svg
├── js
├── calendar.min.js
├── customize.js
├── index.js
└── options.js
└── manifest.json
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # myNewTabWE by sakuyaa
2 |
3 | [myNewTabMod](https://github.com/sakuyaa/myNewTabMod/)这个扩展的WebExtension版本,由于API限制部分功能无法实现。
4 |
--------------------------------------------------------------------------------
/release/myNewTabWE-1.0.xpi:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sakuyaa/myNewTabWE/335c6f74b83f79bfef3dec4386b1bb3bffeb8b5a/release/myNewTabWE-1.0.xpi
--------------------------------------------------------------------------------
/release/myNewTabWE-1.1.xpi:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sakuyaa/myNewTabWE/335c6f74b83f79bfef3dec4386b1bb3bffeb8b5a/release/myNewTabWE-1.1.xpi
--------------------------------------------------------------------------------
/release/myNewTabWE-1.10.xpi:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sakuyaa/myNewTabWE/335c6f74b83f79bfef3dec4386b1bb3bffeb8b5a/release/myNewTabWE-1.10.xpi
--------------------------------------------------------------------------------
/release/myNewTabWE-1.11.1.xpi:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sakuyaa/myNewTabWE/335c6f74b83f79bfef3dec4386b1bb3bffeb8b5a/release/myNewTabWE-1.11.1.xpi
--------------------------------------------------------------------------------
/release/myNewTabWE-1.11.xpi:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sakuyaa/myNewTabWE/335c6f74b83f79bfef3dec4386b1bb3bffeb8b5a/release/myNewTabWE-1.11.xpi
--------------------------------------------------------------------------------
/release/myNewTabWE-1.2.1.xpi:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sakuyaa/myNewTabWE/335c6f74b83f79bfef3dec4386b1bb3bffeb8b5a/release/myNewTabWE-1.2.1.xpi
--------------------------------------------------------------------------------
/release/myNewTabWE-1.2.xpi:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sakuyaa/myNewTabWE/335c6f74b83f79bfef3dec4386b1bb3bffeb8b5a/release/myNewTabWE-1.2.xpi
--------------------------------------------------------------------------------
/release/myNewTabWE-1.3.xpi:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sakuyaa/myNewTabWE/335c6f74b83f79bfef3dec4386b1bb3bffeb8b5a/release/myNewTabWE-1.3.xpi
--------------------------------------------------------------------------------
/release/myNewTabWE-1.4.xpi:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sakuyaa/myNewTabWE/335c6f74b83f79bfef3dec4386b1bb3bffeb8b5a/release/myNewTabWE-1.4.xpi
--------------------------------------------------------------------------------
/release/myNewTabWE-1.5.xpi:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sakuyaa/myNewTabWE/335c6f74b83f79bfef3dec4386b1bb3bffeb8b5a/release/myNewTabWE-1.5.xpi
--------------------------------------------------------------------------------
/release/myNewTabWE-1.6.1.xpi:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sakuyaa/myNewTabWE/335c6f74b83f79bfef3dec4386b1bb3bffeb8b5a/release/myNewTabWE-1.6.1.xpi
--------------------------------------------------------------------------------
/release/myNewTabWE-1.6.xpi:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sakuyaa/myNewTabWE/335c6f74b83f79bfef3dec4386b1bb3bffeb8b5a/release/myNewTabWE-1.6.xpi
--------------------------------------------------------------------------------
/release/myNewTabWE-1.7.xpi:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sakuyaa/myNewTabWE/335c6f74b83f79bfef3dec4386b1bb3bffeb8b5a/release/myNewTabWE-1.7.xpi
--------------------------------------------------------------------------------
/release/myNewTabWE-1.8.1.xpi:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sakuyaa/myNewTabWE/335c6f74b83f79bfef3dec4386b1bb3bffeb8b5a/release/myNewTabWE-1.8.1.xpi
--------------------------------------------------------------------------------
/release/myNewTabWE-1.8.xpi:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sakuyaa/myNewTabWE/335c6f74b83f79bfef3dec4386b1bb3bffeb8b5a/release/myNewTabWE-1.8.xpi
--------------------------------------------------------------------------------
/release/myNewTabWE-1.9.1.xpi:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sakuyaa/myNewTabWE/335c6f74b83f79bfef3dec4386b1bb3bffeb8b5a/release/myNewTabWE-1.9.1.xpi
--------------------------------------------------------------------------------
/release/myNewTabWE-1.9.xpi:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sakuyaa/myNewTabWE/335c6f74b83f79bfef3dec4386b1bb3bffeb8b5a/release/myNewTabWE-1.9.xpi
--------------------------------------------------------------------------------
/release/updates.json:
--------------------------------------------------------------------------------
1 | {
2 | "addons": {
3 | "myNewTabWE@sakuyaa": {
4 | "updates": [
5 | {
6 | "version": "1.0",
7 | "update_link": "https://raw.githubusercontent.com/sakuyaa/myNewTabWE/master/release/myNewTabWE-1.0.xpi",
8 | "applications": {
9 | "gecko": {
10 | "strict_min_version": "56.0"
11 | }
12 | }
13 | }, {
14 | "version": "1.1",
15 | "update_link": "https://raw.githubusercontent.com/sakuyaa/myNewTabWE/master/release/myNewTabWE-1.1.xpi",
16 | "applications": {
17 | "gecko": {
18 | "strict_min_version": "56.0"
19 | }
20 | }
21 | }, {
22 | "version": "1.2",
23 | "update_link": "https://raw.githubusercontent.com/sakuyaa/myNewTabWE/master/release/myNewTabWE-1.2.xpi",
24 | "applications": {
25 | "gecko": {
26 | "strict_min_version": "56.0"
27 | }
28 | }
29 | }, {
30 | "version": "1.2.1",
31 | "update_link": "https://raw.githubusercontent.com/sakuyaa/myNewTabWE/master/release/myNewTabWE-1.2.1.xpi",
32 | "applications": {
33 | "gecko": {
34 | "strict_min_version": "56.0"
35 | }
36 | }
37 | }, {
38 | "version": "1.3",
39 | "update_link": "https://raw.githubusercontent.com/sakuyaa/myNewTabWE/master/release/myNewTabWE-1.3.xpi",
40 | "applications": {
41 | "gecko": {
42 | "strict_min_version": "56.0"
43 | }
44 | }
45 | }, {
46 | "version": "1.4",
47 | "update_link": "https://raw.githubusercontent.com/sakuyaa/myNewTabWE/master/release/myNewTabWE-1.4.xpi",
48 | "applications": {
49 | "gecko": {
50 | "strict_min_version": "56.0"
51 | }
52 | }
53 | }, {
54 | "version": "1.5",
55 | "update_link": "https://raw.githubusercontent.com/sakuyaa/myNewTabWE/master/release/myNewTabWE-1.5.xpi",
56 | "applications": {
57 | "gecko": {
58 | "strict_min_version": "56.0"
59 | }
60 | }
61 | }, {
62 | "version": "1.6",
63 | "update_link": "https://raw.githubusercontent.com/sakuyaa/myNewTabWE/master/release/myNewTabWE-1.6.xpi",
64 | "applications": {
65 | "gecko": {
66 | "strict_min_version": "56.0"
67 | }
68 | }
69 | }, {
70 | "version": "1.6.1",
71 | "update_link": "https://raw.githubusercontent.com/sakuyaa/myNewTabWE/master/release/myNewTabWE-1.6.1.xpi",
72 | "applications": {
73 | "gecko": {
74 | "strict_min_version": "56.0"
75 | }
76 | }
77 | }, {
78 | "version": "1.7",
79 | "update_link": "https://raw.githubusercontent.com/sakuyaa/myNewTabWE/master/release/myNewTabWE-1.7.xpi",
80 | "applications": {
81 | "gecko": {
82 | "strict_min_version": "56.0"
83 | }
84 | }
85 | }, {
86 | "version": "1.8",
87 | "update_link": "https://raw.githubusercontent.com/sakuyaa/myNewTabWE/master/release/myNewTabWE-1.8.xpi",
88 | "applications": {
89 | "gecko": {
90 | "strict_min_version": "56.0"
91 | }
92 | }
93 | }, {
94 | "version": "1.8.1",
95 | "update_link": "https://raw.githubusercontent.com/sakuyaa/myNewTabWE/master/release/myNewTabWE-1.8.1.xpi",
96 | "applications": {
97 | "gecko": {
98 | "strict_min_version": "56.0"
99 | }
100 | }
101 | }, {
102 | "version": "1.9",
103 | "update_link": "https://raw.githubusercontent.com/sakuyaa/myNewTabWE/master/release/myNewTabWE-1.9.xpi",
104 | "applications": {
105 | "gecko": {
106 | "strict_min_version": "56.0"
107 | }
108 | }
109 | }, {
110 | "version": "1.9.1",
111 | "update_link": "https://raw.githubusercontent.com/sakuyaa/myNewTabWE/master/release/myNewTabWE-1.9.1.xpi",
112 | "applications": {
113 | "gecko": {
114 | "strict_min_version": "56.0"
115 | }
116 | }
117 | }, {
118 | "version": "1.10",
119 | "update_link": "https://raw.githubusercontent.com/sakuyaa/myNewTabWE/master/release/myNewTabWE-1.10.xpi",
120 | "applications": {
121 | "gecko": {
122 | "strict_min_version": "56.0"
123 | }
124 | }
125 | }, {
126 | "version": "1.11",
127 | "update_link": "https://raw.githubusercontent.com/sakuyaa/myNewTabWE/master/release/myNewTabWE-1.11.xpi",
128 | "applications": {
129 | "gecko": {
130 | "strict_min_version": "56.0"
131 | }
132 | }
133 | }, {
134 | "version": "1.11.1",
135 | "update_link": "https://raw.githubusercontent.com/sakuyaa/myNewTabWE/master/release/myNewTabWE-1.11.1.xpi",
136 | "applications": {
137 | "gecko": {
138 | "strict_min_version": "56.0"
139 | }
140 | }
141 | }
142 | ]
143 | }
144 | }
145 | }
--------------------------------------------------------------------------------
/src/css/customize.css:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * myNewTabWE by sakuyaa.
3 | *
4 | * https://github.com/sakuyaa/
5 | **************************************************/
6 | body {
7 | background-color: #EEEEEE;
8 | font-family: "microsoft yahei", sans-serif;
9 | margin: 1.5em 3em;
10 | }
11 |
12 | button {
13 | background-color: #F9F9F9;
14 | border: .1em solid gray;
15 | border-radius: .5em;
16 | padding: .3em 1em;
17 | }
18 | button:hover {
19 | background-color: #CCCCCC;
20 | }
21 | button:active { /*点击效果*/
22 | background-color: #BBBBBB;
23 | }
24 | textarea {
25 | tab-size: 4;
26 | background-color: #F9F9F9;
27 | overflow-y: hidden;
28 | padding: 0; /*使其宽度100%能居中*/
29 | resize: none;
30 | width: 100%;
31 | }
32 | textarea:focus { /*输入框聚焦效果*/
33 | box-shadow: 0 0 1em 0 #999999;
34 | transition: box-shadow .1s ease-in-out;
35 | }
36 |
37 | .group {
38 | border: .1em solid gray;
39 | border-radius: .5em;
40 | margin: 1em 0;
41 | }
42 | .header {
43 | background-color: #DDDDDD;
44 | border-bottom: .1em solid gray;
45 | border-top-left-radius: .5em;
46 | border-top-right-radius: .5em;
47 | padding: .5em 1em;
48 | }
49 | .header button {
50 | float: right; /*按钮靠右*/
51 | margin: -.2em .2em;
52 | }
53 | .content {
54 | padding: .5em 1em;
55 | }
56 |
--------------------------------------------------------------------------------
/src/css/index.css:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * myNewTabWE by sakuyaa.
3 | *
4 | * https://github.com/sakuyaa/
5 | **************************************************/
6 | /*天气*/
7 | #weather {
8 | left: 0;
9 | position: fixed;
10 | top: .5em;
11 | z-index: 1;
12 | }
13 |
14 | html, body {
15 | height: 100%;
16 | }
17 | body {
18 | align-items: center;
19 | background-attachment: fixed;
20 | background-color: #EDEDED;
21 | background-position: center;
22 | background-repeat: no-repeat;
23 | background-size: cover;
24 | display: flex;
25 | flex-direction: column;
26 | font-family: "Microsoft YaHei", sans-serif;
27 | margin: 0; /*避免容器大小100%造成的滚动条*/
28 | }
29 | /*上下空白高度比例1:3*/
30 | header {
31 | flex-grow: 1;
32 | }
33 | footer {
34 | flex-grow: 3;
35 | }
36 |
37 | /*日历整体*/
38 | #date {
39 | color: #1E90FF;
40 | font: bold 3em Arial, "Microsoft YaHei", sans-serif;
41 | margin: .25em 0;
42 | text-align: center;
43 | text-shadow: .1em .1em .1em black;
44 | z-index: 9;
45 | }
46 | /*农历*/
47 | #lunar {
48 | color: #333;
49 | font-size: .75em;
50 | text-shadow: .1em .1em .1em silver;
51 | }
52 | /*节日*/
53 | .festival {
54 | color: orangered;
55 | }
56 | /*法定假日*/
57 | .holiday {
58 | color: red;
59 | }
60 |
61 | /*导航整体面板*/
62 | #navs {
63 | background-color: rgba(0, 0, 0, .5);
64 | backdrop-filter: blur(5px);
65 | border: .1em solid gray;
66 | border-radius: 1em;
67 | margin-bottom: 1em; /*导航底部保留空间*/
68 | max-width: 80%; /*最大宽度*/
69 | z-index: 9;
70 | }
71 | /*导航链接*/
72 | #navs a {
73 | color: white;
74 | outline: none; /*不显示虚框*/
75 | text-decoration: none;
76 | }
77 | /*导航图标*/
78 | #navs img {
79 | height: 1em;
80 | margin-bottom: -.15em; /*与文字对齐*/
81 | margin-right: .2em; /*与文字的间隔*/
82 | width: 1em;
83 | }
84 |
85 | /*导航标题*/
86 | #navtitle {
87 | border-bottom: .15em solid rgba(123, 123, 123, .65);
88 | color: rgba(255, 255, 255, .65);
89 | font-size: 1.25em;
90 | font-weight: bold;
91 | padding: .4em .8em;
92 | }
93 | /*导航标题按钮*/
94 | #navtitle a {
95 | float: right;
96 | opacity: .5;
97 | padding: 0 .2em;
98 | }
99 | #navtitle a:hover {
100 | opacity: .8;
101 | }
102 |
103 | /*导航表格*/
104 | #navtable {
105 | padding: .25em 1em;
106 | }
107 | /*设置导航分类*/
108 | #navtable th {
109 | color: rgba(255, 255, 255, .6);
110 | padding: .3em 0;
111 | text-align: left;
112 | vertical-align: top;
113 | width: 6em;
114 | }
115 | /*设置导航单元大小*/
116 | #navtable td {
117 | float: left; /*超出自动换行*/
118 | padding: .3em .2em;
119 | width: 7.2em; /*文字长度6加上图标1和图标文字间的间隔0.2*/
120 | }
121 | /*设置导航链接*/
122 | #navtable a {
123 | opacity: .8;
124 | }
125 | #navtable a:hover {
126 | opacity: 1;
127 | text-shadow: 0 1px rgba(64, 64, 255, 0.9), 0 1px 1px rgba(64, 64, 255, 0.9), 0 -1px 1px rgba(64, 64, 255, 0.9), 1px 0 1px rgba(64, 64, 255, 0.9), -1px 0 1px rgba(64, 64, 255, 0.9), 0 0 3px rgba(64, 64, 255, 0.9);
128 | transition: color 0.423s ease, text-shadow 0.423s ease;
129 | }
130 |
--------------------------------------------------------------------------------
/src/css/options.css:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * myNewTabWE by sakuyaa.
3 | *
4 | * https://github.com/sakuyaa/
5 | **************************************************/
6 | body {
7 | background-color: #EEEEEE;
8 | font-family: "microsoft yahei", sans-serif;
9 | margin: 1.5em 3em;
10 | }
11 | table {
12 | width: 100%;
13 | }
14 | tr:hover {
15 | background-color: #DDDDDD;
16 | }
17 | th {
18 | background-color: #EEEEEE; /*表头保持背景色*/
19 | padding: .3em;
20 | }
21 | td {
22 | padding: .3em;
23 | }
24 | button {
25 | background-color: #F9F9F9;
26 | border: .1em solid gray;
27 | border-radius: .5em;
28 | padding: .3em 1em;
29 | }
30 | button:hover {
31 | background-color: #CCCCCC;
32 | }
33 | button:active { /*点击效果*/
34 | background-color: #BBBBBB;
35 | }
36 | input {
37 | background-color: #F9F9F9;
38 | }
39 | input:focus { /*输入框聚焦效果*/
40 | box-shadow: 0 0 1em 0 #999999;
41 | transition: box-shadow .1s ease-in-out;
42 | }
43 |
44 | .group {
45 | border: .1em solid gray;
46 | border-radius: .5em;
47 | margin: 1em 0;
48 | }
49 | .header {
50 | background-color: #DDDDDD;
51 | border-bottom: .1em solid gray;
52 | border-top-left-radius: .5em;
53 | border-top-right-radius: .5em;
54 | padding: .5em 1em;
55 | }
56 | .header button {
57 | float: right; /*按钮靠右*/
58 | margin: -.2em .2em;
59 | }
60 | .content {
61 | padding: .5em 1em;
62 | }
63 | .group-table {
64 | table-layout: fixed; /*固定表格布局*/
65 | }
66 | .group-table td { /*修剪文本*/
67 | overflow: hidden;
68 | text-overflow: ellipsis;
69 | white-space: nowrap;
70 | }
71 | .group-table th:first-child {
72 | width: 7em; /*固定表格布局需要对第一行各项控制宽度*/
73 | }
74 | .group-table th:nth-child(2) {
75 | width: 2em;
76 | }
77 | .group-table th:last-child { /*操作列*/
78 | width: 15em;
79 | }
80 | .group-table td:nth-child(2), .group-table td:last-child { /*图标按钮居中*/
81 | text-align: center;
82 | }
83 | .group-table img {
84 | height: 1em;
85 | margin-bottom: -.15em; /*与文字对齐*/
86 | width: 1em;
87 | }
88 |
89 | #edit-modal { /*模态框遮罩*/
90 | align-items: center;
91 | background-color: rgba(0, 0, 0, .6);
92 | display: none; /*flex*/
93 | height: 100%;
94 | justify-content: center;
95 | left: 0;
96 | position: fixed;
97 | top: 0;
98 | width: 100%;
99 | z-index: 9;
100 | }
101 | #edit-modal .content { /*保持背景颜色和圆弧边框*/
102 | background-color: #EEEEEE;
103 | border-bottom-left-radius: .5em;
104 | border-bottom-right-radius: .5em;
105 | }
106 | #edit-modal input:not([size]), #user-image-src, #title, #weather-src { /*除图标列之外输入框长度*/
107 | width: 99%;
108 | }
109 | #confirm { /*确认取消按钮位置*/
110 | border-top: .1em solid gray;
111 | padding-top: .5em;
112 | text-align: center;
113 | }
114 | #logo {
115 | text-align: center;
116 | }
117 | #logo a {
118 | color: black;
119 | font-size: 2.5em;
120 | opacity: .8;
121 | text-decoration: none;
122 | }
123 | #logo img { /*图片文字对齐*/
124 | height: 1.3em;
125 | vertical-align: top;
126 | }
127 | #config td:first-child { /*选项文字宽度*/
128 | width: 12em;
129 | }
130 | #image-upload {
131 | float: right; /*按钮靠右*/
132 | padding: 0 .3em;
133 | }
134 |
--------------------------------------------------------------------------------
/src/css/weather.css:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * myNewTabWE by sakuyaa.
3 | *
4 | * https://github.com/sakuyaa/
5 | **************************************************/
6 | /*使其自适应网页宽度*/
7 | body {
8 | float: left;
9 | }
10 | /*链接白字蓝光*/
11 | a {
12 | color: rgba(255, 255, 255, 1) !important;
13 | text-decoration: none;
14 | text-shadow: 0 1px rgba(64, 64, 255, 0.9), 0 1px 1px rgba(64, 64, 255, 0.9), 0 -1px 1px rgba(64, 64, 255, 0.9),
15 | 1px 0 1px rgba(64, 64, 255, 0.9), -1px 0 1px rgba(64, 64, 255, 0.9), 0 0 3px rgba(64, 64, 255, 0.9) !important;
16 | }
17 |
--------------------------------------------------------------------------------
/src/html/customize.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 定制页面
7 |
8 |
9 |
10 |
11 |
12 |
23 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/src/html/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/src/html/options.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 配置页面
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
114 |
115 |
116 |
117 |
118 |
126 |
127 |
128 |
129 | 标题 |
130 | 图标 |
131 | 网址 |
132 | 操作 |
133 |
134 |
135 | 项目主页 |
136 | ![]() |
137 | https://github.com/sakuyaa/myNewTabWE |
138 |
139 |
140 |
141 |
142 |
143 | |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
--------------------------------------------------------------------------------
/src/image/change.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/image/config.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/image/default.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/image/download.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/image/home.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/js/calendar.min.js:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Copyright © 2011-2024 sakuyaa.
3 | * All rights reserved.
4 | *
5 | * https://github.com/sakuyaa/
6 | **************************************************/
7 | 'use strict';
8 | let Solar={a:['星期日','星期一','星期二','星期三','星期四','星期五','星期六'],b:['0101*元旦','0214情人节','0305学雷锋纪念日','0308妇女节','0312植树节','0315消费者权益日','0401愚人节','0415国家安全教育日','0422世界地球日','0501*劳动节','0504青年节','0512护士节','0601儿童节','0701建党节','0801建军节','0903抗日战争胜利纪念日','0910教师节','0930烈士纪念日','1001*国庆节','1031万圣节前夜','1101万圣节','1111光棍节','1204宪法日','1213国家公祭日','1224平安夜','1225圣诞节'],c:['0520母亲节','0630父亲节','1144感恩节'],d:a=>a%400==0||(a%4==0&&a%100),e:a=>{let c=0;for(let b=1900;b{let e='';for(let d of Solar.b){if((c.getMonth()+1)*100+c.getDate()==parseInt(d.substring(0,4))){e+=d.substring(4);break;}}for(let d of Solar.c){let a=parseInt(d.substring(0,4));if((c.getMonth()+1)==parseInt(a/100)&&c.getDay()==a%10){let b=parseInt(a/10)%10;if(c.getDate()-(b-1)*7>0&&c.getDate()-b*7<=0){if(e){e+=' ';}e+=d.substring(4);break;}}}return e;},getSolar:a=>{let b={date:(a.getMonth()+1)+'月'+a.getDate()+'日 '+Solar.a[a.getDay()],festival:'',holiday:''};let c=Solar.f(a);if(c.charAt(0)=='*'){b.holiday=c.substring(1);}else{b.festival=c;}return b;}};let Lunar={a:['小寒','大寒','立春','雨水','惊蛰','春分','*清明','谷雨','立夏','小满','芒种','夏至','小暑','大暑','立秋','处暑','白露','秋分','寒露','霜降','立冬','小雪','大雪','冬至'],b:'甲乙丙丁戊己庚辛壬癸',c:'子丑寅卯辰巳午未申酉戌亥',d:'鼠牛虎兔龙蛇马羊猴鸡狗猪',e:['闰','正月','二月','三月','四月','五月','六月','七月','八月','九月','十月','冬月','腊月'],f:'初一二三四五六七八九十廿',g:['0101*春节','0115元宵','0202龙抬头','0303上巳节','0505*端午','0707七夕','0715中元节','0815*中秋','0909重阳','1001寒衣节','1015下元节','1208腊八节','1223北方小年','1224南方小年','1230除夕'],h:1900,i:0,j:[],k:1,l:1,m:true,x:{1382:-1,1393:-1,1395:-1,1408:-1,1413:1,1418:-1,1426:1,1430:-1,1474:1,1483:-1,1489:1,1493:-1,1501:1,1506:-1,1511:1,1524:1,1537:1,1544:-1,1556:-1,1568:-1,1581:-1,1587:1,1594:-1,1602:-1,1607:-1,1609:1,},y:{201111:1,201212:1,201416:1,201511:1,201615:1,201702:-1,201816:1,202123:-1,202210:1,202603:-1,202714:1,202917:1,},n:a=>{if(a in Lunar.x){return Math.floor(1.6+29.5306*a+0.4*Math.sin(1-0.45058*a))+Lunar.x[a];}return Math.floor(1.6+29.5306*a+0.4*Math.sin(1-0.45058*a));},o:(b,a)=>{if((b*100+a)in Lunar.y){return Math.floor(365.242*(b-1900)+6.2+15.22*a-1.9*Math.sin(0.262*a))+Lunar.y[b*100+a];}return Math.floor(365.242*(b-1900)+6.2+15.22*a-1.9*Math.sin(0.262*a));},p:c=>{for(;Lunar.h<=c;Lunar.h++){let a=Lunar.o(Lunar.h-1,23);while(Lunar.n(Lunar.i)<=a){Lunar.i++}if(Lunar.n(Lunar.i+12)<=Lunar.o(Lunar.h,23)){for(let b=0;b<12;b++){a=Lunar.o(Lunar.h,2*b+1);if(Lunar.n(Lunar.i+b)>a||Lunar.n(Lunar.i+b+1)<=a){Lunar.j.push(Lunar.i+b);break;}}}}},q:c=>{Lunar.m=false;Lunar.p(c.getFullYear());let b=Solar.e(c);let a=(c.getFullYear()-1900)*12-1;for(;;a++){if(Lunar.n(a+1)>b){let e=Lunar.j.length;for(let d=0;da){e=d;break;}}Lunar.k=(a-e+11)%12+1;Lunar.l=b-Lunar.n(a)+1;break;}}},r:b=>{let a=b.getFullYear();if(Solar.e(b){for(let a=0;;a++){if(Lunar.o(parseInt(a/12)+1899,a%12*2)>Solar.e(b)){return Lunar.b[a%10]+Lunar.c[a%12]+'月 ';}}},t:b=>{let a=Solar.e(b);a+=9;while(a<0){a+=60000;}return Lunar.b[a%10]+Lunar.c[a%12]+'日 ';},u:b=>{Lunar.q(b);let a=Lunar.e[Lunar.k];if(Lunar.l<=10){a+=Lunar.f[0]+Lunar.f[Lunar.l];}else if(Lunar.l<20){a+=Lunar.f[10]+Lunar.f[Lunar.l%10];}else if(Lunar.l==20){a+=Lunar.f[2]+Lunar.f[10];}else if(Lunar.l==30){a+=Lunar.f[3]+Lunar.f[10];}else{a+=Lunar.f[11]+Lunar.f[Lunar.l%10];}return Lunar.m?Lunar.e[0]+a:a;},v:b=>{for(let a=0;a<24;a++){if(Solar.e(b)==Lunar.o(b.getFullYear(),a)){return Lunar.a[a];}}return'';},w:()=>{for(let a=0;a{let d=Lunar.u(b);let a=Lunar.w();let e=Lunar.v(b);let c={date:Lunar.r(b)+Lunar.s(b)+Lunar.t(b)+d,festival:'',holiday:''};if(e.charAt(0)=='*'){c.holiday=e.substring(1);}else{c.festival=e;}if(a.charAt(0)=='*'){if(c.holiday){c.holiday+=' ';}c.holiday+=a.substring(1);}else{if(c.festival){c.festival+=' ';}if(d=='腊月廿九'&&Lunar.u(new Date(b.getFullYear(),b.getMonth(),b.getDate()+1))!='腊月三十'){c.festival+='除夕';}else{c.festival+=a;}}return c;}};
--------------------------------------------------------------------------------
/src/js/customize.js:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * myNewTabWE by sakuyaa.
3 | *
4 | * https://github.com/sakuyaa/
5 | **************************************************/
6 | 'use strict';
7 |
8 | //简化函数
9 | const $id = id => document.getElementById(id);
10 | //最近修改过默认css文件的扩展版本,只针对主页
11 | const LAST_MODIFY_CSS_VERSION = '1.11.1';
12 |
13 | let myNewTabWE = {
14 | css: {
15 | version: 0,
16 | index: '',
17 | weather: ''
18 | },
19 | defaultCss: { //默认css
20 | index: '',
21 | weather: ''
22 | },
23 |
24 | notify: (message, title) => {
25 | browser.notifications.create({
26 | type: 'basic',
27 | message: message + '',
28 | title: title,
29 | iconUrl: browser.runtime.getURL('image/home.svg')
30 | });
31 | },
32 |
33 | //获取参数
34 | getStorage: () => {
35 | return new Promise((resolve, reject) => {
36 | browser.storage.local.get({
37 | css: {
38 | version: 0,
39 | index: '',
40 | weather: ''
41 | }
42 | }).then(storage => {
43 | myNewTabWE.css = storage.css;
44 | resolve();
45 | }, e => {
46 | myNewTabWE.notify(e, '获取定制css内容失败');
47 | reject();
48 | });
49 | });
50 | },
51 |
52 | initConf: async () => {
53 | if (myNewTabWE.css.index) { //存在定制css
54 | if (LAST_MODIFY_CSS_VERSION != myNewTabWE.css.version) {
55 | $id('tips').textContent = '此扩展的默认css相对于定制主页时的默认css有改动,请检查定制css是否需要更新';
56 | }
57 | }
58 | let response = await fetch('../css/index.css'); //读取默认css
59 | myNewTabWE.defaultCss.index = (await response.text()).split(/\*{50}\/\n/)[1]; //去除文件头备注
60 | response = await fetch('../css/weather.css');
61 | myNewTabWE.defaultCss.weather = (await response.text()).split(/\*{50}\/\n/)[1];
62 | if (myNewTabWE.css.weather) {
63 | $id('weather-css').value = myNewTabWE.css.weather;
64 | myNewTabWE.adjustRows($id('weather-css'));
65 | } else {
66 | $id('weather-css').value = ''; //刷新后不自动填写
67 | }
68 | if (myNewTabWE.css.index) {
69 | $id('index-css').value = myNewTabWE.css.index;
70 | myNewTabWE.adjustRows($id('index-css'));
71 | } else {
72 | $id('index-css').value = ''; //刷新后不自动填写
73 | }
74 | },
75 | initEvent: () => {
76 | $id('weather-save').addEventListener('click', () => {
77 | myNewTabWE.css.weather = $id('weather-css').value;
78 | browser.storage.local.set({css: myNewTabWE.css}).then(null, e => {
79 | myNewTabWE.notify(e, '设置定制css内容失败');
80 | });
81 | });
82 | $id('index-save').addEventListener('click', () => {
83 | myNewTabWE.css.version = $id('index-css').value == '' ? 0 : LAST_MODIFY_CSS_VERSION;
84 | myNewTabWE.css.index = $id('index-css').value;
85 | browser.storage.local.set({css: myNewTabWE.css}).then(null, e => {
86 | myNewTabWE.notify(e, '设置定制css内容失败');
87 | });
88 | });
89 | $id('weather-default').addEventListener('click', () => {
90 | if (!$id('weather-css').value || confirm('是否加载默认css?')) {
91 | $id('weather-css').value = myNewTabWE.defaultCss.weather;
92 | myNewTabWE.adjustRows($id('weather-css'));
93 | }
94 | });
95 | $id('index-default').addEventListener('click', () => {
96 | if (!$id('index-css').value || confirm('是否加载默认css?')) {
97 | $id('index-css').value = myNewTabWE.defaultCss.index;
98 | myNewTabWE.adjustRows($id('index-css'));
99 | }
100 | });
101 | $id('weather-css').addEventListener('input', e => {
102 | myNewTabWE.adjustRows(e.target);
103 | });
104 | $id('index-css').addEventListener('input', e => {
105 | myNewTabWE.adjustRows(e.target);
106 | });
107 |
108 | //文本框输入Tab
109 | $id('weather-css').addEventListener('keydown', e => {
110 | if (e.key == 'Tab') {
111 | e.preventDefault();
112 | let start = e.target.selectionStart;
113 | e.target.value = e.target.value.substring(0, start) + '\t' +
114 | e.target.value.substring(e.target.selectionEnd);
115 | e.target.setSelectionRange(start + 1, start + 1);
116 | }
117 | });
118 | $id('index-css').addEventListener('keydown', e => {
119 | if (e.key == 'Tab') {
120 | e.preventDefault();
121 | let start = e.target.selectionStart;
122 | e.target.value = e.target.value.substring(0, start) + '\t' +
123 | e.target.value.substring(e.target.selectionEnd);
124 | e.target.setSelectionRange(start + 1, start + 1);
125 | }
126 | });
127 | },
128 |
129 | init: () => {
130 | myNewTabWE.initConf();
131 | myNewTabWE.initEvent();
132 | },
133 |
134 | //自动调整文本框行数
135 | adjustRows: textarea => {
136 | textarea.rows = textarea.value.split('\n').length;
137 | }
138 | };
139 |
140 | myNewTabWE.getStorage().then(myNewTabWE.init);
141 |
--------------------------------------------------------------------------------
/src/js/index.js:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * myNewTabWE by sakuyaa.
3 | *
4 | * https://github.com/sakuyaa/
5 | **************************************************/
6 | 'use strict';
7 |
8 | //简化函数
9 | const $id = id => document.getElementById(id);
10 | const DEFAULT_CONFIG = {
11 | config: {
12 | autoChange: true, //自动切换壁纸
13 | autoDownload: false, //自动下载壁纸
14 | bingMaxHistory: 8, //最大历史天数,可设置[2, 8]
15 | downloadDir: 'bingImg', //相对于浏览器下载文件夹的目录
16 | newTabOpen: true, //是否新标签页打开导航链接
17 | title: '我的主页', //网页标题
18 | useBigImage: 2, //bing图片的尺寸,0为默认的1366x768,1为1920x1080,2为UHD
19 | userImage: false, //使用自定义壁纸
20 | userImageSrc: '', //自定义壁纸的URL
21 | weatherSrc: 'https://i.tianqi.com/index.php?c=code&id=8&num=3' //天气代码的URL
22 | },
23 | sites: [],
24 | css: {
25 | index: '',
26 | weather: ''
27 | }
28 | };
29 |
30 | let myNewTabWE = {
31 | bingIndex: 0, //Bing图片历史天数
32 | config: {},
33 | sites: [],
34 | css: {
35 | index: '',
36 | weather: ''
37 | },
38 |
39 | //显示桌面通知
40 | notify: (message, title) => {
41 | browser.notifications.create({
42 | type: 'basic',
43 | message: message + '',
44 | title: title,
45 | iconUrl: browser.runtime.getURL('image/home.svg')
46 | });
47 | },
48 |
49 | //获取参数
50 | getStorage: () => {
51 | return new Promise((resolve, reject) => {
52 | browser.storage.local.get(DEFAULT_CONFIG).then(storage => {
53 | myNewTabWE.config = storage.config;
54 | myNewTabWE.sites = storage.sites;
55 | myNewTabWE.css = storage.css;
56 | resolve();
57 | }, e => {
58 | myNewTabWE.notify(e, '获取myNewTabWE配置失败');
59 | reject();
60 | });
61 | });
62 | },
63 |
64 | //初始化css
65 | initCss: () => {
66 | if (myNewTabWE.css.index) {
67 | let style = document.createElement('style');
68 | style.appendChild(document.createTextNode(myNewTabWE.css.index));
69 | document.head.appendChild(style);
70 | } else {
71 | let link = document.createElement('link');
72 | link.rel = 'stylesheet';
73 | link.href = '../css/index.css';
74 | document.head.appendChild(link);
75 | }
76 | },
77 | //初始化日期
78 | initDate: () => {
79 | let date = Solar.getSolar(new Date());
80 | $id('solar-date').textContent = date.date;
81 | $id('solar-festival').textContent = date.festival;
82 | $id('solar-holiday').textContent = date.holiday;
83 | date = Lunar.getLunar(new Date());
84 | $id('lunar-date').textContent = date.date;
85 | $id('lunar-festival').textContent = date.festival;
86 | $id('lunar-holiday').textContent = date.holiday;
87 | },
88 | //初始化导航网址
89 | initSite: () => {
90 | let table = $id('navtable');
91 | for(let list of myNewTabWE.sites) {
92 | if (list.name.toLowerCase() == 'yooo') { //神秘的代码
93 | let yooo = myNewTabWE.buildTr(list);
94 | yooo.setAttribute('hidden', 'hidden');
95 | yooo.setAttribute('name', 'yooo');
96 | table.appendChild(yooo);
97 | } else {
98 | table.appendChild(myNewTabWE.buildTr(list));
99 | }
100 | }
101 | },
102 | //初始化监听器
103 | initListener: () => {
104 | //神秘的代码
105 | addEventListener('keydown', e => {
106 | if ((e.key.toLowerCase() == 'q') && e.ctrlKey) {
107 | for (let yooo of document.getElementsByName('yooo')) {
108 | yooo.removeAttribute('hidden');
109 | }
110 | }
111 | });
112 | addEventListener('keyup', e => {
113 | for (let yooo of document.getElementsByName('yooo')) {
114 | yooo.setAttribute('hidden', 'hidden');
115 | }
116 | });
117 |
118 | $id('change').addEventListener('click', () => {
119 | if (myNewTabWE.isNewDate()) {
120 | myNewTabWE.bingIndex = 0; //过0点重新获取
121 | } else {
122 | myNewTabWE.bingIndex++;
123 | }
124 | myNewTabWE.getBingImage();
125 | });
126 |
127 | //自动判断并切换天气、日期和壁纸
128 | let lastCheckTime = new Date();
129 | setInterval(async () => {
130 | let now = new Date();
131 | if (now.getDate() != lastCheckTime.getDate()) { //第二天
132 | myNewTabWE.initDate();
133 | }
134 | if (now.getDate() != lastCheckTime.getDate() || (now.getTime() - lastCheckTime.getTime()) >= 3600000) { //第二天或间隔一小时
135 | lastCheckTime = now;
136 | if (myNewTabWE.config.weatherSrc) {
137 | await myNewTabWE.delay(9876); //延迟获取避免刚唤醒后没有网络
138 | $id('weather').src = myNewTabWE.config.weatherSrc;
139 | }
140 | }
141 | if (!myNewTabWE.config.userImage && myNewTabWE.config.autoChange && myNewTabWE.isNewDate()) {
142 | await myNewTabWE.delay(9876); //延迟获取避免刚唤醒后没有网络
143 | myNewTabWE.bingIndex = 0;
144 | myNewTabWE.getBingImage();
145 | }
146 | }, 60000);
147 | },
148 | //初始化背景图片
149 | initImage: () => {
150 | if (myNewTabWE.config.userImage) { //使用自定义壁纸
151 | document.body.style.backgroundImage = `url("${myNewTabWE.config.userImageSrc}")`;
152 | $id('download').setAttribute('hidden', 'hidden');
153 | } else {
154 | let imageSrc = localStorage.getItem('imageSrc');
155 | if (imageSrc) {
156 | document.body.style.backgroundImage = `url("${imageSrc}")`;
157 | $id('download').setAttribute('download', localStorage.getItem('imageName'));
158 | if (imageSrc.startsWith('http')) {
159 | $id('download').setAttribute('href', imageSrc);
160 | } else {
161 | $id('download').setAttribute('href', URL.createObjectURL(myNewTabWE.dataURItoBlob(imageSrc)));
162 | }
163 | if (myNewTabWE.config.autoChange && myNewTabWE.isNewDate()) {
164 | myNewTabWE.getBingImage(); //过0点重新获取
165 | }
166 | } else {
167 | myNewTabWE.getBingImage();
168 | }
169 | }
170 | },
171 | //初始化天气
172 | initWeather: () => {
173 | return new Promise((resolve, reject) => {
174 | $id('weather').onload = async () => {
175 | for (let tab of await browser.tabs.query({url: browser.runtime.getURL('html/index.html')})) {
176 | for (let frame of await browser.webNavigation.getAllFrames({tabId: tab.id})) {
177 | if (frame.frameId) {
178 | //天气页面插入css
179 | if (myNewTabWE.css.weather) {
180 | await browser.tabs.insertCSS(tab.id, {
181 | code: myNewTabWE.css.weather,
182 | cssOrigin: 'user',
183 | frameId: frame.frameId,
184 | runAt: 'document_start'
185 | });
186 | } else {
187 | await browser.tabs.insertCSS(tab.id, {
188 | cssOrigin: 'user',
189 | file: browser.runtime.getURL('css/weather.css'),
190 | frameId: frame.frameId,
191 | runAt: 'document_start'
192 | });
193 | }
194 | //自动适应页面大小
195 | let size = (await browser.tabs.executeScript(tab.id, {
196 | code: '[document.body.scrollHeight, document.body.scrollWidth]',
197 | frameId: frame.frameId,
198 | runAt: 'document_end'
199 | }))[0];
200 | $id('weather').style.height = size[0] + 'px';
201 | $id('weather').style.width = size[1] + 'px';
202 | }
203 | }
204 | }
205 | };
206 | $id('weather').src = myNewTabWE.config.weatherSrc;
207 | resolve();
208 | });
209 |
210 | },
211 |
212 | init: () => {
213 | document.title = myNewTabWE.config.title;
214 | myNewTabWE.initCss();
215 | myNewTabWE.initDate();
216 | myNewTabWE.initSite();
217 | myNewTabWE.initListener();
218 | myNewTabWE.initImage();
219 |
220 | if (myNewTabWE.config.weatherSrc) {
221 | myNewTabWE.initWeather().then(null, e => {
222 | console.log('天气栏css加载失败:' + e);
223 | });
224 | }
225 | },
226 |
227 | getBingImage: async () => {
228 | let data, url, image;
229 | try {
230 | data = (await myNewTabWE.httpRequest(`https://cn.bing.com/HPImageArchive.aspx?format=js&n=1&mkt=zh-CN&idx=${myNewTabWE.bingIndex % myNewTabWE.config.bingMaxHistory}`,
231 | 'json', 'https://cn.bing.com/')).images[0];
232 | url = 'https://cn.bing.com' + data.urlbase;
233 | if (myNewTabWE.config.useBigImage == 2) {
234 | url += '_UHD.jpg';
235 | } else if (myNewTabWE.config.useBigImage == 1) {
236 | url += '_1920x1080.jpg';
237 | } else if (myNewTabWE.config.useBigImage == 0) {
238 | url += '_1366x768.jpg';
239 | }
240 | image = await myNewTabWE.httpRequest(url, 'blob', 'https://cn.bing.com/');
241 | } catch (e) {
242 | myNewTabWE.notify(e, '获取图片失败');
243 | return;
244 | }
245 | let reader = new FileReader();
246 | reader.onload = () => {
247 | document.body.style.backgroundImage = `url("${reader.result}")`;
248 |
249 | //保存图片和获取时间
250 | localStorage.setItem('lastCheckTime', Date.now());
251 | let imageName = data.enddate + '-' +
252 | data.copyright.replace(/\(.*?\)/g, '').trim()
253 | .replace(/(\\|\/|\*|\|)/g, '') //Win文件名不能包含下列字符
254 | .replace(/:/g, ':')
255 | .replace(/\?/g, '?')
256 | .replace(/("|<|>)/g, '\'') + '.jpg';
257 | localStorage.setItem('imageName', imageName);
258 | if (myNewTabWE.config.useBigImage > 1) { //UHD大小超出localStorage限制
259 | localStorage.setItem('imageSrc', url);
260 | } else {
261 | localStorage.setItem('imageSrc', reader.result);
262 | }
263 |
264 |
265 | //设置图片下载链接
266 | $id('download').setAttribute('download', imageName);
267 | $id('download').setAttribute('href', URL.createObjectURL(image));
268 | //自动下载壁纸
269 | if (myNewTabWE.config.autoDownload) {
270 | if (myNewTabWE.config.downloadDir) {
271 | imageName = myNewTabWE.config.downloadDir + '/' + imageName;
272 | }
273 | browser.downloads.download({
274 | conflictAction: 'overwrite', //覆盖旧文件避免出现重复文件
275 | filename: imageName,
276 | url: URL.createObjectURL(image)
277 | });
278 | }
279 | };
280 | reader.readAsDataURL(image);
281 | },
282 |
283 | buildTr: list => {
284 | let tr = document.createElement('tr'),
285 | th = document.createElement('th'),
286 | td, a, img, textNode, path;
287 |
288 | //添加分类
289 | th.textContent = list.name;
290 | tr.appendChild(th);
291 |
292 | //添加站点
293 | for (let site of list.list) {
294 | td = document.createElement('td');
295 | a = document.createElement('a');
296 | img = document.createElement('img');
297 | textNode = document.createTextNode(site.title);
298 |
299 | a.setAttribute('href', site.url);
300 | if (myNewTabWE.config.newTabOpen) {
301 | a.setAttribute('target', '_blank');
302 | }
303 | img.src = site.icon ? site.icon : '../image/default.svg';
304 |
305 | a.appendChild(img);
306 | a.appendChild(textNode);
307 | td.appendChild(a);
308 | tr.appendChild(td);
309 | }
310 | return tr;
311 | },
312 |
313 | dataURItoBlob: dataURI => {
314 | let byteString = atob(dataURI.substring(dataURI.indexOf(',') + 1));
315 | let arrayBuffer = new ArrayBuffer(byteString.length);
316 | let array = new Uint8Array(arrayBuffer);
317 | for (let i = 0; i < byteString.length; i++) {
318 | array[i] = byteString.charCodeAt(i);
319 | }
320 | return new Blob([arrayBuffer], {type: dataURI.substring(dataURI.indexOf(':') + 1, dataURI.indexOf(';'))});
321 | },
322 |
323 | isNewDate: item => {
324 | let today = new Date();
325 | today.setHours(0, 0, 0); //毫秒就不管了
326 | if (new Date(parseInt(localStorage.getItem(item ? item : 'lastCheckTime'))) < today) {
327 | return true;
328 | }
329 | return false;
330 | },
331 |
332 | delay: async time => {
333 | let now = new Date();
334 | await new Promise(resolve => setTimeout(resolve, time));
335 | if ((new Date()).getTime() - now.getTime() - time > 999) {
336 | //延迟的时间比预定的还久的话,怀疑是中间电脑睡眠了,重新延迟
337 | return await myNewTabWE.delay(time);
338 | }
339 | },
340 |
341 | httpRequest: (url, type, referrer) => {
342 | return new Promise((resolve, reject) => {
343 | let xhr = new XMLHttpRequest();
344 | if (type) {
345 | xhr.responseType = type;
346 | }
347 | xhr.open('GET', url);
348 | if (referrer) {
349 | xhr.setRequestHeader('referrer', referrer);
350 | }
351 | xhr.onload = () => {
352 | if (xhr.status == 200) {
353 | resolve(xhr.response);
354 | } else {
355 | reject(new Error(xhr.statusText));
356 | }
357 | };
358 | xhr.onerror = () => {
359 | reject(new Error('网络错误'));
360 | };
361 | xhr.send(null);
362 | });
363 | }
364 | };
365 |
366 | myNewTabWE.getStorage().then(myNewTabWE.init);
367 |
--------------------------------------------------------------------------------
/src/js/options.js:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * myNewTabWE by sakuyaa.
3 | *
4 | * https://github.com/sakuyaa/
5 | **************************************************/
6 | 'use strict';
7 |
8 | //简化函数
9 | const $id = id => document.getElementById(id);
10 | const DEFAULT_CONFIG = {
11 | config: {
12 | autoChange: true, //自动切换壁纸
13 | autoDownload: false, //自动下载壁纸
14 | bingMaxHistory: 8, //最大历史天数,可设置[2, 8]
15 | downloadDir: 'bingImg', //相对于浏览器下载文件夹的目录
16 | newTabOpen: true, //是否新标签页打开导航链接
17 | title: '我的主页', //网页标题
18 | useBigImage: 2, //bing图片的尺寸,0为1366x768,1为1920x1080,2为UHD
19 | userImage: false, //使用自定义壁纸
20 | userImageSrc: '', //自定义壁纸的URL
21 | weatherSrc: 'https://i.tianqi.com/index.php?c=code&id=8&num=3' //天气代码的URL
22 | },
23 | sites: []
24 | };
25 | let upload = $id('upload');
26 |
27 | let myNewTabWE = {
28 | config: {},
29 | sites: [],
30 |
31 | notify: (message, title) => {
32 | browser.notifications.create({
33 | type: 'basic',
34 | message: message + '',
35 | title: title,
36 | iconUrl: browser.runtime.getURL('image/home.svg')
37 | });
38 | },
39 |
40 | //获取参数
41 | getStorage: () => {
42 | return new Promise((resolve, reject) => {
43 | browser.storage.local.get(DEFAULT_CONFIG).then(storage => {
44 | myNewTabWE.config = storage.config;
45 | myNewTabWE.sites = storage.sites;
46 | resolve();
47 | }, e => {
48 | myNewTabWE.notify(e, '获取myNewTabWE配置失败');
49 | reject();
50 | });
51 | });
52 | },
53 | setStorage: isConfig => {
54 | if (isConfig) { //保存配置
55 | browser.storage.local.set({config: myNewTabWE.config}).then(null, e => {
56 | myNewTabWE.notify(e, '设置myNewTabWE配置失败');
57 | });
58 | } else { //保存网址列表
59 | browser.storage.local.set({sites: myNewTabWE.sites}).then(null, e => {
60 | myNewTabWE.notify(e, '设置myNewTabWE配置失败');
61 | });
62 | }
63 | },
64 |
65 | //初始化导入导出功能
66 | initImportExport: () => {
67 | $id('import').addEventListener('click', () => {
68 | upload.setAttribute('accept', 'application/json');
69 | upload.onchange = () => {
70 | let reader = new FileReader();
71 | reader.onload = () => {
72 | let json, storage = {};
73 | try {
74 | json = JSON.parse(reader.result);
75 | } catch(e) {
76 | myNewTabWE.notify(e, '导入myNewTabWE配置失败');
77 | return;
78 | }
79 | if (json.config) {
80 | storage.config = json.config;
81 | }
82 | if (json.sites) {
83 | storage.sites = json.sites;
84 | }
85 | if (json.css) {
86 | storage.css = json.css;
87 | }
88 | browser.storage.local.clear().then(() => browser.storage.local.set(storage)).then(() => {
89 | location.reload(); //刷新网页
90 | }, e => {
91 | myNewTabWE.notify(e, '设置myNewTabWE配置失败');
92 | });
93 | };
94 | reader.readAsText(upload.files[0]);
95 | };
96 | upload.click();
97 | });
98 | $id('export').addEventListener('click', async () => {
99 | let storage = {
100 | css: {
101 | version: 0,
102 | index: '',
103 | weather: ''
104 | }
105 | };
106 | try { //获取定制css内容
107 | storage = await browser.storage.local.get(storage);
108 | } catch(e) {
109 | myNewTabWE.notify(e, '获取定制css内容失败');
110 | }
111 | browser.downloads.download({
112 | filename: 'myNewTabWE.json',
113 | saveAs: true,
114 | url: URL.createObjectURL(new Blob([JSON.stringify({
115 | config: myNewTabWE.config,
116 | sites: myNewTabWE.sites,
117 | css: storage.css
118 | }, null, '\t')]))
119 | });
120 | });
121 | },
122 | //初始化选项
123 | initConf: () => {
124 | $id('newtab-open').checked = myNewTabWE.config.newTabOpen;
125 | if (myNewTabWE.config.bingMaxHistory > 8 || myNewTabWE.config.bingMaxHistory < 2) {
126 | myNewTabWE.config.bingMaxHistory = 8;
127 | myNewTabWE.setStorage(true);
128 | }
129 | $id('bing-max-history').value = myNewTabWE.config.bingMaxHistory;
130 | if (myNewTabWE.config.useBigImage == 2) {
131 | $id('UHD').checked = true;
132 | } else if (myNewTabWE.config.useBigImage == 1) {
133 | $id('1920').checked = true;
134 | } else if (myNewTabWE.config.useBigImage == 0) {
135 | $id('1366').checked = true;
136 | }
137 | $id('auto-change').checked = myNewTabWE.config.autoChange;
138 | $id('auto-download').checked = myNewTabWE.config.autoDownload;
139 | $id('download-dir').value = myNewTabWE.config.downloadDir;
140 | $id('user-image').checked = myNewTabWE.config.userImage;
141 | $id('user-image-src').value = myNewTabWE.config.userImageSrc;
142 | $id('title').value = myNewTabWE.config.title;
143 | $id('weather-src').value = myNewTabWE.config.weatherSrc;
144 | },
145 | //初始化导航网址
146 | initSites: ()=> {
147 | for (let group of myNewTabWE.sites) {
148 | $id('sites').appendChild(myNewTabWE.buildGroup(group));
149 | }
150 | $id('new-group').addEventListener('click', () => {
151 | let name = prompt('请输入分组名');
152 | if (name != null) {
153 | let group = {
154 | name: name,
155 | list: []
156 | };
157 | myNewTabWE.sites.push(group);
158 | myNewTabWE.setStorage();
159 | let node = myNewTabWE.buildGroup(group);
160 | $id('sites').appendChild(node);
161 | node.scrollIntoView({behavior: 'smooth', block: 'end'}); //与滚动区的可视区域的底端对齐
162 | }
163 | });
164 | },
165 | //初始化编辑界面
166 | initEdit: () => {
167 | $id('edit-upload').addEventListener('click', () => {
168 | upload.setAttribute('accept', 'image/*');
169 | upload.onchange = () => {
170 | let reader = new FileReader();
171 | reader.onload = () => {
172 | $id('edit-icon').value = reader.result;
173 | };
174 | reader.readAsDataURL(upload.files[0]);
175 | };
176 | upload.click();
177 | });
178 | let count = 0; //用来判断获取到的图标时的模态框是否还是原来的
179 | $id('edit-modal').setAttribute('count', count);
180 | $id('edit-geticon').addEventListener('click', () => {
181 | let iconUrl = /^https?:\/\/[^\/]+/i.exec($id('edit-url').value); //获取host
182 | if (iconUrl) {
183 | $id('edit-geticon').textContent = '正在获取';
184 | count = parseInt($id('edit-modal').getAttribute('count'));
185 | iconUrl += '/favicon.ico';
186 | let xhr = new XMLHttpRequest();
187 | xhr.responseType = 'document';
188 | xhr.open('GET', $id('edit-url').value, true);
189 | xhr.onload = () => {
190 | if (xhr.status == 200) {
191 | let icon = xhr.response.querySelector('link[rel~=icon]');
192 | if (icon && icon.href) {
193 | iconUrl = icon.href;
194 | } else {
195 | console.log($id('edit-url').value + ' 没有指定图标,尝试获取favicon.ico');
196 | }
197 | } else {
198 | console.log(new Error(xhr.statusText));
199 | }
200 | //获取图标
201 | xhr = new XMLHttpRequest();
202 | xhr.responseType = 'blob';
203 | xhr.open('GET', iconUrl, true);
204 | xhr.onload = () => {
205 | if (count == parseInt($id('edit-modal').getAttribute('count'))) {
206 | if (xhr.status == 200) {
207 | let reader = new FileReader();
208 | reader.onload = () => {
209 | $id('edit-icon').value = reader.result;
210 | };
211 | reader.readAsDataURL(xhr.response);
212 | } else {
213 | myNewTabWE.notify(new Error(xhr.statusText), '获取图标失败');
214 | }
215 | $id('edit-geticon').textContent = '自动获取';
216 | }
217 | };
218 | xhr.send(null);
219 | };
220 | xhr.send(null);
221 | } else {
222 | myNewTabWE.notify($id('edit-url').value, '不是标准http网址');
223 | }
224 | });
225 | },
226 |
227 | init: () => {
228 | myNewTabWE.initImportExport();
229 | myNewTabWE.initConf();
230 | myNewTabWE.confListener();
231 | myNewTabWE.initSites();
232 | myNewTabWE.initEdit();
233 | },
234 |
235 | //初始化选项事件
236 | confListener: () => {
237 | $id('config-default').addEventListener('click', e => {
238 | if (confirm('是否恢复默认选项?')) {
239 | myNewTabWE.config = DEFAULT_CONFIG.config;
240 | myNewTabWE.setStorage(true);
241 | myNewTabWE.initConf(); //重新初始化选项
242 | }
243 | });
244 | $id('newtab-open').addEventListener('click', e => {
245 | myNewTabWE.config.newTabOpen = e.target.checked;
246 | myNewTabWE.setStorage(true);
247 | });
248 | $id('bing-max-history').addEventListener('change', e => {
249 | myNewTabWE.config.bingMaxHistory = e.target.value;
250 | myNewTabWE.setStorage(true);
251 | });
252 | $id('UHD').addEventListener('click', () => {
253 | myNewTabWE.config.useBigImage = 2;
254 | myNewTabWE.setStorage(true);
255 | });
256 | $id('1920').addEventListener('click', () => {
257 | myNewTabWE.config.useBigImage = 1;
258 | myNewTabWE.setStorage(true);
259 | });
260 | $id('1366').addEventListener('click', () => {
261 | myNewTabWE.config.useBigImage = 0;
262 | myNewTabWE.setStorage(true);
263 | });
264 | $id('auto-change').addEventListener('click', e => {
265 | myNewTabWE.config.autoChange = e.target.checked;
266 | myNewTabWE.setStorage(true);
267 | });
268 | $id('auto-download').addEventListener('click', e => {
269 | myNewTabWE.config.autoDownload = e.target.checked;
270 | myNewTabWE.setStorage(true);
271 | });
272 | $id('download-dir').addEventListener('change', e => {
273 | myNewTabWE.config.downloadDir = e.target.value;
274 | myNewTabWE.setStorage(true);
275 | });
276 | $id('user-image').addEventListener('click', e => {
277 | myNewTabWE.config.userImage = e.target.checked;
278 | myNewTabWE.setStorage(true);
279 | });
280 | $id('image-upload').addEventListener('click', e => {
281 | upload.setAttribute('accept', 'image/*');
282 | upload.onchange = () => {
283 | let reader = new FileReader();
284 | reader.onload = () => {
285 | $id('user-image-src').value = myNewTabWE.config.userImageSrc = reader.result;
286 | myNewTabWE.setStorage(true);
287 | };
288 | reader.readAsDataURL(upload.files[0]);
289 | };
290 | upload.click();
291 | });
292 | $id('user-image-src').addEventListener('change', e => {
293 | myNewTabWE.config.userImageSrc = e.target.value;
294 | myNewTabWE.setStorage(true);
295 | });
296 | $id('title').addEventListener('change', e => {
297 | myNewTabWE.config.title = e.target.value;
298 | myNewTabWE.setStorage(true);
299 | });
300 | $id('weather-src').addEventListener('change', e => {
301 | myNewTabWE.config.weatherSrc = e.target.value;
302 | myNewTabWE.setStorage(true);
303 | });
304 | },
305 | buildGroup: group => {
306 | let node = $id('template-group').cloneNode(true);
307 | node.removeAttribute('id');
308 | node.removeAttribute('hidden');
309 | let table = node.querySelector('.group-table'),
310 | row = node.querySelector('.template-row');
311 |
312 | node.querySelector('.group-name').textContent = group.name;
313 | node.querySelector('.group-up').addEventListener('click', () => {
314 | let index = myNewTabWE.sites.indexOf(group);
315 | if (index) { //不是第一个
316 | myNewTabWE.sites[index - 1] = myNewTabWE.sites.splice(index, 1, myNewTabWE.sites[index - 1])[0];
317 | myNewTabWE.setStorage();
318 | node.parentNode.insertBefore(node, node.previousElementSibling);
319 | node.scrollIntoView({behavior: 'smooth', block: 'start'});
320 | }
321 | });
322 | node.querySelector('.group-down').addEventListener('click', () => {
323 | let index = myNewTabWE.sites.indexOf(group);
324 | if (index + 1 < myNewTabWE.sites.length) { //不是最后一个
325 | myNewTabWE.sites[index + 1] = myNewTabWE.sites.splice(index, 1, myNewTabWE.sites[index + 1])[0];
326 | myNewTabWE.setStorage();
327 | node.parentNode.insertBefore(node.nextElementSibling, node);
328 | node.scrollIntoView({behavior: 'smooth', block: 'start'});
329 | }
330 | });
331 | node.querySelector('.group-add').addEventListener('click', () => {
332 | let site = {
333 | title: '',
334 | url: '',
335 | icon: ''
336 | };
337 | myNewTabWE.editSite(site).then(() => {
338 | group.list.push(site);
339 | myNewTabWE.setStorage();
340 | let node = myNewTabWE.buildTr(site, group.list, row.cloneNode(true));
341 | table.appendChild(node);
342 | node.scrollIntoView({behavior: 'smooth', block: 'end'}); //与滚动区的可视区域的底端对齐
343 | });
344 | });
345 | node.querySelector('.group-rename').addEventListener('click', () => {
346 | let name = prompt('请输入分组名', group.name);
347 | if (name != null) {
348 | group.name = name;
349 | myNewTabWE.setStorage();
350 | node.querySelector('.group-name').textContent = group.name;
351 | }
352 | });
353 | node.querySelector('.group-delete').addEventListener('click', () => {
354 | myNewTabWE.sites.splice(myNewTabWE.sites.indexOf(group), 1);
355 | myNewTabWE.setStorage();
356 | $id('sites').removeChild(node);
357 | });
358 | for (let site of group.list) {
359 | table.appendChild(myNewTabWE.buildTr(site, group.list, row.cloneNode(true)));
360 | }
361 | return node;
362 | },
363 | buildTr: (site, list, node) => {
364 | node.removeAttribute('class');
365 | node.removeAttribute('hidden');
366 | let title = node.querySelector('.row-title'),
367 | img = node.querySelector('.row-icon img'),
368 | url = node.querySelector('.row-url');
369 | title.textContent = title.title = site.title;
370 | img.src = img.title = site.icon ? site.icon : '../image/default.svg';
371 | url.textContent = url.title = site.url;
372 | node.querySelector('.row-up').addEventListener('click', () => {
373 | let index = list.indexOf(site);
374 | if (index) { //不是第一个
375 | list[index - 1] = list.splice(index, 1, list[index - 1])[0];
376 | myNewTabWE.setStorage();
377 | node.parentNode.insertBefore(node, node.previousElementSibling);
378 | }
379 | });
380 | node.querySelector('.row-down').addEventListener('click', () => {
381 | let index = list.indexOf(site);
382 | if (index + 1 < list.length) { //不是最后一个
383 | list[index + 1] = list.splice(index, 1, list[index + 1])[0];
384 | myNewTabWE.setStorage();
385 | node.parentNode.insertBefore(node.nextElementSibling, node);
386 | }
387 | });
388 | node.querySelector('.row-edit').addEventListener('click', () => {
389 | myNewTabWE.editSite(site).then(() => {
390 | title.textContent = title.title = site.title;
391 | img.src = img.title = site.icon;
392 | url.textContent = url.title = site.url;
393 | myNewTabWE.setStorage();
394 | });
395 | });
396 | node.querySelector('.row-delete').addEventListener('click', () => {
397 | list.splice(list.indexOf(site), 1);
398 | myNewTabWE.setStorage();
399 | node.parentNode.removeChild(node);
400 | });
401 | return node;
402 | },
403 | editSite: site => {
404 | return new Promise((resolve, reject) => {
405 | $id('edit-title').value = site.title;
406 | $id('edit-url').value = site.url;
407 | $id('edit-icon').value = site.icon;
408 | $id('edit-geticon').textContent = '自动获取';
409 | $id('edit-confirm').onclick = () => {
410 | site.title = $id('edit-title').value;
411 | site.url = $id('edit-url').value;
412 | site.icon = $id('edit-icon').value;
413 | $id('edit-modal').style.display = 'none';
414 | $id('edit-modal').setAttribute('count', parseInt($id('edit-modal').getAttribute('count')) + 1);
415 | resolve();
416 | };
417 | $id('edit-cancel').onclick = () => {
418 | $id('edit-modal').style.display = 'none';
419 | $id('edit-modal').setAttribute('count', parseInt($id('edit-modal').getAttribute('count')) + 1);
420 | reject();
421 | };
422 | $id('edit-modal').style.display = 'flex';
423 | $id('edit-title').focus();
424 | });
425 | }
426 | };
427 |
428 | myNewTabWE.getStorage().then(myNewTabWE.init);
429 |
--------------------------------------------------------------------------------
/src/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "applications": {
3 | "gecko": {
4 | "id": "myNewTabWE@sakuyaa",
5 | "strict_min_version": "56.0",
6 | "update_url": "https://raw.githubusercontent.com/sakuyaa/myNewTabWE/master/release/updates.json"
7 | }
8 | },
9 | "author": "sakuyaa",
10 | "chrome_settings_overrides": {
11 | "homepage": "html/index.html"
12 | },
13 | "chrome_url_overrides": {
14 | "newtab": "html/index.html"
15 | },
16 | "description": "myNewTabMod这个扩展的WebExtension版本,由于API限制部分功能无法实现",
17 | "homepage_url": "https://github.com/sakuyaa/myNewTabWE",
18 | "icons": {
19 | "48": "image/home.svg",
20 | "96": "image/home.svg"
21 | },
22 | "manifest_version": 2,
23 | "name": "myNewTab WE",
24 | "options_ui": {
25 | "browser_style": false,
26 | "open_in_tab": true,
27 | "page": "html/options.html"
28 | },
29 | "permissions": [
30 | "downloads",
31 | "notifications",
32 | "storage",
33 | "tabs",
34 | "unlimitedStorage",
35 | "webNavigation",
36 | ""
37 | ],
38 | "version": "1.11.1"
39 | }
--------------------------------------------------------------------------------