UNPKG

5.1 kBJavaScriptView Raw
1
2/* litejs.com/MIT-LICENSE.txt */
3
4
5
6!function(exports) {
7 var fn, lastView, lastParams, lastStr, lastUrl, syncResume
8 , capture = 1
9 , fnStr = ""
10 , reStr = ""
11 , views = View.views = {}
12 , escapeRe = /[.*+?^=!:${}()|\[\]\/\\]/g
13 , parseRe = /\{([\w%.]+?)\}|.[^{\\]*?/g
14
15 exports.View = View
16
17 function View(route, el, parent) {
18 var view = views[route]
19 if (view) {
20 if (el) {
21 view.el = el
22 view.parent = parent && View(parent)
23 }
24 return view
25 }
26 view = this
27 if (!(view instanceof View)) return new View(route, el, parent)
28 views[view.route = route] = view
29 view.el = el
30 view.parent = parent && View(parent)
31
32 if (route.charAt(0) != "#") {
33 var params = "m[" + (view.seq = capture++) + "]?("
34 , _re = route.replace(parseRe, function(_, key) {
35 return key ?
36 (params += "o['" + key + "']=m[" + (capture++) + "],") && "([^/]+?)" :
37 _.replace(escapeRe, "\\$&")
38 })
39
40 fnStr += params + "'" + route + "'):"
41 reStr += (reStr ? "|(" : "(") + _re + ")"
42 fn = 0
43 }
44 }
45
46 View.prototype = {
47 show: function(_params) {
48 var parent
49 , params = lastParams = _params || {}
50 , view = lastView = this
51 , tmp = params._v || view
52 , close = view.isOpen && view
53
54 View.active = view.route
55
56 for (; tmp; tmp = parent) {
57 syncResume = params._v = tmp
58 tmp.emit("ping", params)
59 View.emit("ping", params, tmp)
60 syncResume = null
61 if (lastParams != params) return
62 if (parent = tmp.parent) {
63 if (parent.child && parent.child != tmp) {
64 close = parent.child
65 }
66 parent.child = tmp
67 }
68 if (!tmp.el) {
69 if (tmp.file) {
70 xhr.load(
71 tmp.file
72 .replace(/^|,/g, "$&" + (View.base || ""))
73 .split(","),
74 view.wait()
75 )
76 tmp.file = null
77 } else {
78 View("404").show(Object.assign({}, params))
79 }
80 return
81 }
82 }
83
84 for (tmp in params) if (tmp.charAt(0) != "_") {
85 if (syncResume = param[tmp] || param["*"]) {
86 syncResume.call(view, params[tmp], tmp, params)
87 syncResume = null
88 }
89 }
90
91 bubbleDown(params, close)
92 },
93 wait: function() {
94 var params = lastParams
95 params._p = 1 + (params._p | 0)
96 return function() {
97 if (--params._p || lastParams != params || syncResume) return
98 if (params._d) {
99 bubbleDown(params)
100 } else if (params._v) {
101 lastView.show(params)
102 }
103 }
104 }
105 }
106
107 function bubbleDown(params, close) {
108 var tmp
109 , view = params._v
110 , parent = view && view.parent
111 if (!view || params._p && /{/.test(view.route)) {
112 return closeView(close)
113 }
114 if (parent && !view.isOpen || view === close) {
115 closeView(close, view)
116 El.scope(
117 view.isOpen = view.el.cloneNode(true),
118 El.scope(tmp = parent.isOpen || parent.el)
119 )
120 El.append(tmp, view.isOpen)
121 El.render(view.isOpen)
122 parent.emit("openChild", view, close)
123 view.emit("open", params)
124 View.emit("open", params, view)
125 if (view.kb) El.addKb(view.kb)
126 close = null
127 }
128 if (params._d = params._v = view.child) {
129 bubbleDown(params, close)
130 }
131 if (lastView == view) {
132 view.emit("show", params)
133 View.emit("show", params, view)
134 blur()
135 }
136 }
137
138 function closeView(view, open) {
139 if (view && view.isOpen) {
140 view.parent.emit("closeChild", view, open)
141 closeView(view.child)
142 El.kill(view.isOpen)
143 view.isOpen = null
144 if (view.kb) El.rmKb(view.kb)
145 view.emit("close")
146 }
147 }
148
149 Event.asEmitter(View)
150 Event.asEmitter(View.prototype)
151
152 View.base = "view/"
153 View.home = "home"
154
155 View.get = get
156 function get(url, params) {
157 if (!fn) {
158 fn = Function(
159 "var r=/^\\/?(?:" + reStr + ")[\\/\\s]*$/;" +
160 "return function(i,o,d){var m=r.exec(i);return m!==null?(" + fnStr + "d):d}"
161 )()
162 }
163 return View(fn(url || View.home, params || {}, "404"))
164 }
165
166 View.show = function(url, _params) {
167 if (url === true) {
168 url = lastUrl
169 lastUrl = 0
170 }
171 var params = _params || {}
172 , view = get(url, params)
173 if (!view.isOpen || lastUrl != url) {
174 params._u = lastUrl = url
175 view.show(El.data.route = params)
176 }
177 }
178
179 View.param = param
180 function param(name, cb) {
181 [].concat(name).forEach(function(n) {
182 param[n] = cb
183 })
184 }
185
186 View.def = function(str) {
187 for (var match, re = /(\S+) (\S+)/g; match = re.exec(str);) {
188 match[1].split(",").map(function(view) {
189 view = View(defMap(view, lastStr))
190 view.file = (view.file ? view.file + "," : "") +
191 match[2].split(",").map(function(file) {
192 return views[file] ? views[file].file : defMap(file, lastStr)
193 })
194 })
195 }
196 }
197
198 View.blur = blur
199 function blur() {
200 // When a View completes, blur focused link
201 // IE8 can throw an exception for document.activeElement.
202 try {
203 var el = document.activeElement
204 , tag = el && el.tagName
205 if (tag === "A" || tag === "BUTTON") el.blur()
206 } catch(e) {}
207 }
208
209 View.url = defMap
210 function defMap(str, _last) {
211 var chr = str.charAt(0)
212 , slice = str.slice(1)
213 , last = _last || lastUrl
214 return (
215 chr === "+" ? last + slice :
216 chr === "%" ? ((chr = last.lastIndexOf(slice.charAt(0))), (chr > 0 ? last.slice(0, chr) : last)) + slice :
217 (lastStr = str)
218 )
219 }
220
221}(this)
222