avalon-mmRouter-rails 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a296a27f53516f76fa78459c0dbf614e1b30759e
4
+ data.tar.gz: 7a2c0f6ec0d2b9d38f81e09d396ca58583c4e089
5
+ SHA512:
6
+ metadata.gz: ccf719babbefbf6d1c891309a78c4f08b33fc8808bf5ba664e343b90fad62b8baa15a0d73fb3b834d78a34d19237f9f0df54f6940b68a5f300a87d50e8b5e561
7
+ data.tar.gz: 3cd2a801ced381fb890948c89e76338c829bd811af60e8e009cd0e94731ad9d434f43c643bdc2b25f2241f864b5fd45a19b93be1af3dbb7a08cdcb456f2d6419
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ *.DS_Store
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in avalon-mmRouter-rails.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 iron
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,17 @@
1
+ # Avalon::MmRouter::Rails
2
+
3
+ Rails 3.1 asset-pipeline gem to provide avalon.js mmRouter
4
+
5
+ mmRouter js: https://github.com/RubyLouvre/mmRouter
6
+
7
+ ```ruby
8
+ gem 'avalon-mmRouter-rails'
9
+ ```
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install avalon-mmRouter-rails
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'avalon/mmRouter/rails/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "avalon-mmRouter-rails"
8
+ spec.version = Avalon::MmRouter::Rails::VERSION
9
+ spec.authors = ["zj0713001"]
10
+ spec.email = ["zj0713001@gmail.com"]
11
+ spec.summary = %q{Use javascript framework Avalon mmRouter with Rails 3+}
12
+ spec.description = %q{his gem provides javascript framework Avalon mmRouter for your Rails 3+ application.}
13
+ spec.homepage = "https://github.com/zj0713001/avalon-mmRouter-rails"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.7"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ end
@@ -0,0 +1,13 @@
1
+ require "avalon/mmRouter/rails/version"
2
+
3
+ module Avalon
4
+ module MmRouter
5
+ module Rails
6
+ if defined?(::Rails) and Gem::Requirement.new('>= 3.1').satisfied_by?(Gem::Version.new ::Rails.version)
7
+ class Rails::Engine < ::Rails::Engine
8
+ # this class enables the asset pipeline
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,7 @@
1
+ module Avalon
2
+ module MmRouter
3
+ module Rails
4
+ VERSION = "0.0.1"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,310 @@
1
+ /*
2
+ *
3
+ * version 0.7
4
+ * built in 2015.10.12
5
+ */
6
+
7
+ define(["avalon"], function(avalon) {
8
+ var anchorElement = document.createElement('a')
9
+
10
+ var History = avalon.History = function() {
11
+ this.location = location
12
+ }
13
+
14
+ History.started = false
15
+ //取得当前IE的真实运行环境
16
+ History.IEVersion = (function() {
17
+ var mode = document.documentMode
18
+ return mode ? mode : window.XMLHttpRequest ? 7 : 6
19
+ })()
20
+
21
+ History.defaults = {
22
+ basepath: "/",
23
+ html5Mode: false,
24
+ hashPrefix: "!",
25
+ iframeID: null, //IE6-7,如果有在页面写死了一个iframe,这样似乎刷新的时候不会丢掉之前的历史
26
+ interval: 50, //IE6-7,使用轮询,这是其时间时隔
27
+ fireAnchor: true,//决定是否将滚动条定位于与hash同ID的元素上
28
+ routeElementJudger: avalon.noop // 判断a元素是否是触发router切换的链接
29
+ }
30
+
31
+ var oldIE = window.VBArray && History.IEVersion <= 7
32
+ var supportPushState = !!(window.history.pushState)
33
+ var supportHashChange = !!("onhashchange" in window && (!window.VBArray || !oldIE))
34
+ History.prototype = {
35
+ constructor: History,
36
+ getFragment: function(fragment) {
37
+ if (fragment == null) {
38
+ if (this.monitorMode === "popstate") {
39
+ fragment = this.getPath()
40
+ } else {
41
+ fragment = this.getHash()
42
+ }
43
+ }
44
+ return fragment.replace(/^[#\/]|\s+$/g, "")
45
+ },
46
+ getHash: function(window) {
47
+ // IE6直接用location.hash取hash,可能会取少一部分内容
48
+ // 比如 http://www.cnblogs.com/rubylouvre#stream/xxxxx?lang=zh_c
49
+ // ie6 => location.hash = #stream/xxxxx
50
+ // 其他浏览器 => location.hash = #stream/xxxxx?lang=zh_c
51
+ // firefox 会自作多情对hash进行decodeURIComponent
52
+ // 又比如 http://www.cnblogs.com/rubylouvre/#!/home/q={%22thedate%22:%2220121010~20121010%22}
53
+ // firefox 15 => #!/home/q={"thedate":"20121010~20121010"}
54
+ // 其他浏览器 => #!/home/q={%22thedate%22:%2220121010~20121010%22}
55
+ var path = (window || this).location.href
56
+ return this._getHash(path.slice(path.indexOf("#")))
57
+ },
58
+ _getHash: function(path) {
59
+ if (path.indexOf("#/") === 0) {
60
+ return decodeURIComponent(path.slice(2))
61
+ }
62
+ if (path.indexOf("#!/") === 0) {
63
+ return decodeURIComponent(path.slice(3))
64
+ }
65
+ return ""
66
+ },
67
+ getPath: function() {
68
+ var path = decodeURIComponent(this.location.pathname + this.location.search)
69
+ var root = this.basepath.slice(0, -1)
70
+ if (!path.indexOf(root))
71
+ path = path.slice(root.length)
72
+ return path.slice(1)
73
+ },
74
+ _getAbsolutePath: function(a) {
75
+ return !a.hasAttribute ? a.getAttribute("href", 4) : a.href
76
+ },
77
+ /*
78
+ * @interface avalon.history.start 开始监听历史变化
79
+ * @param options 配置参数
80
+ * @param options.hashPrefix hash以什么字符串开头,默认是 "!",对应实际效果就是"#!"
81
+ * @param options.routeElementJudger 判断a元素是否是触发router切换的链接的函数,return true则触发切换,默认为avalon.noop,history内部有一个判定逻辑,是先判定a元素的href属性是否以hashPrefix开头,如果是则当做router切换元素,因此综合判定规则是 href.indexOf(hashPrefix) == 0 || routeElementJudger(ele, ele.href),如果routeElementJudger返回true则跳转至href,如果返回的是字符串,则跳转至返回的字符串,如果返回false则返回浏览器默认行为
82
+ * @param options.html5Mode 是否采用html5模式,即不使用hash来记录历史,默认false
83
+ * @param options.fireAnchor 决定是否将滚动条定位于与hash同ID的元素上,默认为true
84
+ * @param options.basepath 根目录,默认为"/"
85
+ */
86
+ start: function(options) {
87
+ if (History.started)
88
+ throw new Error("avalon.history has already been started")
89
+ History.started = true
90
+ this.options = avalon.mix({}, History.defaults, options)
91
+ //IE6不支持maxHeight, IE7支持XMLHttpRequest, IE8支持window.Element,querySelector,
92
+ //IE9支持window.Node, window.HTMLElement, IE10不支持条件注释
93
+ //确保html5Mode属性存在,并且是一个布尔
94
+ this.html5Mode = !!this.options.html5Mode
95
+ //监听模式
96
+ this.monitorMode = this.html5Mode ? "popstate" : "hashchange"
97
+ if (!supportPushState) {
98
+ if (this.html5Mode) {
99
+ avalon.log("如果浏览器不支持HTML5 pushState,强制使用hash hack!")
100
+ this.html5Mode = false
101
+ }
102
+ this.monitorMode = "hashchange"
103
+ }
104
+ if (!supportHashChange) {
105
+ this.monitorMode = "iframepoll"
106
+ }
107
+ this.prefix = "#" + this.options.hashPrefix + "/"
108
+ //确认前后都存在斜线, 如"aaa/ --> /aaa/" , "/aaa --> /aaa/", "aaa --> /aaa/", "/ --> /"
109
+ this.basepath = ("/" + this.options.basepath + "/").replace(/^\/+|\/+$/g, "/") // 去最左右两边的斜线
110
+
111
+ this.fragment = this.getFragment()
112
+
113
+ anchorElement.href = this.basepath
114
+ this.rootpath = this._getAbsolutePath(anchorElement)
115
+ var that = this
116
+
117
+ var html = '<!doctype html><html><body>@</body></html>'
118
+ if (this.options.domain) {
119
+ html = html.replace("<body>", "<script>document.domain =" + this.options.domain + "</script><body>")
120
+ }
121
+ this.iframeHTML = html
122
+ if (this.monitorMode === "iframepoll") {
123
+ //IE6,7在hash改变时不会产生历史,需要用一个iframe来共享历史
124
+ avalon.ready(function() {
125
+ if(that.iframe) return
126
+ var iframe = that.iframe || document.getElementById(that.iframeID) || document.createElement('iframe')
127
+ iframe.src = 'javascript:0'
128
+ iframe.style.display = 'none'
129
+ iframe.tabIndex = -1
130
+ document.body.appendChild(iframe)
131
+ that.iframe = iframe.contentWindow
132
+ that._setIframeHistory(that.prefix + that.fragment)
133
+ })
134
+
135
+ }
136
+
137
+ // 支持popstate 就监听popstate
138
+ // 支持hashchange 就监听hashchange
139
+ // 否则的话只能每隔一段时间进行检测了
140
+ function checkUrl(e) {
141
+ var iframe = that.iframe
142
+ if (that.monitorMode === "iframepoll" && !iframe) {
143
+ return false
144
+ }
145
+ var pageHash = that.getFragment(), hash, lastHash = avalon.router.getLastPath()
146
+ if (iframe) {//IE67
147
+ var iframeHash = that.getHash(iframe)
148
+ //与当前页面hash不等于之前的页面hash,这主要是用户通过点击链接引发的
149
+ if (pageHash !== lastHash) {
150
+ that._setIframeHistory(that.prefix + pageHash)
151
+ hash = pageHash
152
+ //如果是后退按钮触发hash不一致
153
+ } else if (iframeHash !== lastHash) {
154
+ that.location.hash = that.prefix + iframeHash
155
+ hash = iframeHash
156
+ }
157
+
158
+ } else if (pageHash !== lastHash) {
159
+ hash = pageHash
160
+ }
161
+ if (hash !== void 0) {
162
+ that.fragment = hash
163
+ that.fireRouteChange(hash, {fromHistory: true})
164
+ }
165
+ }
166
+
167
+ //thanks https://github.com/browserstate/history.js/blob/master/scripts/uncompressed/history.html4.js#L272
168
+
169
+ // 支持popstate 就监听popstate
170
+ // 支持hashchange 就监听hashchange(IE8,IE9,FF3)
171
+ // 否则的话只能每隔一段时间进行检测了(IE6, IE7)
172
+ switch (this.monitorMode) {
173
+ case "popstate":
174
+ this.checkUrl = avalon.bind(window, "popstate", checkUrl)
175
+ this._fireLocationChange = checkUrl
176
+ break
177
+ case "hashchange":
178
+ this.checkUrl = avalon.bind(window, "hashchange", checkUrl)
179
+ break;
180
+ case "iframepoll":
181
+ this.checkUrl = setInterval(checkUrl, this.options.interval)
182
+ break;
183
+ }
184
+ //根据当前的location立即进入不同的路由回调
185
+ avalon.ready(function() {
186
+ that.fireRouteChange(that.fragment || "/", {replace: true})
187
+ })
188
+ },
189
+ fireRouteChange: function(hash, options) {
190
+ var router = avalon.router
191
+ if (router && router.navigate) {
192
+ router.setLastPath(hash)
193
+ router.navigate(hash === "/" ? hash : "/" + hash, options)
194
+ }
195
+ if (this.options.fireAnchor) {
196
+ scrollToAnchorId(hash.replace(/\?.*/g,""))
197
+ }
198
+ },
199
+ // 中断URL的监听
200
+ stop: function() {
201
+ avalon.unbind(window, "popstate", this.checkUrl)
202
+ avalon.unbind(window, "hashchange", this.checkUrl)
203
+ clearInterval(this.checkUrl)
204
+ History.started = false
205
+ },
206
+ updateLocation: function(hash, options, urlHash) {
207
+ var options = options || {},
208
+ rp = options.replace,
209
+ st = options.silent
210
+ if (this.monitorMode === "popstate") {
211
+ // html5 mode 第一次加载的时候保留之前的hash
212
+ var path = this.rootpath + hash + (urlHash || "")
213
+ // html5 model包含query
214
+ if(path != this.location.href.split("#")[0]) history[rp ? "replaceState" : "pushState"]({path: path}, document.title, path)
215
+ if(!st) this._fireLocationChange()
216
+ } else {
217
+ var newHash = this.prefix + hash
218
+ if(st && hash != this.getHash()) {
219
+ this._setIframeHistory(newHash, rp)
220
+ if(this.fragment) avalon.router.setLastPath(this.fragment)
221
+ this.fragment = this._getHash(newHash)
222
+ }
223
+ this._setHash(this.location, newHash, rp)
224
+ }
225
+ },
226
+ _setHash: function(location, hash, replace){
227
+ var href = location.href.replace(/(javascript:|#).*$/, '')
228
+ if (replace){
229
+ location.replace(href + hash)
230
+ }
231
+ else location.hash = hash
232
+ },
233
+ _setIframeHistory: function(hash, replace) {
234
+ if(!this.iframe) return
235
+ var idoc = this.iframe.document
236
+ idoc.open()
237
+ idoc.write(this.iframeHTML)
238
+ idoc.close()
239
+ this._setHash(idoc.location, hash, replace)
240
+ }
241
+ }
242
+
243
+ avalon.history = new History
244
+
245
+ //https://github.com/asual/jquery-address/blob/master/src/jquery.address.js
246
+
247
+ //劫持页面上所有点击事件,如果事件源来自链接或其内部,
248
+ //并且它不会跳出本页,并且以"#/"或"#!/"开头,那么触发updateLocation方法
249
+ avalon.bind(document, "click", function(event) {
250
+ var defaultPrevented = "defaultPrevented" in event ? event['defaultPrevented'] : event.returnValue === false
251
+
252
+ if (!History.started || defaultPrevented || event.ctrlKey || event.metaKey || event.which === 2)
253
+ return
254
+ var target = event.target
255
+ while (target.nodeName !== "A") {
256
+ target = target.parentNode
257
+ if (!target || target.tagName === "BODY") {
258
+ return
259
+ }
260
+ }
261
+
262
+ if (targetIsThisWindow(target.target)) {
263
+ var href = oldIE ? target.getAttribute("href", 2) : target.getAttribute("href") || target.getAttribute("xlink:href")
264
+ var prefix = avalon.history.prefix
265
+ if (href === null) { // href is null if the attribute is not present
266
+ return
267
+ }
268
+ var hash = href.replace(prefix, "").trim()
269
+ if(!(href.indexOf(prefix) === 0 && hash !== "")) {
270
+ var routeElementJudger = avalon.history.options.routeElementJudger
271
+ hash = routeElementJudger(target, href)
272
+ if(hash === true) hash = href
273
+ }
274
+ if (hash) {
275
+ event.preventDefault()
276
+ avalon.router && avalon.router.navigate(hash)
277
+ }
278
+ }
279
+ })
280
+
281
+ //判定A标签的target属性是否指向自身
282
+ //thanks https://github.com/quirkey/sammy/blob/master/lib/sammy.js#L219
283
+ function targetIsThisWindow(targetWindow) {
284
+ if (!targetWindow || targetWindow === window.name || targetWindow === '_self' || (targetWindow === 'top' && window == window.top)) {
285
+ return true
286
+ }
287
+ return false
288
+ }
289
+ //得到页面第一个符合条件的A标签
290
+ function getFirstAnchor(list) {
291
+ for (var i = 0, el; el = list[i++]; ) {
292
+ if (el.nodeName === "A") {
293
+ return el
294
+ }
295
+ }
296
+ }
297
+
298
+ function scrollToAnchorId(hash, el) {
299
+ if ((el = document.getElementById(hash))) {
300
+ el.scrollIntoView()
301
+ } else if ((el = getFirstAnchor(document.getElementsByName(hash)))) {
302
+ el.scrollIntoView()
303
+ } else {
304
+ window.scrollTo(0, 0)
305
+ }
306
+ }
307
+ return avalon
308
+ })
309
+
310
+ // 主要参数有 basepath html5Mode hashPrefix interval domain fireAnchor
@@ -0,0 +1,221 @@
1
+ define(["avalon"], function (avalon) {
2
+ //chrome36的原生Promise还多了一个defer()静态方法,允许不通过传参就能生成Promise实例,
3
+ //另还多了一个chain(onSuccess, onFail)原型方法,意义不明
4
+ //目前,firefox24, opera19也支持原生Promise(chrome32就支持了,但需要打开开关,自36起直接可用)
5
+ //本模块提供的Promise完整实现ECMA262v6 的Promise规范
6
+ //2015.3.12 支持async属性
7
+ function ok(val) {
8
+ return val
9
+ }
10
+ function ng(e) {
11
+ throw e
12
+ }
13
+
14
+ function done(onSuccess) {//添加成功回调
15
+ return this.then(onSuccess, ng)
16
+ }
17
+ function fail(onFail) {//添加出错回调
18
+ return this.then(ok, onFail)
19
+ }
20
+ function defer() {
21
+ var ret = {};
22
+ ret.promise = new this(function (resolve, reject) {
23
+ ret.resolve = resolve
24
+ ret.reject = reject
25
+ });
26
+ return ret
27
+ }
28
+ var msPromise = function (executor) {
29
+ this._callbacks = []
30
+ var me = this
31
+ if (typeof this !== "object")
32
+ throw new TypeError("Promises must be constructed via new")
33
+ if (typeof executor !== "function")
34
+ throw new TypeError("not a function")
35
+
36
+ executor(function (value) {
37
+ _resolve(me, value)
38
+ }, function (reason) {
39
+ _reject(me, reason)
40
+ })
41
+ }
42
+ function fireCallbacks(promise, fn) {
43
+ if (typeof promise.async === "boolean") {
44
+ var isAsync = promise.async
45
+ } else {
46
+ isAsync = promise.async = true
47
+ }
48
+ if (isAsync) {
49
+ window.setTimeout(fn, 0)
50
+ } else {
51
+ fn()
52
+ }
53
+ }
54
+ //返回一个已经处于`resolved`状态的Promise对象
55
+ msPromise.resolve = function (value) {
56
+ return new msPromise(function (resolve) {
57
+ resolve(value)
58
+ })
59
+ }
60
+ //返回一个已经处于`rejected`状态的Promise对象
61
+ msPromise.reject = function (reason) {
62
+ return new msPromise(function (resolve, reject) {
63
+ reject(reason)
64
+ })
65
+ }
66
+
67
+ msPromise.prototype = {
68
+ //一个Promise对象一共有3个状态:
69
+ //- `pending`:还处在等待状态,并没有明确最终结果
70
+ //- `resolved`:任务已经完成,处在成功状态
71
+ //- `rejected`:任务已经完成,处在失败状态
72
+ constructor: msPromise,
73
+ _state: "pending",
74
+ _fired: false, //判定是否已经被触发
75
+ _fire: function (onSuccess, onFail) {
76
+ if (this._state === "rejected") {
77
+ if (typeof onFail === "function") {
78
+ onFail(this._value)
79
+ } else {
80
+ throw this._value
81
+ }
82
+ } else {
83
+ if (typeof onSuccess === "function") {
84
+ onSuccess(this._value)
85
+ }
86
+ }
87
+ },
88
+ _then: function (onSuccess, onFail) {
89
+ if (this._fired) {//在已有Promise上添加回调
90
+ var me = this
91
+ fireCallbacks(me, function () {
92
+ me._fire(onSuccess, onFail)
93
+ });
94
+ } else {
95
+ this._callbacks.push({onSuccess: onSuccess, onFail: onFail})
96
+ }
97
+ },
98
+ then: function (onSuccess, onFail) {
99
+ onSuccess = typeof onSuccess === "function" ? onSuccess : ok
100
+ onFail = typeof onFail === "function" ? onFail : ng
101
+ var me = this//在新的Promise上添加回调
102
+ var nextPromise = new msPromise(function (resolve, reject) {
103
+ me._then(function (value) {
104
+ try {
105
+ value = onSuccess(value)
106
+ } catch (e) {
107
+ // https://promisesaplus.com/#point-55
108
+ reject(e)
109
+ return
110
+ }
111
+ resolve(value)
112
+ }, function (value) {
113
+ try {
114
+ value = onFail(value)
115
+ } catch (e) {
116
+ reject(e)
117
+ return
118
+ }
119
+ resolve(value)
120
+ })
121
+ })
122
+ for (var i in me) {
123
+ if (!personal[i]) {
124
+ nextPromise[i] = me[i]
125
+ }
126
+ }
127
+ return nextPromise
128
+ },
129
+ "done": done,
130
+ "catch": fail,
131
+ "fail": fail
132
+ }
133
+ var personal = {
134
+ _state: 1,
135
+ _fired: 1,
136
+ _value: 1,
137
+ _callbacks: 1
138
+ }
139
+ function _resolve(promise, value) {//触发成功回调
140
+ if (promise._state !== "pending")
141
+ return;
142
+ if (value && typeof value.then === "function") {
143
+ //thenable对象使用then,Promise实例使用_then
144
+ var method = value instanceof msPromise ? "_then" : "then"
145
+ value[method](function (val) {
146
+ _transmit(promise, val, true)
147
+ }, function (reason) {
148
+ _transmit(promise, reason, false)
149
+ });
150
+ } else {
151
+ _transmit(promise, value, true);
152
+ }
153
+ }
154
+ function _reject(promise, value) {//触发失败回调
155
+ if (promise._state !== "pending")
156
+ return
157
+ _transmit(promise, value, false)
158
+ }
159
+ //改变Promise的_fired值,并保持用户传参,触发所有回调
160
+ function _transmit(promise, value, isResolved) {
161
+ promise._fired = true;
162
+ promise._value = value;
163
+ promise._state = isResolved ? "fulfilled" : "rejected"
164
+ fireCallbacks(promise, function () {
165
+ promise._callbacks.forEach(function (data) {
166
+ promise._fire(data.onSuccess, data.onFail);
167
+ })
168
+ })
169
+ }
170
+ function _some(any, iterable) {
171
+ iterable = Array.isArray(iterable) ? iterable : []
172
+ var n = 0, result = [], end
173
+ return new msPromise(function (resolve, reject) {
174
+ // 空数组直接resolve
175
+ if (!iterable.length)
176
+ resolve(result)
177
+ function loop(a, index) {
178
+ a.then(function (ret) {
179
+ if (!end) {
180
+ result[index] = ret//保证回调的顺序
181
+ n++
182
+ if (any || n >= iterable.length) {
183
+ resolve(any ? ret : result)
184
+ end = true
185
+ }
186
+ }
187
+ }, function (e) {
188
+ end = true
189
+ reject(e)
190
+ })
191
+ }
192
+ for (var i = 0, l = iterable.length; i < l; i++) {
193
+ loop(iterable[i], i)
194
+ }
195
+ })
196
+ }
197
+
198
+ msPromise.all = function (iterable) {
199
+ return _some(false, iterable)
200
+ }
201
+ msPromise.race = function (iterable) {
202
+ return _some(true, iterable)
203
+ }
204
+ msPromise.defer = defer
205
+
206
+
207
+
208
+ avalon.Promise = msPromise
209
+ var nativePromise = window.Promise
210
+ if (/native code/.test(nativePromise)) {
211
+ nativePromise.prototype.done = done
212
+ nativePromise.prototype.fail = fail
213
+ if (!nativePromise.defer) { //chrome实现的私有方法
214
+ nativePromise.defer = defer
215
+ }
216
+ }
217
+ return window.Promise = nativePromise || msPromise
218
+
219
+ })
220
+ //https://github.com/ecomfe/er/blob/master/src/Deferred.js
221
+ //http://jser.info/post/77696682011/es6-promises