joosy 1.1.2 → 1.2.0.alpha.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +6 -7
- data/Gemfile +1 -11
- data/Gruntfile.coffee +138 -0
- data/README.md +65 -24
- data/bin/joosy +21 -0
- data/bower.json +23 -0
- data/joosy.gemspec +6 -12
- data/lib/joosy.js +3754 -0
- data/lib/joosy.rb +8 -9
- data/package.json +37 -0
- data/spec/{javascripts/helpers/spec_helper.js.coffee → helpers/helper.coffee} +0 -0
- data/spec/{javascripts/joosy/core/application_spec.js.coffee → joosy/core/application_spec.coffee} +0 -0
- data/spec/{javascripts/joosy/core/form_spec.js.coffee → joosy/core/form_spec.coffee} +30 -30
- data/spec/{javascripts/joosy/core/helpers/forms_spec.js.coffee → joosy/core/helpers/forms_spec.coffee} +0 -0
- data/spec/{javascripts/joosy/core/helpers/view_spec.js.coffee → joosy/core/helpers/view_spec.coffee} +0 -0
- data/spec/{javascripts/joosy/core/helpers/widgets_spec.js.coffee → joosy/core/helpers/widgets_spec.coffee} +0 -0
- data/spec/{javascripts/joosy/core/joosy_spec.js.coffee → joosy/core/joosy_spec.coffee} +0 -0
- data/spec/{javascripts/joosy/core/layout_spec.js.coffee → joosy/core/layout_spec.coffee} +0 -0
- data/spec/{javascripts/joosy/core/modules/container_spec.js.coffee → joosy/core/modules/container_spec.coffee} +1 -1
- data/spec/{javascripts/joosy/core/modules/events_spec.js.coffee → joosy/core/modules/events_spec.coffee} +0 -0
- data/spec/{javascripts/joosy/core/modules/filters_spec.js.coffee → joosy/core/modules/filters_spec.coffee} +0 -0
- data/spec/{javascripts/joosy/core/modules/log_spec.js.coffee → joosy/core/modules/log_spec.coffee} +0 -0
- data/spec/{javascripts/joosy/core/modules/module_spec.js.coffee → joosy/core/modules/module_spec.coffee} +0 -0
- data/spec/{javascripts/joosy/core/modules/renderer_spec.js.coffee → joosy/core/modules/renderer_spec.coffee} +35 -0
- data/spec/{javascripts/joosy/core/modules/time_manager_spec.js.coffee → joosy/core/modules/time_manager_spec.coffee} +0 -0
- data/spec/{javascripts/joosy/core/modules/widget_manager_spec.js.coffee → joosy/core/modules/widget_manager_spec.coffee} +0 -0
- data/spec/{javascripts/joosy/core/page_spec.js.coffee → joosy/core/page_spec.coffee} +0 -0
- data/spec/{javascripts/joosy/core/resource/collection_spec.js.coffee → joosy/core/resource/collection_spec.coffee} +0 -0
- data/spec/{javascripts/joosy/core/resource/generic_spec.js.coffee → joosy/core/resource/generic_spec.coffee} +0 -0
- data/spec/{javascripts/joosy/core/resource/rest_collection_spec.js.coffee → joosy/core/resource/rest_collection_spec.coffee} +0 -0
- data/spec/{javascripts/joosy/core/resource/rest_spec.js.coffee → joosy/core/resource/rest_spec.coffee} +0 -8
- data/spec/{javascripts/joosy/core/router_spec.js.coffee → joosy/core/router_spec.coffee} +19 -22
- data/spec/{javascripts/joosy/core/templaters/rails_jst_spec.js.coffee → joosy/core/templaters/rails_jst_spec.coffee} +0 -0
- data/spec/{javascripts/joosy/core/widget_spec.js.coffee → joosy/core/widget_spec.coffee} +0 -0
- data/spec/{javascripts/joosy/preloaders/caching_spec.js.coffee → joosy/preloaders/caching_spec.coffee} +2 -2
- data/spec/{javascripts/joosy/preloaders/inline_spec.js.coffee → joosy/preloaders/inline_spec.coffee} +1 -1
- data/spec/support/test.js +1 -0
- data/{app/assets/javascripts/joosy/core/application.js.coffee → src/joosy/core/application.coffee} +0 -0
- data/{app/assets/javascripts/joosy/core/form.js.coffee → src/joosy/core/form.coffee} +5 -5
- data/{app/assets/javascripts/joosy/core/helpers/form.js.coffee → src/joosy/core/helpers/form.coffee} +0 -0
- data/{app/assets/javascripts/joosy/core/helpers/view.js.coffee → src/joosy/core/helpers/view.coffee} +0 -0
- data/{app/assets/javascripts/joosy/core/helpers/widgets.js.coffee → src/joosy/core/helpers/widgets.coffee} +0 -0
- data/{app/assets/javascripts/joosy/core/joosy.js.coffee → src/joosy/core/joosy.coffee} +1 -1
- data/{app/assets/javascripts/joosy/core/layout.js.coffee → src/joosy/core/layout.coffee} +0 -0
- data/{app/assets/javascripts/joosy/core/modules/container.js.coffee → src/joosy/core/modules/container.coffee} +1 -1
- data/{app/assets/javascripts/joosy/core/modules/events.js.coffee → src/joosy/core/modules/events.coffee} +4 -6
- data/{app/assets/javascripts/joosy/core/modules/filters.js.coffee → src/joosy/core/modules/filters.coffee} +0 -0
- data/{app/assets/javascripts/joosy/core/modules/log.js.coffee → src/joosy/core/modules/log.coffee} +0 -0
- data/{app/assets/javascripts/joosy/core/modules/module.js.coffee → src/joosy/core/modules/module.coffee} +0 -0
- data/{app/assets/javascripts/joosy/core/modules/renderer.js.coffee → src/joosy/core/modules/renderer.coffee} +1 -1
- data/{app/assets/javascripts/joosy/core/modules/time_manager.js.coffee → src/joosy/core/modules/time_manager.coffee} +0 -0
- data/{app/assets/javascripts/joosy/core/modules/widgets_manager.js.coffee → src/joosy/core/modules/widgets_manager.coffee} +0 -0
- data/{app/assets/javascripts/joosy/core/page.js.coffee → src/joosy/core/page.coffee} +0 -1
- data/{app/assets/javascripts/joosy/core/preloader.js.coffee → src/joosy/core/preloader.coffee} +0 -0
- data/{app/assets/javascripts/joosy/core/resource/collection.js.coffee → src/joosy/core/resource/collection.coffee} +0 -0
- data/{app/assets/javascripts/joosy/core/resource/generic.js.coffee → src/joosy/core/resource/generic.coffee} +5 -5
- data/{app/assets/javascripts/joosy/core/resource/rest.js.coffee → src/joosy/core/resource/rest.coffee} +5 -5
- data/{app/assets/javascripts/joosy/core/resource/rest_collection.js.coffee → src/joosy/core/resource/rest_collection.coffee} +0 -0
- data/src/joosy/core/resource/watcher.coffee +50 -0
- data/{app/assets/javascripts/joosy/core/router.js.coffee → src/joosy/core/router.coffee} +28 -30
- data/{app/assets/javascripts/joosy/core/templaters/rails_jst.js.coffee → src/joosy/core/templaters/rails_jst.coffee} +12 -2
- data/{app/assets/javascripts/joosy/core/widget.js.coffee → src/joosy/core/widget.coffee} +0 -0
- data/src/joosy/generators/command.coffee +49 -0
- data/src/joosy/generators/generator.coffee +93 -0
- data/src/joosy/generators/layout.coffee +20 -0
- data/src/joosy/generators/page.coffee +20 -0
- data/src/joosy/generators/project/base.coffee +28 -0
- data/src/joosy/generators/project/standalone.coffee +25 -0
- data/src/joosy/generators/project.coffee +16 -0
- data/src/joosy/generators/widget.coffee +20 -0
- data/{app/assets/javascripts/joosy/preloaders/caching.js.coffee → src/joosy/preloaders/caching.coffee} +0 -0
- data/{app/assets/javascripts/joosy/preloaders/inline.js.coffee → src/joosy/preloaders/inline.coffee} +0 -0
- data/src/joosy.coffee +2 -0
- data/src/vendor/metamorph.coffee +410 -0
- data/tasks/joosy.coffee +63 -0
- data/templates/application/base/application.coffee +11 -0
- data/{lib/rails/generators/joosy/templates/app/helpers/application.js.coffee → templates/application/base/helpers/application.coffee} +0 -0
- data/{lib/rails/generators/joosy/templates/app/layouts/application.js.coffee → templates/application/base/layouts/application.coffee} +0 -0
- data/{lib/rails/generators/joosy/templates/app/pages/application.js.coffee → templates/application/base/pages/application.coffee} +0 -0
- data/{lib/rails/generators/joosy/templates/app/pages/welcome/index.js.coffee → templates/application/base/pages/welcome/index.coffee} +3 -3
- data/templates/application/base/routes.coffee +3 -0
- data/{lib/rails/generators/joosy/templates/app → templates/application/base}/templates/layouts/application.jst.hamlc +0 -0
- data/{lib/rails/generators/joosy/templates/app → templates/application/base}/templates/pages/welcome/index.jst.hamlc +1 -2
- data/templates/application/standalone/.gitignore +5 -0
- data/templates/application/standalone/Gruntfile.coffee +40 -0
- data/templates/application/standalone/Procfile +1 -0
- data/templates/application/standalone/bower.json +7 -0
- data/templates/application/standalone/package.json +24 -0
- data/templates/application/standalone/source/index.haml +7 -0
- data/templates/application/standalone/stylesheets/application.styl +2 -0
- data/templates/layout/basic.coffee +2 -0
- data/templates/layout/namespaced.coffee +4 -0
- data/templates/page/basic.coffee +3 -0
- data/templates/page/namespaced.coffee +5 -0
- data/templates/widget/basic.coffee +2 -0
- data/templates/widget/namespaced.coffee +4 -0
- metadata +98 -179
- data/.codoopts +0 -5
- data/Gemfile.lock +0 -157
- data/Guardfile +0 -32
- data/LICENSE +0 -22
- data/MIT-LICENSE +0 -21
- data/Rakefile +0 -14
- data/app/assets/javascripts/joosy.js.coffee +0 -5
- data/app/helpers/joosy/sprockets_helper.rb +0 -41
- data/app/views/layouts/json_wrapper.json.erb +0 -1
- data/lib/joosy/rails/engine.rb +0 -24
- data/lib/joosy/version.rb +0 -3
- data/lib/rails/generators/joosy/application_generator.rb +0 -43
- data/lib/rails/generators/joosy/joosy_base.rb +0 -30
- data/lib/rails/generators/joosy/layout_generator.rb +0 -30
- data/lib/rails/generators/joosy/page_generator.rb +0 -42
- data/lib/rails/generators/joosy/preloader_generator.rb +0 -30
- data/lib/rails/generators/joosy/resource_generator.rb +0 -40
- data/lib/rails/generators/joosy/templates/app/layouts/template.js.coffee +0 -2
- data/lib/rails/generators/joosy/templates/app/pages/template.js.coffee +0 -5
- data/lib/rails/generators/joosy/templates/app/resources/template.js.coffee +0 -2
- data/lib/rails/generators/joosy/templates/app/resources/template_with_namespace.js.coffee +0 -4
- data/lib/rails/generators/joosy/templates/app/routes.js.coffee +0 -8
- data/lib/rails/generators/joosy/templates/app/widgets/template.js.coffee +0 -2
- data/lib/rails/generators/joosy/templates/app.js.coffee +0 -11
- data/lib/rails/generators/joosy/templates/app_controller.rb +0 -9
- data/lib/rails/generators/joosy/templates/app_preloader.js.coffee.erb +0 -13
- data/lib/rails/generators/joosy/templates/app_railties.js.coffee.erb +0 -11
- data/lib/rails/generators/joosy/templates/preload.html.erb +0 -26
- data/lib/rails/generators/joosy/templates/preload.html.haml +0 -19
- data/lib/rails/generators/joosy/templates/preload.html.slim +0 -19
- data/lib/rails/generators/joosy/widget_generator.rb +0 -30
- data/lib/rails/resources_with_joosy.rb +0 -11
- data/spec/javascripts/support/assets/coolface.jpg +0 -0
- data/spec/javascripts/support/assets/okay.jpg +0 -0
- data/spec/javascripts/support/assets/test.js +0 -1
- data/spec/javascripts/support/jasmine.yml +0 -74
- data/spec/javascripts/support/jasmine_config.rb +0 -23
- data/spec/javascripts/support/jasmine_runner.rb +0 -32
- data/spec/javascripts/support/sinon-1.3.1.js +0 -3469
- data/spec/javascripts/support/sinon-ie-1.3.1.js.skip +0 -82
- data/vendor/assets/javascripts/jquery.form.js +0 -1190
- data/vendor/assets/javascripts/jquery.hashchange.js +0 -390
- data/vendor/assets/javascripts/metamorph.js +0 -409
- data/vendor/assets/javascripts/sugar.js +0 -8637
@@ -0,0 +1,410 @@
|
|
1
|
+
# ==========================================================================
|
2
|
+
# Project: metamorph
|
3
|
+
# Copyright: ©2013 Tilde, Inc. All rights reserved.
|
4
|
+
# ==========================================================================
|
5
|
+
((window) ->
|
6
|
+
K = ->
|
7
|
+
|
8
|
+
guid = 0
|
9
|
+
document = window.document
|
10
|
+
|
11
|
+
# Feature-detect the W3C range API, the extended check is for IE9 which only partially supports ranges
|
12
|
+
supportsRange = document and ("createRange" of document) and (typeof Range isnt "undefined") and Range::createContextualFragment
|
13
|
+
|
14
|
+
# Internet Explorer prior to 9 does not allow setting innerHTML if the first element
|
15
|
+
# is a "zero-scope" element. This problem can be worked around by making
|
16
|
+
# the first node an invisible text node. We, like Modernizr, use ­
|
17
|
+
needsShy = document and (->
|
18
|
+
testEl = document.createElement("div")
|
19
|
+
testEl.innerHTML = "<div></div>"
|
20
|
+
testEl.firstChild.innerHTML = "<script></script>"
|
21
|
+
testEl.firstChild.innerHTML is ""
|
22
|
+
)()
|
23
|
+
|
24
|
+
# IE 8 (and likely earlier) likes to move whitespace preceeding
|
25
|
+
# a script tag to appear after it. This means that we can
|
26
|
+
# accidentally remove whitespace when updating a morph.
|
27
|
+
movesWhitespace = document and (->
|
28
|
+
testEl = document.createElement("div")
|
29
|
+
testEl.innerHTML = "Test: <script type='text/x-placeholder'></script>Value"
|
30
|
+
testEl.childNodes[0].nodeValue is "Test:" and testEl.childNodes[2].nodeValue is " Value"
|
31
|
+
)()
|
32
|
+
|
33
|
+
# Constructor that supports either Metamorph('foo') or new
|
34
|
+
# Metamorph('foo');
|
35
|
+
#
|
36
|
+
# Takes a string of HTML as the argument.
|
37
|
+
Metamorph = (html) ->
|
38
|
+
self = undefined
|
39
|
+
if this instanceof Metamorph
|
40
|
+
self = this
|
41
|
+
else
|
42
|
+
self = new K()
|
43
|
+
self.innerHTML = html
|
44
|
+
myGuid = "metamorph-" + (guid++)
|
45
|
+
self.start = myGuid + "-start"
|
46
|
+
self.end = myGuid + "-end"
|
47
|
+
self
|
48
|
+
|
49
|
+
K:: = Metamorph::
|
50
|
+
rangeFor = undefined
|
51
|
+
htmlFunc = undefined
|
52
|
+
removeFunc = undefined
|
53
|
+
outerHTMLFunc = undefined
|
54
|
+
appendToFunc = undefined
|
55
|
+
afterFunc = undefined
|
56
|
+
prependFunc = undefined
|
57
|
+
startTagFunc = undefined
|
58
|
+
endTagFunc = undefined
|
59
|
+
outerHTMLFunc = ->
|
60
|
+
@startTag() + @innerHTML + @endTag()
|
61
|
+
|
62
|
+
startTagFunc = ->
|
63
|
+
|
64
|
+
#
|
65
|
+
# * We replace chevron by its hex code in order to prevent escaping problems.
|
66
|
+
# * Check this thread for more explaination:
|
67
|
+
# * http://stackoverflow.com/questions/8231048/why-use-x3c-instead-of-when-generating-html-from-javascript
|
68
|
+
#
|
69
|
+
"<script id='" + @start + "' type='text/x-placeholder'></script>"
|
70
|
+
|
71
|
+
endTagFunc = ->
|
72
|
+
|
73
|
+
#
|
74
|
+
# * We replace chevron by its hex code in order to prevent escaping problems.
|
75
|
+
# * Check this thread for more explaination:
|
76
|
+
# * http://stackoverflow.com/questions/8231048/why-use-x3c-instead-of-when-generating-html-from-javascript
|
77
|
+
#
|
78
|
+
"<script id='" + @end + "' type='text/x-placeholder'></script>"
|
79
|
+
|
80
|
+
|
81
|
+
# If we have the W3C range API, this process is relatively straight forward.
|
82
|
+
if supportsRange
|
83
|
+
|
84
|
+
# Get a range for the current morph. Optionally include the starting and
|
85
|
+
# ending placeholders.
|
86
|
+
rangeFor = (morph, outerToo) ->
|
87
|
+
range = document.createRange()
|
88
|
+
before = document.getElementById(morph.start)
|
89
|
+
after = document.getElementById(morph.end)
|
90
|
+
if outerToo
|
91
|
+
range.setStartBefore before
|
92
|
+
range.setEndAfter after
|
93
|
+
else
|
94
|
+
range.setStartAfter before
|
95
|
+
range.setEndBefore after
|
96
|
+
range
|
97
|
+
|
98
|
+
htmlFunc = (html, outerToo) ->
|
99
|
+
|
100
|
+
# get a range for the current metamorph object
|
101
|
+
range = rangeFor(this, outerToo)
|
102
|
+
|
103
|
+
# delete the contents of the range, which will be the
|
104
|
+
# nodes between the starting and ending placeholder.
|
105
|
+
range.deleteContents()
|
106
|
+
|
107
|
+
# create a new document fragment for the HTML
|
108
|
+
fragment = range.createContextualFragment(html)
|
109
|
+
|
110
|
+
# insert the fragment into the range
|
111
|
+
range.insertNode fragment
|
112
|
+
|
113
|
+
removeFunc = ->
|
114
|
+
|
115
|
+
# get a range for the current metamorph object including
|
116
|
+
# the starting and ending placeholders.
|
117
|
+
range = rangeFor(this, true)
|
118
|
+
|
119
|
+
# delete the entire range.
|
120
|
+
range.deleteContents()
|
121
|
+
|
122
|
+
appendToFunc = (node) ->
|
123
|
+
range = document.createRange()
|
124
|
+
range.setStart node
|
125
|
+
range.collapse false
|
126
|
+
frag = range.createContextualFragment(@outerHTML())
|
127
|
+
node.appendChild frag
|
128
|
+
|
129
|
+
afterFunc = (html) ->
|
130
|
+
range = document.createRange()
|
131
|
+
after = document.getElementById(@end)
|
132
|
+
range.setStartAfter after
|
133
|
+
range.setEndAfter after
|
134
|
+
fragment = range.createContextualFragment(html)
|
135
|
+
range.insertNode fragment
|
136
|
+
|
137
|
+
prependFunc = (html) ->
|
138
|
+
range = document.createRange()
|
139
|
+
start = document.getElementById(@start)
|
140
|
+
range.setStartAfter start
|
141
|
+
range.setEndAfter start
|
142
|
+
fragment = range.createContextualFragment(html)
|
143
|
+
range.insertNode fragment
|
144
|
+
else
|
145
|
+
|
146
|
+
###
|
147
|
+
This code is mostly taken from jQuery, with one exception. In jQuery's case, we
|
148
|
+
have some HTML and we need to figure out how to convert it into some nodes.
|
149
|
+
|
150
|
+
In this case, jQuery needs to scan the HTML looking for an opening tag and use
|
151
|
+
that as the key for the wrap map. In our case, we know the parent node, and
|
152
|
+
can use its type as the key for the wrap map.
|
153
|
+
###
|
154
|
+
wrapMap =
|
155
|
+
select: [1, "<select multiple='multiple'>", "</select>"]
|
156
|
+
fieldset: [1, "<fieldset>", "</fieldset>"]
|
157
|
+
table: [1, "<table>", "</table>"]
|
158
|
+
tbody: [2, "<table><tbody>", "</tbody></table>"]
|
159
|
+
tr: [3, "<table><tbody><tr>", "</tr></tbody></table>"]
|
160
|
+
colgroup: [2, "<table><tbody></tbody><colgroup>", "</colgroup></table>"]
|
161
|
+
map: [1, "<map>", "</map>"]
|
162
|
+
_default: [0, "", ""]
|
163
|
+
|
164
|
+
findChildById = (element, id) ->
|
165
|
+
return element if element.getAttribute("id") is id
|
166
|
+
len = element.childNodes.length
|
167
|
+
idx = undefined
|
168
|
+
node = undefined
|
169
|
+
found = undefined
|
170
|
+
idx = 0
|
171
|
+
while idx < len
|
172
|
+
node = element.childNodes[idx]
|
173
|
+
found = node.nodeType is 1 and findChildById(node, id)
|
174
|
+
return found if found
|
175
|
+
idx++
|
176
|
+
|
177
|
+
setInnerHTML = (element, html) ->
|
178
|
+
matches = []
|
179
|
+
if movesWhitespace
|
180
|
+
|
181
|
+
# Right now we only check for script tags with ids with the
|
182
|
+
# goal of targeting morphs.
|
183
|
+
html = html.replace(/(\s+)(<script id='([^']+)')/g, (match, spaces, tag, id) ->
|
184
|
+
matches.push [id, spaces]
|
185
|
+
tag
|
186
|
+
)
|
187
|
+
element.innerHTML = html
|
188
|
+
|
189
|
+
# If we have to do any whitespace adjustments do them now
|
190
|
+
if matches.length > 0
|
191
|
+
len = matches.length
|
192
|
+
idx = undefined
|
193
|
+
idx = 0
|
194
|
+
while idx < len
|
195
|
+
script = findChildById(element, matches[idx][0])
|
196
|
+
node = document.createTextNode(matches[idx][1])
|
197
|
+
script.parentNode.insertBefore node, script
|
198
|
+
idx++
|
199
|
+
|
200
|
+
|
201
|
+
###
|
202
|
+
Given a parent node and some HTML, generate a set of nodes. Return the first
|
203
|
+
node, which will allow us to traverse the rest using nextSibling.
|
204
|
+
|
205
|
+
We need to do this because innerHTML in IE does not really parse the nodes.
|
206
|
+
###
|
207
|
+
firstNodeFor = (parentNode, html) ->
|
208
|
+
arr = wrapMap[parentNode.tagName.toLowerCase()] or wrapMap._default
|
209
|
+
depth = arr[0]
|
210
|
+
start = arr[1]
|
211
|
+
end = arr[2]
|
212
|
+
html = "­" + html if needsShy
|
213
|
+
element = document.createElement("div")
|
214
|
+
setInnerHTML element, start + html + end
|
215
|
+
i = 0
|
216
|
+
|
217
|
+
while i <= depth
|
218
|
+
element = element.firstChild
|
219
|
+
i++
|
220
|
+
|
221
|
+
# Look for ­ to remove it.
|
222
|
+
if needsShy
|
223
|
+
shyElement = element
|
224
|
+
|
225
|
+
# Sometimes we get nameless elements with the shy inside
|
226
|
+
shyElement = shyElement.firstChild while shyElement.nodeType is 1 and not shyElement.nodeName
|
227
|
+
|
228
|
+
# At this point it's the actual unicode character.
|
229
|
+
shyElement.nodeValue = shyElement.nodeValue.slice(1) if shyElement.nodeType is 3 and shyElement.nodeValue.charAt(0) is ""
|
230
|
+
element
|
231
|
+
|
232
|
+
|
233
|
+
###
|
234
|
+
In some cases, Internet Explorer can create an anonymous node in
|
235
|
+
the hierarchy with no tagName. You can create this scenario via:
|
236
|
+
|
237
|
+
div = document.createElement("div");
|
238
|
+
div.innerHTML = "<table>­<script></script><tr><td>hi</td></tr></table>";
|
239
|
+
div.firstChild.firstChild.tagName //=> ""
|
240
|
+
|
241
|
+
If our script markers are inside such a node, we need to find that
|
242
|
+
node and use *it* as the marker.
|
243
|
+
###
|
244
|
+
realNode = (start) ->
|
245
|
+
start = start.parentNode while start.parentNode.tagName is ""
|
246
|
+
start
|
247
|
+
|
248
|
+
|
249
|
+
###
|
250
|
+
When automatically adding a tbody, Internet Explorer inserts the
|
251
|
+
tbody immediately before the first <tr>. Other browsers create it
|
252
|
+
before the first node, no matter what.
|
253
|
+
|
254
|
+
This means the the following code:
|
255
|
+
|
256
|
+
div = document.createElement("div");
|
257
|
+
div.innerHTML = "<table><script id='first'></script><tr><td>hi</td></tr><script id='last'></script></table>
|
258
|
+
|
259
|
+
Generates the following DOM in IE:
|
260
|
+
|
261
|
+
+ div
|
262
|
+
+ table
|
263
|
+
- script id='first'
|
264
|
+
+ tbody
|
265
|
+
+ tr
|
266
|
+
+ td
|
267
|
+
- "hi"
|
268
|
+
- script id='last'
|
269
|
+
|
270
|
+
Which means that the two script tags, even though they were
|
271
|
+
inserted at the same point in the hierarchy in the original
|
272
|
+
HTML, now have different parents.
|
273
|
+
|
274
|
+
This code reparents the first script tag by making it the tbody's
|
275
|
+
first child.
|
276
|
+
###
|
277
|
+
fixParentage = (start, end) ->
|
278
|
+
end.parentNode.insertBefore start, end.parentNode.firstChild if start.parentNode isnt end.parentNode
|
279
|
+
|
280
|
+
htmlFunc = (html, outerToo) ->
|
281
|
+
|
282
|
+
# get the real starting node. see realNode for details.
|
283
|
+
start = realNode(document.getElementById(@start))
|
284
|
+
end = document.getElementById(@end)
|
285
|
+
parentNode = end.parentNode
|
286
|
+
node = undefined
|
287
|
+
nextSibling = undefined
|
288
|
+
last = undefined
|
289
|
+
|
290
|
+
# make sure that the start and end nodes share the same
|
291
|
+
# parent. If not, fix it.
|
292
|
+
fixParentage start, end
|
293
|
+
|
294
|
+
# remove all of the nodes after the starting placeholder and
|
295
|
+
# before the ending placeholder.
|
296
|
+
node = start.nextSibling
|
297
|
+
while node
|
298
|
+
nextSibling = node.nextSibling
|
299
|
+
last = node is end
|
300
|
+
|
301
|
+
# if this is the last node, and we want to remove it as well,
|
302
|
+
# set the `end` node to the next sibling. This is because
|
303
|
+
# for the rest of the function, we insert the new nodes
|
304
|
+
# before the end (note that insertBefore(node, null) is
|
305
|
+
# the same as appendChild(node)).
|
306
|
+
#
|
307
|
+
# if we do not want to remove it, just break.
|
308
|
+
if last
|
309
|
+
if outerToo
|
310
|
+
end = node.nextSibling
|
311
|
+
else
|
312
|
+
break
|
313
|
+
node.parentNode.removeChild node
|
314
|
+
|
315
|
+
# if this is the last node and we didn't break before
|
316
|
+
# (because we wanted to remove the outer nodes), break
|
317
|
+
# now.
|
318
|
+
break if last
|
319
|
+
node = nextSibling
|
320
|
+
|
321
|
+
# get the first node for the HTML string, even in cases like
|
322
|
+
# tables and lists where a simple innerHTML on a div would
|
323
|
+
# swallow some of the content.
|
324
|
+
node = firstNodeFor(start.parentNode, html)
|
325
|
+
|
326
|
+
# copy the nodes for the HTML between the starting and ending
|
327
|
+
# placeholder.
|
328
|
+
while node
|
329
|
+
nextSibling = node.nextSibling
|
330
|
+
parentNode.insertBefore node, end
|
331
|
+
node = nextSibling
|
332
|
+
|
333
|
+
|
334
|
+
# remove the nodes in the DOM representing this metamorph.
|
335
|
+
#
|
336
|
+
# this includes the starting and ending placeholders.
|
337
|
+
removeFunc = ->
|
338
|
+
start = realNode(document.getElementById(@start))
|
339
|
+
end = document.getElementById(@end)
|
340
|
+
@html ""
|
341
|
+
start.parentNode.removeChild start
|
342
|
+
end.parentNode.removeChild end
|
343
|
+
|
344
|
+
appendToFunc = (parentNode) ->
|
345
|
+
node = firstNodeFor(parentNode, @outerHTML())
|
346
|
+
nextSibling = undefined
|
347
|
+
while node
|
348
|
+
nextSibling = node.nextSibling
|
349
|
+
parentNode.appendChild node
|
350
|
+
node = nextSibling
|
351
|
+
|
352
|
+
afterFunc = (html) ->
|
353
|
+
|
354
|
+
# get the real starting node. see realNode for details.
|
355
|
+
end = document.getElementById(@end)
|
356
|
+
insertBefore = end.nextSibling
|
357
|
+
parentNode = end.parentNode
|
358
|
+
nextSibling = undefined
|
359
|
+
node = undefined
|
360
|
+
|
361
|
+
# get the first node for the HTML string, even in cases like
|
362
|
+
# tables and lists where a simple innerHTML on a div would
|
363
|
+
# swallow some of the content.
|
364
|
+
node = firstNodeFor(parentNode, html)
|
365
|
+
|
366
|
+
# copy the nodes for the HTML between the starting and ending
|
367
|
+
# placeholder.
|
368
|
+
while node
|
369
|
+
nextSibling = node.nextSibling
|
370
|
+
parentNode.insertBefore node, insertBefore
|
371
|
+
node = nextSibling
|
372
|
+
|
373
|
+
prependFunc = (html) ->
|
374
|
+
start = document.getElementById(@start)
|
375
|
+
parentNode = start.parentNode
|
376
|
+
nextSibling = undefined
|
377
|
+
node = undefined
|
378
|
+
node = firstNodeFor(parentNode, html)
|
379
|
+
insertBefore = start.nextSibling
|
380
|
+
while node
|
381
|
+
nextSibling = node.nextSibling
|
382
|
+
parentNode.insertBefore node, insertBefore
|
383
|
+
node = nextSibling
|
384
|
+
Metamorph::html = (html) ->
|
385
|
+
@checkRemoved()
|
386
|
+
return @innerHTML if html is `undefined`
|
387
|
+
htmlFunc.call this, html
|
388
|
+
@innerHTML = html
|
389
|
+
|
390
|
+
Metamorph::replaceWith = (html) ->
|
391
|
+
@checkRemoved()
|
392
|
+
htmlFunc.call this, html, true
|
393
|
+
|
394
|
+
Metamorph::remove = removeFunc
|
395
|
+
Metamorph::outerHTML = outerHTMLFunc
|
396
|
+
Metamorph::appendTo = appendToFunc
|
397
|
+
Metamorph::after = afterFunc
|
398
|
+
Metamorph::prepend = prependFunc
|
399
|
+
Metamorph::startTag = startTagFunc
|
400
|
+
Metamorph::endTag = endTagFunc
|
401
|
+
Metamorph::isRemoved = ->
|
402
|
+
before = document.getElementById(@start)
|
403
|
+
after = document.getElementById(@end)
|
404
|
+
not before or not after
|
405
|
+
|
406
|
+
Metamorph::checkRemoved = ->
|
407
|
+
throw new Error("Cannot perform operations on a Metamorph that is not in the DOM.") if @isRemoved()
|
408
|
+
|
409
|
+
window.Metamorph = Metamorph
|
410
|
+
) this
|
data/tasks/joosy.coffee
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
module.exports = (grunt) ->
|
2
|
+
|
3
|
+
Path = require('path')
|
4
|
+
|
5
|
+
grunt.loadNpmTasks 'grunt-mincer'
|
6
|
+
grunt.loadNpmTasks 'grunt-contrib-connect'
|
7
|
+
grunt.loadNpmTasks 'grunt-contrib-uglify'
|
8
|
+
grunt.loadNpmTasks 'grunt-contrib-stylus'
|
9
|
+
grunt.loadNpmTasks 'grunt-contrib-cssmin'
|
10
|
+
grunt.loadNpmTasks 'grunt-bower-task'
|
11
|
+
|
12
|
+
grunt.registerTask 'joosy:compile', ['joosy:compile:code', 'joosy:compile:styles', 'joosy:compile:playground']
|
13
|
+
grunt.registerTask 'joosy:compile:code', ['mince:application', 'uglify:application']
|
14
|
+
grunt.registerTask 'joosy:compile:styles', ['stylus:application', 'cssmin:application']
|
15
|
+
|
16
|
+
grunt.registerTask 'joosy:compile:playground', ->
|
17
|
+
hamlc = require 'haml-coffee'
|
18
|
+
grunt.file.write 'public/index.html', hamlc.compile(grunt.file.read 'source/index.haml')()
|
19
|
+
|
20
|
+
grunt.registerTask 'joosy:server', ->
|
21
|
+
@async()
|
22
|
+
connect = require('connect')
|
23
|
+
mincer = require('mincer')
|
24
|
+
hamlc = require('haml-coffee')
|
25
|
+
|
26
|
+
mincer.StylusEngine.registerConfigurator (stylus) ->
|
27
|
+
stylus.options.paths.push Path.join(process.cwd(), 'public')
|
28
|
+
stylus.use require('nib')()
|
29
|
+
|
30
|
+
server = connect()
|
31
|
+
assets = new mincer.Environment(process.cwd())
|
32
|
+
assets.appendPath 'source',
|
33
|
+
assets.appendPath 'stylesheets',
|
34
|
+
assets.appendPath 'components'
|
35
|
+
assets.appendPath 'vendor'
|
36
|
+
assets.appendPath 'node_modules/joosy/lib'
|
37
|
+
|
38
|
+
server.use '/assets', mincer.createServer(assets)
|
39
|
+
|
40
|
+
server.use '/', (req, res, next) ->
|
41
|
+
if req.url == '/'
|
42
|
+
res.end hamlc.compile(grunt.file.read 'source/index.haml')()
|
43
|
+
else
|
44
|
+
next()
|
45
|
+
|
46
|
+
server.use connect.static('public')
|
47
|
+
server.listen 4000
|
48
|
+
|
49
|
+
grunt.registerTask 'joosy:server:production', ->
|
50
|
+
@async()
|
51
|
+
connect = require('connect')
|
52
|
+
server = connect()
|
53
|
+
server.use require('gzippo').staticGzip('public')
|
54
|
+
server.listen process.env['PORT'] ? 4000
|
55
|
+
|
56
|
+
grunt.registerTask 'joosy:postinstall', ->
|
57
|
+
@async
|
58
|
+
|
59
|
+
if grunt.file.exists('bower.json')
|
60
|
+
grunt.task.run 'bower:install'
|
61
|
+
|
62
|
+
if process.env['NODE_ENV'] == 'production'
|
63
|
+
grunt.task.run 'joosy:compile'
|
File without changes
|
File without changes
|
File without changes
|
@@ -6,8 +6,8 @@ Joosy.namespace 'Welcome', ->
|
|
6
6
|
|
7
7
|
@afterLoad ->
|
8
8
|
@startHeartbeat()
|
9
|
-
|
10
|
-
'padding-top': "#{$(window).height() / 2 -
|
9
|
+
@$content.css
|
10
|
+
'padding-top': "#{$(window).height() / 2 - 80}px"
|
11
11
|
|
12
12
|
elements:
|
13
13
|
content: '#content'
|
@@ -19,4 +19,4 @@ Joosy.namespace 'Welcome', ->
|
|
19
19
|
|
20
20
|
startHeartbeat: ->
|
21
21
|
@heartbeat = @setInterval 1500, =>
|
22
|
-
|
22
|
+
@$joosy.animate({opacity: 0.8}, 300).animate({opacity: 1}, 300)
|
File without changes
|
@@ -1,7 +1,6 @@
|
|
1
1
|
#wrapper
|
2
2
|
#content
|
3
3
|
%h1 Welcome aboard
|
4
|
-
%h2{:style => 'margin-bottom: 30px'} You’re still riding Ruby on Rails.
|
5
4
|
.joosy{:style => 'background: #F71; border-radius: 10px; width: 250px; display: inline-block'}
|
6
5
|
%div{:style => 'color: #FFF; padding: 10px;'}
|
7
|
-
|
6
|
+
It's Joosy time!
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module.exports = (grunt) ->
|
2
|
+
|
3
|
+
grunt.loadNpmTasks 'joosy'
|
4
|
+
|
5
|
+
grunt.initConfig
|
6
|
+
bower:
|
7
|
+
install:
|
8
|
+
options:
|
9
|
+
copy: false
|
10
|
+
verbose: true
|
11
|
+
|
12
|
+
connect:
|
13
|
+
server:
|
14
|
+
options:
|
15
|
+
port: 4000
|
16
|
+
base: 'public'
|
17
|
+
|
18
|
+
mince:
|
19
|
+
application:
|
20
|
+
include: ['source', 'components', 'vendor', 'node_modules/joosy/src']
|
21
|
+
src: 'application.coffee'
|
22
|
+
dest: 'public/assets/application.js'
|
23
|
+
|
24
|
+
stylus:
|
25
|
+
application:
|
26
|
+
options:
|
27
|
+
paths: ['stylesheets', 'public']
|
28
|
+
files: 'public/assets/application.css': 'stylesheets/application.styl'
|
29
|
+
|
30
|
+
uglify:
|
31
|
+
application:
|
32
|
+
options:
|
33
|
+
sourceMap: 'public/assets/application.js.map'
|
34
|
+
files:
|
35
|
+
'public/assets/application.js': 'public/assets/application.js'
|
36
|
+
|
37
|
+
cssmin:
|
38
|
+
application:
|
39
|
+
files:
|
40
|
+
'public/assets/application.css': 'public/assets/application.css'
|
@@ -0,0 +1 @@
|
|
1
|
+
web: node_modules/.bin/grunt joosy:server:production
|
@@ -0,0 +1,24 @@
|
|
1
|
+
{
|
2
|
+
"dependencies": {
|
3
|
+
"joosy": "~<%= joosy_version %>",
|
4
|
+
"connect": "~2.7.11",
|
5
|
+
"gzippo": "~0.2.0",
|
6
|
+
"mincer": "~0.4.6",
|
7
|
+
"coffee-script": "~1.6.3",
|
8
|
+
"stylus": "~0.32.1",
|
9
|
+
"nib": "~0.9.1",
|
10
|
+
"haml-coffee": "~1.11.1",
|
11
|
+
"grunt": "~0.4.1",
|
12
|
+
"grunt-mincer": "~0.3.1",
|
13
|
+
"grunt-contrib-connect": "~0.3.0",
|
14
|
+
"grunt-contrib-uglify": "~0.2.2",
|
15
|
+
"grunt-contrib-watch": "~0.4.4",
|
16
|
+
"grunt-contrib-stylus": "~0.5.0",
|
17
|
+
"grunt-contrib-cssmin": "~0.6.1",
|
18
|
+
"grunt-bower-task": "~0.2.3",
|
19
|
+
"grunt-cli": "~0.1.9"
|
20
|
+
},
|
21
|
+
"scripts": {
|
22
|
+
"postinstall": "node_modules/.bin/grunt joosy:postinstall"
|
23
|
+
}
|
24
|
+
}
|