├── README.md
├── images
├── 1_x.png
├── x_2.png
├── x_y.png
├── 10_x.png
└── x_y_sqrt.png
├── screenshots
├── science.png
├── standard.png
└── programmer.png
├── css
└── cal.css
├── index.html
├── LICENSE
└── js
└── cal.js
/README.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/seaswalker/js_calculator/HEAD/README.md
--------------------------------------------------------------------------------
/images/1_x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/seaswalker/js_calculator/HEAD/images/1_x.png
--------------------------------------------------------------------------------
/images/x_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/seaswalker/js_calculator/HEAD/images/x_2.png
--------------------------------------------------------------------------------
/images/x_y.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/seaswalker/js_calculator/HEAD/images/x_y.png
--------------------------------------------------------------------------------
/images/10_x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/seaswalker/js_calculator/HEAD/images/10_x.png
--------------------------------------------------------------------------------
/images/x_y_sqrt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/seaswalker/js_calculator/HEAD/images/x_y_sqrt.png
--------------------------------------------------------------------------------
/screenshots/science.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/seaswalker/js_calculator/HEAD/screenshots/science.png
--------------------------------------------------------------------------------
/screenshots/standard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/seaswalker/js_calculator/HEAD/screenshots/standard.png
--------------------------------------------------------------------------------
/screenshots/programmer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/seaswalker/js_calculator/HEAD/screenshots/programmer.png
--------------------------------------------------------------------------------
/css/cal.css:
--------------------------------------------------------------------------------
1 | /*各界面共用部分开始*/
2 | * {
3 | font-family: "微软雅黑";
4 | }
5 |
6 | .standard-main,
7 | .science-main,
8 | .programmer-main {
9 | background-color: #F2F2F2;
10 | margin: 40px auto 0px;
11 | box-shadow: 0px 0px 15px #4D4D4D;
12 | }
13 |
14 | ul {
15 | list-style: none;
16 | margin: 0px;
17 | padding: 0px;
18 | }
19 |
20 | li {
21 | float: left;
22 | text-align: center;
23 | cursor: pointer;
24 | }
25 |
26 | li img {
27 | height: 14px;
28 | }
29 |
30 | .title {
31 | height: 30px;
32 | line-height: 30px;
33 | }
34 |
35 | .result {
36 | height: 120px;
37 | text-align: right;
38 | }
39 |
40 | .second {
41 | font-size: 40px;
42 | font-weight: bold;
43 | padding-right: 10px;
44 | }
45 |
46 | .pre {
47 | color: #A7A7A7;
48 | padding-right: 10px;
49 | }
50 |
51 | /*计算器类型*/
52 | .type {
53 | height: 20px;
54 | text-align: left;
55 | margin-left: 10px;
56 | font-weight: bold;
57 | margin-top: 10px;
58 | cursor: pointer;
59 | }
60 |
61 | /*类型选择侧边栏*/
62 | .type-bar {
63 | display: none;
64 | height: 90px;
65 | width: 100px;
66 | position: absolute;
67 | top: 110px;
68 | background-color: #E6E6E6;
69 | }
70 |
71 | .type-bar li {
72 | float: left;
73 | width: 100px;
74 | text-align: center;
75 | line-height: 30px;
76 | }
77 |
78 | .active {
79 | background-color: #CFCFCF;
80 | }
81 |
82 | /*数字加粗*/
83 | .number {
84 | font-weight: bold;
85 | }
86 |
87 | /*共用部分结束*/
88 |
89 | /*计算器标准版界面开始*/
90 | .standard-main {
91 | width: 350px;
92 | height: 480px;
93 | }
94 |
95 | #std-top-symbol {
96 | border-top: 1px #A7A7A7 solid;
97 | height: 52px;
98 | }
99 |
100 | #std-num-symbol {
101 | background-color: #E6E6E6;
102 | height: 270px;
103 | font-size: 20px;
104 | }
105 |
106 | #std-top-symbol li,
107 | #std-num-symbol li {
108 | line-height: 52px;
109 | width: 87.5px;
110 | }
111 |
112 | /*标准界面结束*/
113 |
114 | /*科学型界面开始*/
115 | .science-main {
116 | display: none;
117 | width: 350px;
118 | }
119 |
120 | .sci-result {
121 | height: 120px;
122 | text-align: right;
123 | }
124 |
125 | #sci-top-symbol {
126 | border-top: 1px #A7A7A7 solid;
127 | height: 135px;
128 | }
129 |
130 | #sci-top-symbol li,
131 | #sci-num-symbol li {
132 | line-height: 45px;
133 | width: 70px;
134 | }
135 |
136 | #sci-num-symbol {
137 | height: 235px;
138 | background-color: #E6E6E6;
139 | }
140 |
141 | /*科学型界面结束*/
142 |
143 | /*程序员型界面开始*/
144 | .programmer-main {
145 | display: none;
146 | width: 350px;
147 | }
148 |
149 | .pro-result {
150 | height: 220px;
151 | text-align: right;
152 | }
153 |
154 | #pro-top-symbol {
155 | border-top: 1px #A7A7A7 solid;
156 | height: 45px;
157 | }
158 |
159 | #pro-top-symbol li {
160 | line-height: 45px;
161 | width: 58px;
162 | }
163 |
164 | #pro-num-symbol li {
165 | line-height: 45px;
166 | width: 70px;
167 | }
168 |
169 | #pro-num-symbol {
170 | height: 235px;
171 | background-color: #E6E6E6;
172 | }
173 |
174 | /*四个进制*/
175 | #pro-scales {
176 | margin-left: 20px;
177 | }
178 |
179 | #pro-scales div {
180 | text-align: left;
181 | margin-top: 5px;
182 | cursor: pointer;
183 | }
184 |
185 | /*当前使用的进制*/
186 | .scale-active {
187 | color: cornflowerblue;
188 | }
189 |
190 | /*按键不可用*/
191 | .disable-btn {
192 | color: #CACACA;
193 | }
194 |
195 | /*程序员型界面结束*/
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 计算器
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | 计算器
16 |
17 |
18 |
19 |
20 |
21 | ☰ Standard
22 |
23 |
24 |
25 |
26 |
27 |
28 |
0
29 |
30 |
31 | - %
32 | - √
33 | 
34 | 
35 |
36 |
37 |
38 | - CE
39 | - C
40 | - Back
41 | - ÷
42 | - 7
43 | - 8
44 | - 9
45 | - ×
46 | - 4
47 | - 5
48 | - 6
49 | - -
50 | - 1
51 | - 2
52 | - 3
53 | - +
54 | - ±
55 | - 0
56 | - .
57 | - =
58 |
59 |
60 |
61 | - 标准
62 | - 科学
63 | - 程序员
64 |
65 |
66 |
67 |
68 |
69 | 计算器
70 |
71 |
72 |
73 |
74 |
75 | ☰ Science
76 |
77 |
78 |
79 |
80 |
81 |
82 |
0
83 |
84 |
85 |
86 | - (
87 | - )
88 | 
89 | - n!
90 | - Exp
91 | 
92 | 
93 | - sin
94 | - cos
95 | - tan
96 | 
97 | - log
98 | - sinh
99 | - cosh
100 | - tanh
101 |
102 |
103 |
104 | - π
105 | - CE
106 | - C
107 | - Back
108 | - ÷
109 | - √
110 | - 7
111 | - 8
112 | - 9
113 | - ×
114 | - %
115 | - 4
116 | - 5
117 | - 6
118 | - -
119 | 
120 | - 1
121 | - 2
122 | - 3
123 | - +
124 | - ↑
125 | - ±
126 | - 0
127 | - .
128 | - =
129 |
130 |
131 |
132 | - 标准
133 | - 科学
134 | - 程序员
135 |
136 |
137 |
138 |
139 |
140 | 计算器
141 |
142 |
143 |
144 |
145 |
146 | ☰ Programmer
147 |
148 |
149 |
150 |
151 |
152 |
153 |
0
154 |
155 |
156 |
HEX 0
157 |
DEC 0
158 |
OCT 0
159 |
BIN 0
160 |
161 |
162 |
163 |
164 | - A
165 | - B
166 | - C
167 | - D
168 | - E
169 | - F
170 |
171 |
172 |
173 | - ↑
174 | - CE
175 | - C
176 | - Back
177 | - ÷
178 | - And
179 | - 7
180 | - 8
181 | - 9
182 | - ×
183 | - Or
184 | - 4
185 | - 5
186 | - 6
187 | - -
188 | - Not
189 | - 1
190 | - 2
191 | - 3
192 | - +
193 | - (
194 | - )
195 | - 0
196 | - .
197 | - =
198 |
199 |
200 |
201 | - 标准
202 | - 科学
203 | - 程序员
204 |
205 |
206 |
207 |
208 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction, and
10 | distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by the copyright
13 | owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all other entities
16 | that control, are controlled by, or are under common control with that entity.
17 | For the purposes of this definition, "control" means (i) the power, direct or
18 | indirect, to cause the direction or management of such entity, whether by
19 | contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
20 | outstanding shares, or (iii) beneficial ownership of such entity.
21 |
22 | "You" (or "Your") shall mean an individual or Legal Entity exercising
23 | permissions granted by this License.
24 |
25 | "Source" form shall mean the preferred form for making modifications, including
26 | but not limited to software source code, documentation source, and configuration
27 | files.
28 |
29 | "Object" form shall mean any form resulting from mechanical transformation or
30 | translation of a Source form, including but not limited to compiled object code,
31 | generated documentation, and conversions to other media types.
32 |
33 | "Work" shall mean the work of authorship, whether in Source or Object form, made
34 | available under the License, as indicated by a copyright notice that is included
35 | in or attached to the work (an example is provided in the Appendix below).
36 |
37 | "Derivative Works" shall mean any work, whether in Source or Object form, that
38 | is based on (or derived from) the Work and for which the editorial revisions,
39 | annotations, elaborations, or other modifications represent, as a whole, an
40 | original work of authorship. For the purposes of this License, Derivative Works
41 | shall not include works that remain separable from, or merely link (or bind by
42 | name) to the interfaces of, the Work and Derivative Works thereof.
43 |
44 | "Contribution" shall mean any work of authorship, including the original version
45 | of the Work and any modifications or additions to that Work or Derivative Works
46 | thereof, that is intentionally submitted to Licensor for inclusion in the Work
47 | by the copyright owner or by an individual or Legal Entity authorized to submit
48 | on behalf of the copyright owner. For the purposes of this definition,
49 | "submitted" means any form of electronic, verbal, or written communication sent
50 | to the Licensor or its representatives, including but not limited to
51 | communication on electronic mailing lists, source code control systems, and
52 | issue tracking systems that are managed by, or on behalf of, the Licensor for
53 | the purpose of discussing and improving the Work, but excluding communication
54 | that is conspicuously marked or otherwise designated in writing by the copyright
55 | owner as "Not a Contribution."
56 |
57 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf
58 | of whom a Contribution has been received by Licensor and subsequently
59 | incorporated within the Work.
60 |
61 | 2. Grant of Copyright License.
62 |
63 | Subject to the terms and conditions of this License, each Contributor hereby
64 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
65 | irrevocable copyright license to reproduce, prepare Derivative Works of,
66 | publicly display, publicly perform, sublicense, and distribute the Work and such
67 | Derivative Works in Source or Object form.
68 |
69 | 3. Grant of Patent License.
70 |
71 | Subject to the terms and conditions of this License, each Contributor hereby
72 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
73 | irrevocable (except as stated in this section) patent license to make, have
74 | made, use, offer to sell, sell, import, and otherwise transfer the Work, where
75 | such license applies only to those patent claims licensable by such Contributor
76 | that are necessarily infringed by their Contribution(s) alone or by combination
77 | of their Contribution(s) with the Work to which such Contribution(s) was
78 | submitted. If You institute patent litigation against any entity (including a
79 | cross-claim or counterclaim in a lawsuit) alleging that the Work or a
80 | Contribution incorporated within the Work constitutes direct or contributory
81 | patent infringement, then any patent licenses granted to You under this License
82 | for that Work shall terminate as of the date such litigation is filed.
83 |
84 | 4. Redistribution.
85 |
86 | You may reproduce and distribute copies of the Work or Derivative Works thereof
87 | in any medium, with or without modifications, and in Source or Object form,
88 | provided that You meet the following conditions:
89 |
90 | You must give any other recipients of the Work or Derivative Works a copy of
91 | this License; and
92 | You must cause any modified files to carry prominent notices stating that You
93 | changed the files; and
94 | You must retain, in the Source form of any Derivative Works that You distribute,
95 | all copyright, patent, trademark, and attribution notices from the Source form
96 | of the Work, excluding those notices that do not pertain to any part of the
97 | Derivative Works; and
98 | If the Work includes a "NOTICE" text file as part of its distribution, then any
99 | Derivative Works that You distribute must include a readable copy of the
100 | attribution notices contained within such NOTICE file, excluding those notices
101 | that do not pertain to any part of the Derivative Works, in at least one of the
102 | following places: within a NOTICE text file distributed as part of the
103 | Derivative Works; within the Source form or documentation, if provided along
104 | with the Derivative Works; or, within a display generated by the Derivative
105 | Works, if and wherever such third-party notices normally appear. The contents of
106 | the NOTICE file are for informational purposes only and do not modify the
107 | License. You may add Your own attribution notices within Derivative Works that
108 | You distribute, alongside or as an addendum to the NOTICE text from the Work,
109 | provided that such additional attribution notices cannot be construed as
110 | modifying the License.
111 | You may add Your own copyright statement to Your modifications and may provide
112 | additional or different license terms and conditions for use, reproduction, or
113 | distribution of Your modifications, or for any such Derivative Works as a whole,
114 | provided Your use, reproduction, and distribution of the Work otherwise complies
115 | with the conditions stated in this License.
116 |
117 | 5. Submission of Contributions.
118 |
119 | Unless You explicitly state otherwise, any Contribution intentionally submitted
120 | for inclusion in the Work by You to the Licensor shall be under the terms and
121 | conditions of this License, without any additional terms or conditions.
122 | Notwithstanding the above, nothing herein shall supersede or modify the terms of
123 | any separate license agreement you may have executed with Licensor regarding
124 | such Contributions.
125 |
126 | 6. Trademarks.
127 |
128 | This License does not grant permission to use the trade names, trademarks,
129 | service marks, or product names of the Licensor, except as required for
130 | reasonable and customary use in describing the origin of the Work and
131 | reproducing the content of the NOTICE file.
132 |
133 | 7. Disclaimer of Warranty.
134 |
135 | Unless required by applicable law or agreed to in writing, Licensor provides the
136 | Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
137 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
138 | including, without limitation, any warranties or conditions of TITLE,
139 | NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
140 | solely responsible for determining the appropriateness of using or
141 | redistributing the Work and assume any risks associated with Your exercise of
142 | permissions under this License.
143 |
144 | 8. Limitation of Liability.
145 |
146 | In no event and under no legal theory, whether in tort (including negligence),
147 | contract, or otherwise, unless required by applicable law (such as deliberate
148 | and grossly negligent acts) or agreed to in writing, shall any Contributor be
149 | liable to You for damages, including any direct, indirect, special, incidental,
150 | or consequential damages of any character arising as a result of this License or
151 | out of the use or inability to use the Work (including but not limited to
152 | damages for loss of goodwill, work stoppage, computer failure or malfunction, or
153 | any and all other commercial damages or losses), even if such Contributor has
154 | been advised of the possibility of such damages.
155 |
156 | 9. Accepting Warranty or Additional Liability.
157 |
158 | While redistributing the Work or Derivative Works thereof, You may choose to
159 | offer, and charge a fee for, acceptance of support, warranty, indemnity, or
160 | other liability obligations and/or rights consistent with this License. However,
161 | in accepting such obligations, You may act only on Your own behalf and on Your
162 | sole responsibility, not on behalf of any other Contributor, and only if You
163 | agree to indemnify, defend, and hold each Contributor harmless for any liability
164 | incurred by, or claims asserted against, such Contributor by reason of your
165 | accepting any such warranty or additional liability.
166 |
167 | END OF TERMS AND CONDITIONS
168 |
169 | APPENDIX: How to apply the Apache License to your work
170 |
171 | To apply the Apache License to your work, attach the following boilerplate
172 | notice, with the fields enclosed by brackets "{}" replaced with your own
173 | identifying information. (Don't include the brackets!) The text should be
174 | enclosed in the appropriate comment syntax for the file format. We also
175 | recommend that a file or class name and description of purpose be included on
176 | the same "printed page" as the copyright notice for easier identification within
177 | third-party archives.
178 |
179 | Copyright 2015 seaswalker
180 |
181 | Licensed under the Apache License, Version 2.0 (the "License");
182 | you may not use this file except in compliance with the License.
183 | You may obtain a copy of the License at
184 |
185 | http://www.apache.org/licenses/LICENSE-2.0
186 |
187 | Unless required by applicable law or agreed to in writing, software
188 | distributed under the License is distributed on an "AS IS" BASIS,
189 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
190 | See the License for the specific language governing permissions and
191 | limitations under the License.
--------------------------------------------------------------------------------
/js/cal.js:
--------------------------------------------------------------------------------
1 | window.onload = function () {
2 | Calculator.initCache();
3 | Calculator.initListeners();
4 | };
5 |
6 | //全局计算器对象
7 | var Calculator = (function () {
8 | var cal = {
9 | //计算器按键编码
10 | keyCodes: {
11 | 0: '0',
12 | 1: '1',
13 | 2: '2',
14 | 3: '3',
15 | 4: '4',
16 | 5: '5',
17 | 6: '6',
18 | 7: '7',
19 | 8: '8',
20 | 9: '9',
21 | 10: '.',
22 | 11: '±',
23 | 12: '=',
24 | 13: '+',
25 | 14: '-',
26 | 15: '*',
27 | 16: '/',
28 | 17: '%',
29 | 18: '√',
30 | 19: 'x2',
31 | 20: '1/x',
32 | 21: '(',
33 | 22: ')',
34 | 23: 'yroot',
35 | 24: 'n!',
36 | 25: 'Exp',
37 | 26: '^',
38 | 27: 'sin',
39 | 28: 'cos',
40 | 29: 'tan',
41 | 30: 'powten',
42 | 31: 'log',
43 | 32: 'sinh',
44 | 33: 'cosh',
45 | 34: 'tanh',
46 | 35: 'π',
47 | 36: '↑',
48 | 37: 'CE',
49 | 38: 'C',
50 | 39: 'Back',
51 | //以下是程序员型特有的按键
52 | 40: 'A',
53 | 41: 'B',
54 | 42: 'C',
55 | 43: 'D',
56 | 44: 'E',
57 | 45: 'F',
58 | 46: '&',
59 | 47: '|',
60 | 48: '~'
61 | },
62 | //映射用于显示的操作符,比如计算时用*,而显示时x更好
63 | operatorFacade: {
64 | 13: '+',
65 | 14: '-',
66 | 15: '×',
67 | 16: '÷',
68 | 17: '%',
69 | 23: 'yroot',
70 | 26: '^',
71 | 46: '&',
72 | 47: '|'
73 | },
74 | //当前计算器的类型1 --> 标准型, 2-->科学型, 3-->程序员型,默认标准型
75 | type: 1,
76 | //计算器类型前缀,用于从页面获取元素
77 | typePrefix: {
78 | 1: "std-",
79 | 2: "sci-",
80 | 3: "pro-"
81 | },
82 | //记录每个类型的计算器的事件监听是否已经绑定,key:typpe数值,value:默认标准型是true(已加载)
83 | hasInited: {
84 | 1: true,
85 | 2: false,
86 | 3: false
87 | },
88 | //常量
89 | constants: {
90 | //鼠标悬停时的颜色
91 | mouseHoverColor: "#CFCFCF",
92 | //计算器第一行和下面其它行的颜色是不同的,这个是第一行的背景颜色
93 | firstMouseOutColor: "#F2F2F2",
94 | //剩余各行的背景颜色
95 | mouseOutColor: "#E6E6E6"
96 | },
97 | cache: {
98 | //输入内容显示元素
99 | showInput: null,
100 | //上一步计算结果显示区域
101 | preStep: null,
102 | //显示四种进制数值的span,只在程序员型有效
103 | scaleSpans: null
104 | },
105 | /**
106 | * 获取cache.showInput的内容
107 | * @return String
108 | */
109 | getShowInput: function () {
110 | return cal.cache.showInput.innerHTML;
111 | },
112 | /**
113 | * 设置showInput的值
114 | * @param value
115 | */
116 | setShowInput: function (value) {
117 | cal.cache.showInput.innerHTML = value;
118 | },
119 | /**
120 | * 获取cache.preStep的内容
121 | * @return String
122 | */
123 | getPreStep: function () {
124 | return cal.cache.preStep.innerHTML;
125 | },
126 | setPreStep: function (value) {
127 | cal.cache.preStep.innerHTML = value;
128 | },
129 | //操作数栈
130 | operandStack: [],
131 | //运算符栈
132 | operatorStack: [],
133 | //上一次输入是否是二元运算符,如果是并且再次输入二元运算符,那么忽略此次输入
134 | isPreInputBinaryOperator: false,
135 | //上次按键是否是一元操作
136 | isPreInputUnaryOperator: false,
137 | //等号不可以连按
138 | isPreInputEquals: false,
139 | //如果为true,那么接下来输入的数字需要覆盖在showInput上,而不是追加
140 | //上一次计算的结果(=)
141 | preResult: 0,
142 | //当前使用的进制(只在程序员中有效),默认10进制(DEC)
143 | currentScale: 10,
144 | isOverride: false,
145 | //int校验
146 | intPattern: /^-?\d+$/,
147 | //小数校验
148 | floatPattern: /^-?\d+\.\d+$/,
149 | //科学计数法校验
150 | scientificPattern: /^\d+\.\d+e(\+|-)\d+$/,
151 | //校验16进制数字
152 | hexPattern: /^[0-9A-F]+$/,
153 | //辅助判断运算符的优先级
154 | operatorPriority: {
155 | ")": 0,
156 | "|": 1,
157 | "&": 2,
158 | "+": 3,
159 | "-": 3,
160 | "*": 4,
161 | "%": 4,
162 | "/": 4,
163 | "^": 5,
164 | "yroot": 5,
165 | "(": 6
166 | },
167 | /**
168 | * 初始化缓存对象(cal.cache)
169 | */
170 | initCache: function () {
171 | var prefix = cal.typePrefix[cal.type];
172 | cal.cache.showInput = document.getElementById(prefix + "show-input");
173 | cal.cache.preStep = document.getElementById(prefix + "pre-step");
174 | if (cal.type == 3) {
175 | cal.cache.scaleSpans = document.getElementById("pro-scales").getElementsByTagName("span");
176 | }
177 | },
178 | //各种事件监听函数
179 | listeners: {
180 | /**
181 | * 鼠标悬停在按键上的变色效果
182 | */
183 | mouseHoverListener: function (e) {
184 | var event = e || window.event;
185 | event.currentTarget.style.backgroundColor = cal.constants.mouseHoverColor;
186 | },
187 | /**
188 | * 鼠标从上排符号中移出的变色效果
189 | */
190 | firstMouseOutListener: function (e) {
191 | var event = e || window.event;
192 | event.currentTarget.style.backgroundColor = cal.constants.firstMouseOutColor;
193 | },
194 | /**
195 | * 鼠标从下排数字、符号中移出的变色效果
196 | */
197 | mouseOutListener: function (e) {
198 | var event = e || window.event;
199 | event.currentTarget.style.backgroundColor = cal.constants.mouseOutColor;
200 | },
201 | /**
202 | * 按键按下事件监听
203 | */
204 | keyPressListener: function (e) {
205 | var event = e || window.event;
206 | cal.handleKey(event.currentTarget.value);
207 | },
208 | /**
209 | * 显示/隐藏计算器类型选择栏
210 | */
211 | toggleTypeBarListener: function () {
212 | var bar = document.getElementById(cal.typePrefix[cal.type] + "type-bar");
213 | if (bar.style.display === "block") {
214 | bar.style.display = "none";
215 | } else {
216 | bar.style.display = "block";
217 | }
218 | },
219 | /**
220 | * 切换计算器类型监听器
221 | */
222 | switchTypeListener: function (e) {
223 | var event = e || window.event;
224 | cal.switchType(parseInt(event.currentTarget.value));
225 | },
226 | /**
227 | * 切换进制(程序员专用)
228 | */
229 | switchScaleListener: function (e) {
230 | var event = e || window.event;
231 | var scales = document.getElementById("pro-scales").getElementsByTagName("div"),
232 | //此处应该使用currentTarget属性,因为target属性在绑定事件的元素有子元素的情况下会返回子元素
233 | scale = parseInt(event.currentTarget.getAttribute("scale")),
234 | oldScale = cal.currentScale;
235 | //切换选中样式
236 | for (var i = 0, l = scales.length; i < l; ++i) {
237 | scales[i].removeAttribute("class");
238 | }
239 | event.currentTarget.setAttribute("class", "scale-active");
240 | var lis, btns;
241 | if (scale === 16) {
242 | //处理上排6个16进制数字
243 | cal.listeners._initFirstRowListeners();
244 | if (oldScale < 10) {
245 | cal.listeners._initSecondRowListeners();
246 | }
247 | } else if (scale === 10) {
248 | if (oldScale === 16) {
249 | lis = document.getElementById("pro-top-symbol").getElementsByTagName("li");
250 | cal.disableButtons(lis, cal.listeners.firstMouseOutListener);
251 | } else {
252 | cal.listeners._initSecondRowListeners();
253 | }
254 | } else if (scale === 8) {
255 | if (oldScale > 8) {
256 | lis = document.getElementById("pro-top-symbol").getElementsByTagName("li");
257 | cal.disableButtons(lis, cal.listeners.firstMouseOutListener);
258 | //禁用8和9
259 | btns = cal.getElementsByAttribute("li", "oct-disable", document.getElementById("pro-num-symbol"));
260 | cal.disableButtons(btns, cal.listeners.mouseOutListener);
261 | } else {
262 | cal.listeners._initSecondRowListeners();
263 | }
264 | } else if (scale === 2) {
265 | if (oldScale === 16) {
266 | lis = document.getElementById("pro-top-symbol").getElementsByTagName("li");
267 | cal.disableButtons(lis, cal.listeners.firstMouseOutListener);
268 | }
269 | //禁用2-9
270 | btns = cal.getElementsByAttribute("li", "bin-disable", document.getElementById("pro-num-symbol"));
271 | cal.disableButtons(btns, cal.listeners.mouseOutListener);
272 | }
273 | cal.currentScale = scale;
274 | },
275 | /**
276 | * 初始化第一排操运算符事件监听
277 | * @private
278 | */
279 | _initFirstRowListeners: function () {
280 | var lis = document.getElementById(cal.typePrefix[cal.type] + "top-symbol").getElementsByTagName("li");
281 | cal.rebuildButtons(lis, cal.listeners.firstMouseOutListener);
282 | },
283 | /**
284 | * 初始化第二排运算符事件监听
285 | * @private
286 | */
287 | _initSecondRowListeners: function () {
288 | var lis = document.getElementById(cal.typePrefix[cal.type] + "num-symbol").getElementsByTagName("li");
289 | cal.rebuildButtons(lis, cal.listeners.mouseOutListener);
290 | if (cal.type === 3) {
291 | //程序员型的小数点是禁用的
292 | cal.disableButtons([document.getElementById("pro-point")], cal.listeners.mouseOutListener);
293 | }
294 | }
295 | },
296 | //初始化事件监听器
297 | initListeners: function () {
298 | var prefix = cal.typePrefix[cal.type];
299 | //设置上排运算符事件监听,如果是程序员型,因为默认是10进制,而上排是16进制数字,所以不需要设置事件监听
300 | if (cal.type < 3) {
301 | cal.listeners._initFirstRowListeners();
302 | }
303 | //设置下面一栏数字、四则运算事件监听
304 | cal.listeners._initSecondRowListeners();
305 | //显示/隐藏计算器类型选择侧边栏
306 | cal.addEvent(document.getElementById(prefix + "show-bar"), "click", cal.listeners.toggleTypeBarListener);
307 | //为侧边栏下的li绑定切换类型事件
308 | var bar = document.getElementById(prefix + "type-bar");
309 | lis = bar.getElementsByTagName("li");
310 | var li;
311 | for (var i = 0, l = lis.length; i < l; ++i) {
312 | li = lis[i];
313 | //非当前类型才有必要绑定事件
314 | if (li.className !== "active") {
315 | cal.addEvent(li, "click", cal.listeners.switchTypeListener);
316 | }
317 | }
318 | //加载程序员型特有的
319 | if (cal.type === 3) {
320 | var scales = document.getElementById("pro-scales").getElementsByTagName("div"),
321 | scale;
322 | for (i = 0, l = scales.length; i < l; ++i) {
323 | scale = scales[i];
324 | cal.addEvent(scale, "click", cal.listeners.switchScaleListener);
325 | }
326 | }
327 | },
328 | /**
329 | * 相应按键按下事件
330 | * @param value 按键的value值(即其keyCode)
331 | */
332 | handleKey: function (value) {
333 | var keyCode = parseInt(value);
334 | //如果是一个数字或者小数点,直接显示出来
335 | if (keyCode < 11 || (keyCode > 39 && keyCode < 46)) {
336 | cal.showInput(cal.keyCodes[keyCode]);
337 | if (cal.type === 3) {
338 | //如果是程序员型,那么需要同步显示4中进制的值
339 | cal.showScales(cal.getShowInput());
340 | }
341 | } else {
342 | switch (keyCode) {
343 | //正负号
344 | case 11:
345 | cal.unaryOperate(function (oldValue) {
346 | oldValue += "";
347 | if (oldValue === "0") {
348 | return [oldValue];
349 | }
350 | if (oldValue.charAt(0) === '-') {
351 | return [oldValue.substring(1)];
352 | } else {
353 | return ["-" + oldValue];
354 | }
355 | });
356 | break;
357 | //开根下
358 | case 18:
359 | cal.unaryOperate(function (si) {
360 | return [Math.sqrt(si), "sqrt"];
361 | });
362 | break;
363 | //平方
364 | case 19:
365 | cal.unaryOperate(function (si) {
366 | return [Math.pow(si, 2), "sqr"];
367 | });
368 | break;
369 | //取倒数
370 | case 20:
371 | cal.unaryOperate(function (si) {
372 | return [si === 0 ? "0不能作为被除数" : 1 / si, "1/"];
373 | });
374 | break;
375 | //阶乘
376 | case 24:
377 | cal.unaryOperate(function (si) {
378 | if (si < 0) {
379 | si = (0 - si);
380 | }
381 | if (cal.isFloat(si + "")) {
382 | si = Math.floor(si);
383 | }
384 | return [cal.fact(si), "fact"];
385 | });
386 | break;
387 | //Exp 转为科学计数法表示
388 | case 25:
389 | cal.unaryOperate(function (si) {
390 | return [si.toExponential(7)];
391 | });
392 | break;
393 | //sin
394 | case 27:
395 | cal.unaryOperate(function (si) {
396 | return [Math.sin(si), "sin"];
397 | });
398 | break;
399 | //cos
400 | case 28:
401 | cal.unaryOperate(function (si) {
402 | return [Math.cos(si), "cos"];
403 | });
404 | break;
405 | //tan
406 | case 29:
407 | cal.unaryOperate(function (si) {
408 | return [Math.tan(si), "tan"];
409 | });
410 | break;
411 | //10的x次方
412 | case 30:
413 | cal.unaryOperate(function (si) {
414 | return [Math.pow(10, si), "powten"];
415 | });
416 | break;
417 | //log
418 | case 31:
419 | cal.unaryOperate(function (si) {
420 | //js的Math.log是e的对数,Windows计算器是10的对数,此处参考Windows
421 | return [Math.log10(si), "log"];
422 | });
423 | break;
424 | //sinh(双曲正弦函数)
425 | case 32:
426 | cal.unaryOperate(function (si) {
427 | return [Math.sinh(si), "sinh"];
428 | });
429 | break;
430 | //cosh(双曲余弦函数)
431 | case 33:
432 | cal.unaryOperate(function (si) {
433 | return [Math.cosh(si), "cosh"];
434 | });
435 | break;
436 | //tanh(双曲余切函数)
437 | case 34:
438 | cal.unaryOperate(function (si) {
439 | return [Math.tanh(si), "tanh"];
440 | });
441 | break;
442 | //π
443 | case 35:
444 | cal.unaryOperate(function (si) {
445 | return [Math.PI];
446 | });
447 | break;
448 | //按位取反(~)
449 | case 48:
450 | cal.unaryOperate(function (si) {
451 | var result = eval("~" + si);
452 | //显示四种进制的数值
453 | cal.showScales(result);
454 | return [result];
455 | });
456 | break;
457 | //二元运算符开始
458 | //加、减、乘、除、取余,运算比较简单,直接利用eval即可求值
459 | case 13:
460 | case 14:
461 | case 15:
462 | case 16:
463 | case 17:
464 | //x的y次方
465 | case 26:
466 | //开任意次方根
467 | case 23:
468 | //And Or
469 | case 46:
470 | case 47:
471 | if (cal.isPreInputBinaryOperator) {
472 | break;
473 | }
474 | cal.isPreInputBinaryOperator = true;
475 | cal.isOverride = true;
476 | cal.binaryOperate(cal.keyCodes[keyCode], cal.operatorFacade[keyCode]);
477 | break;
478 | case 12:
479 | cal.calculate();
480 | break;
481 | //ce
482 | case 37:
483 | cal.ce();
484 | break;
485 | //c
486 | case 38:
487 | cal.clear();
488 | break;
489 | //back
490 | case 39:
491 | cal.back();
492 | break;
493 | // (
494 | case 21:
495 | cal.setPreStep(cal.getPreStep() + " (");
496 | cal.operatorStack.push("(");
497 | break;
498 | // )
499 | case 22:
500 | cal.rightTag();
501 | break;
502 | //向上箭头,把上次计算结果显示出来
503 | case 36:
504 | cal.setShowInput(cal.preResult);
505 | break;
506 | }
507 | }
508 | },
509 | /**
510 | * 执行一元运算 比如取倒数、平方
511 | * @param operation 具体运算回调函数
512 | * 会向operation传递一个参数si,为用户当前的输入,同时operation函数应该返回一个数组,数组的第一个
513 | * 元素是计算的结果,第二个元素示例sqrt,第二个参数可选
514 | */
515 | unaryOperate: function (operation) {
516 | var si = cal.getShowInput(),
517 | result;
518 | if (cal.isInteger(si)) {
519 | result = operation(parseInt(si));
520 | } else if (cal.isFloat(si) || cal.isScientific(si)) {
521 | result = operation(parseFloat(si));
522 | }
523 | if (result != null) {
524 | cal.setShowInput(cal.checkLength(result[0]));
525 | if (result.length > 1) {
526 | //显示prestep有两种情况:
527 | //第一种就是这是第一次(指连续调用的第一次)调用一元函数,此时直接接在末尾即可
528 | if (!cal.isPreInputUnaryOperator) {
529 | cal.setPreStep(cal.getPreStep() + " " + result[1] + "(" + si + ")");
530 | cal.isPreInputUnaryOperator = true;
531 | } else {
532 | //第二种就是这不是第一次,那么应该截取最后一个空格之后的内容进行替换
533 | //比如1 + 3 + sqrt(100),那么应该从最后一个空格后替换为此次操作的内容
534 | var pi = cal.getPreStep();
535 | pi = pi.substring(0, pi.lastIndexOf(" "));
536 | pi += (" " + result[1] + "(" + si + ")");
537 | cal.setPreStep(pi);
538 | }
539 | }
540 | //一元运算结束后应该覆盖
541 | cal.isOverride = true;
542 | }
543 | cal.isPreInputBinaryOperator = false;
544 | },
545 | /**
546 | * 二元操作(+ - * / %)
547 | * @param operator 操作符
548 | * @param facade 运算符门面,用于显示在preStep中
549 | */
550 | binaryOperate: function (operator, facade) {
551 | //如果是程序员型,那么需要重置scalesSpan
552 | if (cal.type === 3) {
553 | cal.resetScales();
554 | }
555 | var si = cal.getShowInput(),
556 | pi = cal.getPreStep();
557 | if (cal.isNumber(si)) {
558 | //压操作数栈
559 | cal.operandStack.push(si);
560 | //设置preStep有三种情况:第一种上一步不是一元操作,那么需要设置si,第二种是一元操作,那么由于一元操作会把
561 | //函数表达式(比如sqrt(100))设置到preStep,所以不需要再次设置si
562 | //第三种就是如果最后一位是右括号,那么也不需要设置si
563 | cal.setPreStep(cal.getPreStep() + ((cal.isPreInputUnaryOperator || pi.charAt(pi.length - 1) === ")") ?
564 | (" " + facade) : (" " + si + " " + facade)));
565 | var preOp = cal.operatorStack.pop();
566 | if (preOp != null) {
567 | var op = cal.operatorPriority[operator],
568 | pp = cal.operatorPriority[preOp];
569 | //如果当前运算符优先级更高,那么只需压栈不需要计算
570 | if (op > pp) {
571 | cal.operatorStack.push(preOp);
572 | }
573 | //两者的优先级相等并且高于3(加减),那么只需要计算一步
574 | else if (op > 3 && op === pp) {
575 | cal.operatorStack.push(preOp);
576 | cal.travelStack(1);
577 | } else {
578 | cal.operatorStack.push(preOp);
579 | cal.setShowInput(cal.checkLength(cal.travelStack(null, op)));
580 | }
581 | }
582 | cal.operatorStack.push(operator);
583 | }
584 | cal.isPreInputUnaryOperator = false;
585 | cal.isPreInputEquals = false;
586 | },
587 | /**
588 | * 按下=时计算最终结果
589 | */
590 | calculate: function () {
591 | if (!cal.isPreInputEquals) {
592 | var si = cal.getShowInput(),
593 | result;
594 | if (cal.isNumber(si)) {
595 | cal.operandStack.push(si);
596 | result = cal.checkLength(cal.travelStack());
597 | cal.setShowInput(result);
598 | cal.preResult = result;
599 | cal.setPreStep(" ");
600 | //程序员型需要把计算结果的四种进制值显示出来
601 | if (cal.type === 3) {
602 | cal.showScales(result);
603 | }
604 | cal.isOverride = true;
605 | }
606 | cal._reset();
607 | cal.isPreInputEquals = true;
608 | }
609 | },
610 | /**
611 | * 访问运算栈,返回计算结果
612 | * @param level 计算的层数,如果不指定,那么遍历整个栈
613 | * @param minPri(最小/截止优先级) 此参数针对下面的情况:
614 | * 2 + 2 X 3 X 2 ^ 2 X 2,由于最后一个运算符是X,优先级比^低,所以触发了对操作栈的遍历,但是不能全部遍历,应该遍历到第一个X停止
615 | * 如果不停止得到的将是错误的26 X 2 = 52,正确结果是2 + 24 X 2 = 50
616 | * @return Number
617 | * @private
618 | */
619 | travelStack: function (level, minPri) {
620 | var op, f, s,
621 | //result取操作数栈栈顶,因为防止在下列情况9 X (6 + 时出现undefined
622 | result = cal.operandStack[cal.operandStack.length - 1],
623 | l = level || cal.operatorStack.length,
624 | p = minPri || 0;
625 | for (var i = 0; i < l; ++i) {
626 | op = cal.operatorStack.pop();
627 | //遇到minPri或左括号立即停止,左括号也需要再次压入,因为只有一个右括号才能抵消一个左括号
628 | if (cal.operatorPriority[op] < p || op === "(") {
629 | cal.operatorStack.push(op);
630 | break;
631 | }
632 | s = cal.operandStack.pop();
633 | f = cal.operandStack.pop();
634 | result = cal._stackHelper(f, s, op);
635 | cal.operandStack.push(result);
636 | }
637 | return result;
638 | },
639 | /**
640 | * 输入了一个右括号
641 | */
642 | rightTag: function () {
643 | var si = cal.getShowInput();
644 | if (cal.isNumber(si)) {
645 | cal.setPreStep(cal.getPreStep() + (" " + si + " )"));
646 | cal.operandStack.push(si);
647 | //遍历计算操作栈,直至遇到左括号
648 | var op = cal.operatorStack.pop(),
649 | f, s, result;
650 | while (op !== "(" && op != null) {
651 | s = cal.operandStack.pop();
652 | f = cal.operandStack.pop();
653 | result = cal._stackHelper(f, s, op);
654 | cal.operandStack.push(result);
655 | op = cal.operatorStack.pop();
656 | }
657 | //此处应该直接把小括号的计算内容弹出,因为此结果显示在了showInput中,而再次执行二元操作时会先有一个压栈的操作,
658 | // 并且执行=时也是根据showInput内容计算的
659 | cal.setShowInput(cal.checkLength(cal.operandStack.pop()));
660 | }
661 | },
662 | /**
663 | * 辅助进行一次栈运算
664 | * @param f 第一个操作数
665 | * @param s 第二个操作数
666 | * @param op 运算符
667 | * @return 返回运算结果
668 | * @private
669 | */
670 | _stackHelper: function (f, s, op) {
671 | var result;
672 | if (op === "^") {
673 | result = Math.pow(f, s);
674 | } else if (op === "yroot") {
675 | result = Math.pow(f, 1 / s);
676 | }
677 | //+ - X / %5中操作
678 | else {
679 | //如果是程序员型,那么需要考虑进制的问题
680 | if (cal.type === 3) {
681 | var scale = cal.currentScale,
682 | fi, si;
683 | if (scale === 10) {
684 | result = eval(f + op + s);
685 | } else if (scale === 16) {
686 | fi = parseInt(f, 16);
687 | si = parseInt(s, 16);
688 | result = eval(fi + op + si).toString(16);
689 | } else if (scale === 8) {
690 | fi = parseInt(f, 8);
691 | si = parseInt(s, 8);
692 | result = eval(fi + op + si).toString(8);
693 | } else {
694 | fi = parseInt(f, 2);
695 | si = parseInt(s, 2);
696 | result = eval(fi + op + si).toString(2);
697 | }
698 | } else {
699 | result = eval(f + op + s);
700 | }
701 | }
702 | return result;
703 | },
704 | /**
705 | * 确保结果长度不大于13,如果超出,以科学计数法形式显示(小数点后7位)
706 | * @param value 需要检查的结果
707 | */
708 | checkLength: function (value) {
709 | var valueStr = value + "";
710 | if (cal.isFloat(valueStr)) {
711 | valueStr = valueStr.replace(/0+$/, "");
712 | }
713 | return valueStr.length > 12 ? value.toExponential(7) : valueStr;
714 | },
715 | //CE
716 | ce: function () {
717 | cal.setShowInput("0");
718 | if (cal.type === 3) {
719 | cal.resetScales();
720 | }
721 | },
722 | //C
723 | clear: function () {
724 | cal.setShowInput("0");
725 | cal.setPreStep(" ");
726 | cal._reset();
727 | if (cal.type === 3) {
728 | cal.resetScales();
729 | }
730 | },
731 | /**
732 | * 清空四个进制的值
733 | * @private
734 | */
735 | resetScales: function () {
736 | for (var i = 0; i < 4; i++) {
737 | cal.cache.scaleSpans[i].innerHTML = "0";
738 | }
739 | },
740 | back: function () {
741 | var oldValue = cal.cache.showInput.innerText;
742 | cal.setShowInput(oldValue.length < 2 ? "0" : oldValue.substring(0, oldValue.length - 1));
743 | },
744 | /**
745 | * 当计算器类型是程序员时,需要同步显示四种进制的值
746 | * @param num 需要显示的数字
747 | */
748 | showScales: function (num) {
749 | var result = cal.calculateScales(num),
750 | spans = cal.cache.scaleSpans;
751 | for (var i = 0; i < 4; ++i) {
752 | spans[i].innerHTML = result[i];
753 | }
754 | },
755 | /**
756 | * 根据当前进制分别计算出四种进制的值
757 | * @param num 需要计算的值
758 | * @return Array 共4个元素,依次为16、10、8、2进制的值
759 | */
760 | calculateScales: function (num) {
761 | var scale = cal.currentScale,
762 | result = [],
763 | i;
764 | if (scale === 10) {
765 | i = parseInt(num);
766 | result[0] = i.toString(16);
767 | result[1] = i;
768 | result[2] = i.toString(8);
769 | result[3] = i.toString(2);
770 | } else if (scale === 16) {
771 | //先转成10进制,然后再转成其它进制
772 | i = parseInt(num, 16);
773 | result[0] = num;
774 | result[1] = i;
775 | result[2] = i.toString(8);
776 | result[3] = i.toString(2);
777 | } else if (scale === 8) {
778 | i = parseInt(num, 8);
779 | result[0] = i.toString(16);
780 | result[1] = i;
781 | result[2] = num;
782 | result[3] = i.toString(2);
783 | } else {
784 | i = parseInt(num, 2);
785 | result[0] = i.toString(16);
786 | result[1] = i;
787 | result[2] = i.toString(8);
788 | result[3] = num;
789 | }
790 | return result;
791 | },
792 | /**
793 | * 校验字符串是否是数字
794 | * @param str
795 | * @return 是返回true
796 | */
797 | isNumber: function (str) {
798 | return cal.isInteger(str) || cal.isFloat(str) || cal.isScientific(str) || cal.isHex(str);
799 | },
800 | /**
801 | * 校验是否是整数
802 | * @param str
803 | */
804 | isInteger: function (str) {
805 | return str.match(cal.intPattern);
806 | },
807 | /**
808 | * 校验是否是小数
809 | * @param str
810 | */
811 | isFloat: function (str) {
812 | return str.match(cal.floatPattern);
813 | },
814 | /**
815 | * 是否是科学计数法
816 | * @param str
817 | */
818 | isScientific: function (str) {
819 | return str.match(cal.scientificPattern);
820 | },
821 | /**
822 | * 是否是16进制数字
823 | * @param str
824 | */
825 | isHex: function (str) {
826 | return str.match(cal.hexPattern);
827 | },
828 | /**
829 | * 显示输入的内容
830 | * 用于相应数字/小数点按键
831 | * @param value 按键的内容,不是keyCode
832 | */
833 | showInput: function (value) {
834 | var oldValue = cal.getShowInput();
835 | var newValue = oldValue;
836 | if (cal.isOverride) {
837 | //既然是覆盖,那么如果直接输入.那么肯定是0.x
838 | if (value === ".") {
839 | newValue = "0.";
840 | } else {
841 | newValue = value;
842 | }
843 | } else if (oldValue.length < 13) {
844 | if (oldValue === "0") {
845 | if (value === ".") {
846 | newValue = "0.";
847 | } else {
848 | newValue = value;
849 | }
850 | } else {
851 | newValue += value;
852 | }
853 | }
854 | cal.setShowInput(newValue);
855 | cal.isOverride = false;
856 | cal.isPreInputBinaryOperator = false;
857 | cal.isPreInputUnaryOperator = false;
858 | cal.isPreInputEquals = false;
859 | },
860 | /**
861 | * 切换计算器类型
862 | * @param type int 要切换到的类型
863 | */
864 | switchType: function (type) {
865 | //关闭选择栏
866 | var oldPrefix = cal.typePrefix[cal.type];
867 | document.getElementById(oldPrefix + "type-bar").style.display = "none";
868 | //切换面板
869 | document.getElementById(oldPrefix + "main").style.display = "none";
870 | document.getElementById(cal.typePrefix[type] + "main").style.display = "block";
871 | cal.type = type;
872 | if (!cal.hasInited[type]) {
873 | cal.initListeners();
874 | cal.hasInited[type] = true;
875 | }
876 | cal.initCache();
877 | cal._reset();
878 | },
879 | /**
880 | * 重置各个标志变量以及操作栈
881 | * @private
882 | */
883 | _reset: function () {
884 | cal.operandStack = [];
885 | cal.operatorStack = [];
886 | cal.isPreInputBinaryOperator = false;
887 | cal.isPreInputUnaryOperator = false;
888 | cal.isPreInputEquals = false;
889 | },
890 | /**
891 | * 工具方法,为element添加事件处理函数
892 | * @param element 需要添加事件的dom元素
893 | * @param name name事件名称(不含on)
894 | * @param handler 事件处理函数
895 | */
896 | addEvent: function (element, name, handler) {
897 | if (window.addEventListener) {
898 | element.addEventListener(name, handler);
899 | } else if (window.attachEvent) {
900 | element.attachEvent("on" + name, handler);
901 | }
902 | },
903 | /**
904 | * 工具方法,为element移除特定的事件监听
905 | * @param element 需要移除事件监听的dom元素
906 | * @param name 事件名,没有"on"
907 | * @param handler 需要移除的处理函数
908 | */
909 | removeEvent: function (element, name, handler) {
910 | if (window.removeEventListener) {
911 | element.removeEventListener(name, handler);
912 | } else if (window.detachEvent) {
913 | element.detachEvent("on" + name, handler);
914 | }
915 | },
916 | /**
917 | * 根据元素的属性进行查找,只要存在此属性即可
918 | * @param tag 目标标签名
919 | * @param attr
920 | * @param root 开始查找的起始节点,可选,默认document
921 | */
922 | getElementsByAttribute: function (tag, attr, root) {
923 | var parent = root || document,
924 | result = [];
925 | var arr = parent.getElementsByTagName(tag),
926 | a;
927 | for (var i = 0, l = arr.length; i < l; ++i) {
928 | a = arr[i];
929 | if (a.getAttribute(attr) != null) {
930 | //这个写法...
931 | result[result.length] = a;
932 | }
933 | }
934 | return result;
935 | },
936 | /**
937 | * 阶乘
938 | * @param n 操作数 int
939 | * @return
940 | */
941 | fact: (function () {
942 | //缓存
943 | var cache = [1];
944 |
945 | function factorial(n) {
946 | var result = cache[n - 1];
947 | if (result == null) {
948 | result = 1;
949 | for (var i = 1; i <= n; ++i) {
950 | result *= i;
951 | }
952 | cache[n - 1] = result;
953 | }
954 | return result;
955 | }
956 | return factorial;
957 | })(),
958 | /**
959 | * 禁用按键,只有程序员型才会用到
960 | * @param lis 按钮集合
961 | * @param mouseOutListener function 鼠标移出时采用哪个监听函数,取决于按钮的位置(上排/下排)
962 | */
963 | disableButtons: function (lis, mouseOutListener) {
964 | var li;
965 | for (var i = 0, l = lis.length; i < l; ++i) {
966 | li = lis[i];
967 | li.setAttribute("class", "disable-btn");
968 | cal.removeEvent(li, "click", cal.listeners.keyPressListener);
969 | cal.removeEvent(li, "mouseout", mouseOutListener);
970 | cal.removeEvent(li, "mouseover", cal.listeners.mouseHoverListener);
971 | }
972 | },
973 | /**
974 | * 重新设置按键
975 | * @param lis 按钮集合
976 | * @param mouseOutListener function 鼠标移出时采用哪个监听函数,取决于按钮的位置(上排/下排)
977 | */
978 | rebuildButtons: function (lis, mouseOutListener) {
979 | var li;
980 | for (var i = 0, l = lis.length; i < l; ++i) {
981 | li = lis[i];
982 | li.removeAttribute("class");
983 | cal.addEvent(li, "click", cal.listeners.keyPressListener);
984 | cal.addEvent(li, "mouseout", mouseOutListener);
985 | cal.addEvent(li, "mouseover", cal.listeners.mouseHoverListener);
986 | }
987 | }
988 | };
989 | return cal;
990 | })();
--------------------------------------------------------------------------------