avalon-mmRouter-rails 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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