sproutcore 1.6.0.1-java → 1.7.1.beta-java
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +21 -0
- data/Gemfile +5 -0
- data/Rakefile +26 -13
- data/VERSION.yml +2 -2
- data/lib/Buildfile +43 -4
- data/lib/buildtasks/build.rake +10 -0
- data/lib/buildtasks/helpers/file_rule.rb +22 -0
- data/lib/buildtasks/helpers/file_rule_list.rb +137 -0
- data/lib/buildtasks/manifest.rake +133 -122
- data/lib/frameworks/sproutcore/CHANGELOG.md +69 -2
- data/lib/frameworks/sproutcore/apps/tests/english.lproj/strings.js +1 -0
- data/lib/frameworks/sproutcore/frameworks/bootstrap/system/browser.js +28 -22
- data/lib/frameworks/sproutcore/frameworks/core_foundation/controllers/array.js +9 -5
- data/lib/frameworks/sproutcore/frameworks/core_foundation/controllers/controller.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/core_foundation/controls/button.js +18 -13
- data/lib/frameworks/sproutcore/frameworks/core_foundation/ext/handlebars/bind.js +5 -3
- data/lib/frameworks/sproutcore/frameworks/core_foundation/ext/handlebars/collection.js +2 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/mixins/action_support.js +80 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/mixins/template_helpers/text_field_support.js +84 -116
- data/lib/frameworks/sproutcore/frameworks/core_foundation/panes/pane.js +8 -5
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/event.js +157 -157
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/platform.js +5 -3
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/root_responder.js +6 -6
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/sparse_array.js +10 -7
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/mixins/action_support.js +106 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/template/collection.js +18 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/template/handlebars.js +71 -1
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/attribute_bindings_test.js +38 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/class_name_bindings_test.js +47 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/layoutChildViews.js +18 -18
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/layoutStyle.js +42 -10
- data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view.js +158 -1
- data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/keyboard.js +26 -1
- data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/layout_style.js +14 -8
- data/lib/frameworks/sproutcore/frameworks/datastore/models/record.js +15 -2
- data/lib/frameworks/sproutcore/frameworks/datastore/models/record_attribute.js +108 -108
- data/lib/frameworks/sproutcore/frameworks/datastore/system/query.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/datastore/system/record_array.js +2 -4
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/record/error_methods.js +2 -2
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/single_attribute.js +26 -0
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/query/builders.js +7 -0
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/record_array/error_methods.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/datetime/frameworks/core/system/datetime.js +4 -1
- data/lib/frameworks/sproutcore/frameworks/datetime/frameworks/core/tests/system/datetime.js +6 -0
- data/lib/frameworks/sproutcore/frameworks/desktop/panes/menu.js +26 -5
- data/lib/frameworks/sproutcore/frameworks/desktop/panes/picker.js +97 -96
- data/lib/frameworks/sproutcore/frameworks/desktop/system/drag.js +4 -3
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/panes/menu/ui.js +17 -4
- data/lib/frameworks/sproutcore/frameworks/desktop/views/collection.js +7 -7
- data/lib/frameworks/sproutcore/frameworks/desktop/views/menu_item.js +7 -5
- data/lib/frameworks/sproutcore/frameworks/desktop/views/scroll.js +12 -3
- data/lib/frameworks/sproutcore/frameworks/desktop/views/web.js +23 -14
- data/lib/frameworks/sproutcore/frameworks/experimental/Buildfile +5 -1
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/menu/render_delegates/menu_scroller.js +28 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/menu/tests/menu/scroll.js +235 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/menu/views/menu/scroll.js +363 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/menu/views/menu/scroller.js +250 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/render_delegates/desktop_scroller.js +92 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/render_delegates/native_scroll.js +25 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/render_delegates/scroll.js +33 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/render_delegates/touch_scroller.js +76 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/tests/scroll/integration.js +50 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/tests/scroll/methods.js +143 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/tests/scroll/ui.js +258 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/core_scroll.js +1164 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/core_scroller.js +332 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/desktop/scroll.js +236 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/desktop/scroller.js +347 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/scroll.js +15 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/scroller.js +10 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/touch/scroll.js +804 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/touch/scroller.js +133 -0
- data/lib/frameworks/sproutcore/frameworks/foundation/resources/text_field.css +3 -3
- data/lib/frameworks/sproutcore/frameworks/foundation/validators/number.js +3 -1
- data/lib/frameworks/sproutcore/frameworks/foundation/views/text_field.js +3 -3
- data/lib/frameworks/sproutcore/frameworks/media/views/audio.js +2 -1
- data/lib/frameworks/sproutcore/frameworks/media/views/controls.js +2 -1
- data/lib/frameworks/sproutcore/frameworks/media/views/media_slider.js +2 -4
- data/lib/frameworks/sproutcore/frameworks/media/views/mini_controls.js +2 -4
- data/lib/frameworks/sproutcore/frameworks/media/views/simple_controls.js +2 -4
- data/lib/frameworks/sproutcore/frameworks/media/views/video.js +2 -2
- data/lib/frameworks/sproutcore/frameworks/routing/system/routes.js +29 -3
- data/lib/frameworks/sproutcore/frameworks/runtime/core.js +2 -2
- data/lib/frameworks/sproutcore/frameworks/runtime/debug/test_suites/array/replace.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/runtime/private/property_chain.js +2 -1
- data/lib/frameworks/sproutcore/frameworks/runtime/system/binding.js +3 -3
- data/lib/frameworks/sproutcore/frameworks/runtime/system/index_set.js +2 -2
- data/lib/frameworks/sproutcore/frameworks/runtime/system/object.js +1 -1
- data/lib/frameworks/sproutcore/themes/ace/resources/collection/normal/list_item.css +2 -2
- data/lib/frameworks/sproutcore/themes/legacy_theme/english.lproj/segmented.css +1 -1
- data/lib/gen/app/templates/apps/@target_name@/Buildfile +3 -5
- data/lib/gen/app/templates/apps/@target_name@/resources/_theme.css +18 -0
- data/lib/gen/project/templates/@filename@/Buildfile +2 -2
- data/lib/sproutcore.rb +30 -5
- data/lib/sproutcore/builders.rb +1 -0
- data/lib/sproutcore/builders/chance_file.rb +9 -16
- data/lib/sproutcore/builders/html.rb +2 -1
- data/lib/sproutcore/builders/minify.rb +4 -35
- data/lib/sproutcore/builders/module.rb +38 -1
- data/lib/sproutcore/builders/split.rb +63 -0
- data/lib/sproutcore/builders/strings.rb +7 -1
- data/lib/sproutcore/helpers.rb +1 -1
- data/lib/sproutcore/helpers/css_split.rb +190 -0
- data/lib/sproutcore/helpers/entry_sorter.rb +2 -0
- data/lib/sproutcore/helpers/minifier.rb +40 -16
- data/lib/sproutcore/helpers/static_helper.rb +35 -17
- data/lib/sproutcore/models/manifest.rb +26 -0
- data/lib/sproutcore/models/target.rb +12 -1
- data/lib/sproutcore/rack.rb +1 -0
- data/lib/sproutcore/rack/proxy.rb +244 -225
- data/lib/sproutcore/rack/restrict_ip.rb +67 -0
- data/lib/sproutcore/rack/service.rb +8 -2
- data/lib/sproutcore/tools.rb +102 -46
- data/lib/sproutcore/tools/build.rb +91 -43
- data/lib/sproutcore/tools/gen.rb +2 -3
- data/lib/sproutcore/tools/manifest.rb +22 -16
- data/lib/sproutcore/tools/server.rb +21 -0
- data/spec/buildtasks/helpers/accept_list +22 -0
- data/spec/buildtasks/helpers/accept_list.rb +128 -0
- data/spec/buildtasks/helpers/list.json +11 -0
- data/spec/buildtasks/manifest/prepare_build_tasks/chance_2x_spec.rb +1 -39
- data/spec/buildtasks/manifest/prepare_build_tasks/chance_spec.rb +0 -38
- data/spec/buildtasks/manifest/prepare_build_tasks/combine_spec.rb +4 -4
- data/spec/buildtasks/manifest/prepare_build_tasks/module_spec.rb +2 -2
- data/spec/buildtasks/manifest/prepare_build_tasks/packed_2x_indirect_spec.rb +7 -16
- data/spec/buildtasks/manifest/prepare_build_tasks/packed_2x_spec.rb +7 -17
- data/spec/buildtasks/manifest/prepare_build_tasks/packed_spec.rb +11 -6
- data/spec/fixtures/builder_tests/Buildfile +2 -1
- data/spec/fixtures/builder_tests/apps/module_test/modules/required_module/core.js +0 -0
- data/spec/lib/builders/module_spec.rb +1 -1
- data/spec/spec_helper.rb +1 -0
- data/sproutcore.gemspec +4 -9
- data/vendor/chance/lib/chance.rb +25 -6
- data/vendor/chance/lib/chance/factory.rb +45 -0
- data/vendor/chance/lib/chance/instance.rb +173 -28
- data/vendor/chance/lib/chance/instance/data_url.rb +0 -29
- data/vendor/chance/lib/chance/instance/slicing.rb +57 -4
- data/vendor/chance/lib/chance/instance/spriting.rb +112 -21
- data/vendor/chance/lib/chance/parser.rb +80 -52
- data/vendor/sproutcore/SCCompiler.jar +0 -0
- data/vendor/sproutcore/lib/args4j-2.0.12.jar +0 -0
- data/vendor/sproutcore/lib/yuicompressor-2.4.2.jar +0 -0
- metadata +84 -25
@@ -111,7 +111,13 @@ describe "manifest:prepare_build_tasks:packed" do
|
|
111
111
|
|
112
112
|
before do
|
113
113
|
run_task
|
114
|
-
|
114
|
+
|
115
|
+
# for 1x (but not 2x) there should be an intermediary entry for a transform
|
116
|
+
# (split_css) that... splits the CSS. See its documentation.
|
117
|
+
#
|
118
|
+
# we are looking for the stylesheet-packed.css that is set on its source entry.
|
119
|
+
@entry = entry_for('stylesheet-packed.css')[:source_entry]
|
120
|
+
|
115
121
|
@entry_2x = entry_for('stylesheet@2x-packed.css')
|
116
122
|
end
|
117
123
|
|
@@ -125,11 +131,6 @@ describe "manifest:prepare_build_tasks:packed" do
|
|
125
131
|
@entry.source_entries.each do |entry|
|
126
132
|
entry.filename.should == 'stylesheet.css'
|
127
133
|
end
|
128
|
-
|
129
|
-
@entry_2x.source_entries.size.should > 0
|
130
|
-
@entry_2x.source_entries.each do |entry|
|
131
|
-
entry.filename.should == 'stylesheet@2x.css'
|
132
|
-
end
|
133
134
|
end
|
134
135
|
|
135
136
|
it "should include ordered_entries ordered by required target order" do
|
@@ -145,17 +146,6 @@ describe "manifest:prepare_build_tasks:packed" do
|
|
145
146
|
@entry.ordered_entries.each do |entry|
|
146
147
|
entry.target.should == targets.shift
|
147
148
|
end
|
148
|
-
|
149
|
-
targets = @target.expand_required_targets(:theme => true) + [@target]
|
150
|
-
variation = @entry.manifest.variation
|
151
|
-
targets.reject! do |t|
|
152
|
-
t.manifest_for(variation).build!.entry_for('stylesheet@2x.css').nil?
|
153
|
-
end
|
154
|
-
|
155
|
-
@entry_2x.ordered_entries.each do |entry|
|
156
|
-
entry.target.should == targets.shift
|
157
|
-
end
|
158
|
-
|
159
149
|
end
|
160
150
|
|
161
151
|
it "should include the actual targets this packed version covers in the targets property (even those w no stylesheet.css)" do
|
@@ -40,8 +40,8 @@ describe "manifest:prepare_build_tasks:packed" do
|
|
40
40
|
@manifest.entry_for('javascript-packed.js').should_not be_nil
|
41
41
|
@manifest.entry_for('stylesheet-packed.css').should_not be_nil
|
42
42
|
|
43
|
-
#
|
44
|
-
@manifest.entry_for('stylesheet@2x-packed.css').
|
43
|
+
# there must always be a 2x-packed entry
|
44
|
+
@manifest.entry_for('stylesheet@2x-packed.css').should_not be_nil
|
45
45
|
end
|
46
46
|
|
47
47
|
it "should remove non-packed JS entries from apps" do
|
@@ -132,16 +132,21 @@ describe "manifest:prepare_build_tasks:packed" do
|
|
132
132
|
|
133
133
|
run_task
|
134
134
|
|
135
|
-
|
135
|
+
# for 1x (but not 2x) there should be an intermediary entry for a transform
|
136
|
+
# (split_css) that... splits the CSS. See its documentation.
|
137
|
+
#
|
138
|
+
# we are looking for the stylesheet-packed.css that is set on its source entry.
|
139
|
+
@entry = entry_for('stylesheet-packed.css')[:source_entry]
|
140
|
+
|
136
141
|
@entry_2x = entry_for('stylesheet@2x-packed.css')
|
137
142
|
end
|
138
143
|
|
139
144
|
it "should generate a stylesheet-packed.css entry" do
|
140
145
|
@entry.should_not be_nil
|
141
146
|
|
142
|
-
# should be
|
143
|
-
#
|
144
|
-
@entry_2x.
|
147
|
+
# There should always be a 2x packed entry, because default JS
|
148
|
+
# looks for 2x when running in 2x mode, and has no fallback.
|
149
|
+
@entry_2x.should_not be_nil
|
145
150
|
end
|
146
151
|
|
147
152
|
it "should include stylesheet.css entries from all required targets" do
|
@@ -19,4 +19,5 @@ config '/module_test/deferred_module',
|
|
19
19
|
config :module_test,
|
20
20
|
:deferred_modules => [:deferred_module],
|
21
21
|
:prefetched_modules => [:required_target],
|
22
|
-
:inlined_modules => [:inlined_module]
|
22
|
+
:inlined_modules => [:inlined_module],
|
23
|
+
:required => [:required_module]
|
File without changes
|
@@ -45,7 +45,7 @@ describe 'SC::Builder::ModuleInfo' do
|
|
45
45
|
req = @target.required_targets
|
46
46
|
|
47
47
|
req.size.should == 1
|
48
|
-
req.first.target_name.should == :'/module_test/
|
48
|
+
req.first.target_name.should == :'/module_test/required_module'
|
49
49
|
end
|
50
50
|
|
51
51
|
it "should require one deferred module" do
|
data/spec/spec_helper.rb
CHANGED
data/sproutcore.gemspec
CHANGED
@@ -3,7 +3,6 @@ require "sproutcore/version"
|
|
3
3
|
|
4
4
|
os = Gem::Platform.local.os
|
5
5
|
is_jruby = (os == "java")
|
6
|
-
is_mingw = (os == "mingw32")
|
7
6
|
|
8
7
|
Gem::Specification.new do |s|
|
9
8
|
s.name = 'sproutcore'
|
@@ -14,17 +13,17 @@ Gem::Specification.new do |s|
|
|
14
13
|
s.summary = "SproutCore is a platform for building native look-and-feel applications on the web"
|
15
14
|
|
16
15
|
s.platform = 'java' if is_jruby
|
17
|
-
s.platform = 'x86-mingw32' if is_mingw
|
18
16
|
|
19
17
|
s.add_dependency 'rack', '~> 1.2'
|
20
18
|
s.add_dependency 'json_pure', "~> 1.4.6"
|
21
19
|
s.add_dependency 'extlib', "~> 0.9.15"
|
22
20
|
s.add_dependency 'erubis', "~> 2.6"
|
23
21
|
s.add_dependency 'thor', '~> 0.14.3'
|
24
|
-
s.add_dependency '
|
25
|
-
|
26
|
-
s.add_dependency 'compass', '~> 0.11.1'
|
22
|
+
s.add_dependency 'sass', '~> 3.1.3'
|
23
|
+
s.add_dependency 'haml', '~> 3.1.2'
|
27
24
|
|
25
|
+
s.add_dependency 'compass', '~> 0.11.3'
|
26
|
+
s.add_dependency 'chunky_png', '~> 1.2.0'
|
28
27
|
s.add_dependency 'em-http-request', '~> 1.0.0.beta'
|
29
28
|
|
30
29
|
if is_jruby
|
@@ -33,10 +32,6 @@ Gem::Specification.new do |s|
|
|
33
32
|
s.add_dependency 'thin', '~> 1.2.11'
|
34
33
|
end
|
35
34
|
|
36
|
-
if is_mingw
|
37
|
-
s.add_dependency 'eventmachine', '~> 1.0.0.beta'
|
38
|
-
end
|
39
|
-
|
40
35
|
s.add_development_dependency 'gemcutter', "~> 0.6.0"
|
41
36
|
s.add_development_dependency 'rspec', "~> 2.5.0"
|
42
37
|
s.add_development_dependency 'rake'
|
data/vendor/chance/lib/chance.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require "chance/instance"
|
2
|
+
require "chance/factory"
|
2
3
|
|
3
4
|
require 'sass'
|
4
5
|
|
@@ -19,8 +20,10 @@ module Chance
|
|
19
20
|
|
20
21
|
@files = {}
|
21
22
|
|
23
|
+
@clear_files_immediately = false
|
24
|
+
|
22
25
|
class << self
|
23
|
-
attr_accessor :files, :_current_instance
|
26
|
+
attr_accessor :files, :_current_instance, :clear_files_immediately
|
24
27
|
|
25
28
|
def add_file(path, content=nil)
|
26
29
|
mtime = 0
|
@@ -29,9 +32,7 @@ module Chance
|
|
29
32
|
end
|
30
33
|
|
31
34
|
if @files[path]
|
32
|
-
|
33
|
-
update_file(path, content) if mtime > @files[path][:mtime]
|
34
|
-
return
|
35
|
+
return update_file_if_needed(path, content)
|
35
36
|
end
|
36
37
|
|
37
38
|
file = {
|
@@ -67,6 +68,21 @@ module Chance
|
|
67
68
|
puts "Updated " + path if Chance::CONFIG[:verbose]
|
68
69
|
end
|
69
70
|
|
71
|
+
# if the path is a valid filesystem path and the mtime has changed, this invalidates
|
72
|
+
# the file. Returns the mtime if the file was updated.
|
73
|
+
def update_file_if_needed(path, content=nil)
|
74
|
+
if @files[path]
|
75
|
+
mtime = File.mtime(path).to_f
|
76
|
+
if mtime > @files[path][:mtime]
|
77
|
+
update_file(path, content)
|
78
|
+
end
|
79
|
+
|
80
|
+
return mtime
|
81
|
+
else
|
82
|
+
return false
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
70
86
|
def remove_file(path)
|
71
87
|
if not @files.has_key? path
|
72
88
|
puts "Could not remove " + path + " because it is not in system."
|
@@ -144,10 +160,13 @@ module Chance
|
|
144
160
|
content = file[:content]
|
145
161
|
|
146
162
|
requires = []
|
147
|
-
content = content.gsub(/
|
148
|
-
requires.push $
|
163
|
+
content = content.gsub(/(sc_)?require\(['"]?(.*?)['"]?\);?/) {|match|
|
164
|
+
requires.push $2
|
149
165
|
""
|
150
166
|
}
|
167
|
+
|
168
|
+
# sc_resource will already be handled by the build tool. We just need to ignore it.
|
169
|
+
content.gsub!(/sc_resource\(['"]?(.*?)['"]?\);?/, '')
|
151
170
|
|
152
171
|
file[:requires] = requires
|
153
172
|
file[:content] = content
|
@@ -0,0 +1,45 @@
|
|
1
|
+
#
|
2
|
+
# The Chance factory.
|
3
|
+
# All methods require two parts: a key and a hash of options. The hash will be used in
|
4
|
+
# the case of a cache missed.
|
5
|
+
#
|
6
|
+
module Chance
|
7
|
+
module ChanceFactory
|
8
|
+
|
9
|
+
@instances = {}
|
10
|
+
@file_hashes = {}
|
11
|
+
class << self
|
12
|
+
def clear_instances
|
13
|
+
@file_hashes = {}
|
14
|
+
@instances = {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def instance_for_key(key, opts)
|
18
|
+
if not @instances.include? key
|
19
|
+
@instances[key] = Chance::Instance.new(opts)
|
20
|
+
end
|
21
|
+
|
22
|
+
return @instances[key]
|
23
|
+
end
|
24
|
+
|
25
|
+
# Call with a hash mapping instance paths to absolute paths. This will compare with
|
26
|
+
# the last
|
27
|
+
def update_instance(key, opts, files)
|
28
|
+
instance = instance_for_key(key, opts)
|
29
|
+
last_hash = @file_hashes[key] || {}
|
30
|
+
|
31
|
+
# If they are not equal, we might as well throw everything. The biggest cost is from
|
32
|
+
# Chance re-running, and it will have to anyway.
|
33
|
+
if not last_hash.eql? files
|
34
|
+
instance.unmap_all
|
35
|
+
files.each {|path, identifier|
|
36
|
+
instance.map_file path, identifier
|
37
|
+
}
|
38
|
+
|
39
|
+
@file_hashes[key] = files
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -10,6 +10,8 @@ require 'chance/instance/spriting'
|
|
10
10
|
require 'chance/instance/data_url'
|
11
11
|
require 'chance/instance/javascript'
|
12
12
|
|
13
|
+
require 'digest/md5'
|
14
|
+
|
13
15
|
|
14
16
|
Compass.discover_extensions!
|
15
17
|
Compass.configure_sass_plugin!
|
@@ -21,7 +23,9 @@ module Chance
|
|
21
23
|
attr_reader :path
|
22
24
|
def initialize(path)
|
23
25
|
@path = path
|
26
|
+
super(message)
|
24
27
|
end
|
28
|
+
|
25
29
|
def message
|
26
30
|
"File not mapped in Chance instance: #{path}"
|
27
31
|
end
|
@@ -48,18 +52,25 @@ module Chance
|
|
48
52
|
"chance@2x.css" => { :method => :css, :x2 => true },
|
49
53
|
"chance-sprited.css" => { :method => :css, :sprited => true },
|
50
54
|
"chance-sprited@2x.css" => { :method => :css, :sprited => true, :x2 => true },
|
51
|
-
"chance.js" => { :method => :javascript },
|
52
|
-
"chance-mhtml.txt" => { :method => :mhtml },
|
53
55
|
|
54
56
|
# For Testing Purposes...
|
55
57
|
"chance-test.css" => { :method => :chance_test }
|
56
58
|
}
|
57
59
|
|
60
|
+
@@uid = 0
|
61
|
+
|
58
62
|
@@generation = 0
|
59
63
|
|
60
64
|
def initialize(options = {})
|
61
65
|
@options = options
|
62
66
|
@options[:theme] = "" if @options[:theme].nil?
|
67
|
+
@options[:pad_sprites_for_debugging] = true if @options[:pad_sprites_for_debugging].nil?
|
68
|
+
@options[:optimize_sprites] = true if @options[:optimize_sprites].nil?
|
69
|
+
|
70
|
+
@@uid += 1
|
71
|
+
@uid = @@uid
|
72
|
+
|
73
|
+
@options[:instance_id] = @uid if @options[:instance_id].nil?
|
63
74
|
|
64
75
|
if @options[:theme].length > 0 and @options[:theme][0] != "."
|
65
76
|
@options[:theme] = "." + @options[:theme].to_s
|
@@ -68,6 +79,10 @@ module Chance
|
|
68
79
|
# The mapped files are a map from file names in the Chance Instance to
|
69
80
|
# their identifiers in Chance itself.
|
70
81
|
@mapped_files = { }
|
82
|
+
|
83
|
+
# The file mtimes are a collection of mtimes for all the files we have. Each time we
|
84
|
+
# read a file we record the mtime, and then we compare on check_all_files
|
85
|
+
@file_mtimes = { }
|
71
86
|
|
72
87
|
# The @files set is a set cached generated output files, used by the output_for
|
73
88
|
# method.
|
@@ -80,6 +95,10 @@ module Chance
|
|
80
95
|
|
81
96
|
# Tracks whether _render has been called.
|
82
97
|
@has_rendered = false
|
98
|
+
|
99
|
+
# A generation number for the current render. This allows the slicing and spriting
|
100
|
+
# to be invalidated smartly.
|
101
|
+
@render_cycle = 0
|
83
102
|
end
|
84
103
|
|
85
104
|
# maps a path relative to the instance to a file identifier
|
@@ -90,6 +109,11 @@ module Chance
|
|
90
109
|
# The identifier would be a name of a file that you added to
|
91
110
|
# Chance using add_file.
|
92
111
|
def map_file(path, identifier)
|
112
|
+
if @mapped_files[path] == identifier
|
113
|
+
# Don't do anything if there is nothing to do.
|
114
|
+
return
|
115
|
+
end
|
116
|
+
|
93
117
|
path = path.to_s
|
94
118
|
file = Chance.has_file(identifier)
|
95
119
|
|
@@ -104,12 +128,35 @@ module Chance
|
|
104
128
|
# unmaps a path from its identifier. In short, removes a file
|
105
129
|
# from this Chance instance. The file will remain in Chance's "virtual filesystem".
|
106
130
|
def unmap_file(path)
|
131
|
+
if not @mapped_files.include?(path)
|
132
|
+
# Don't do anything if there is nothing to do
|
133
|
+
return
|
134
|
+
end
|
135
|
+
|
107
136
|
path = path.to_s
|
108
137
|
@mapped_files.delete path
|
109
138
|
|
110
139
|
# Invalidate our render because things have changed.
|
111
140
|
clean
|
112
141
|
end
|
142
|
+
|
143
|
+
# unmaps all files
|
144
|
+
def unmap_all
|
145
|
+
@mapped_files = {}
|
146
|
+
end
|
147
|
+
|
148
|
+
# checks all files to see if they have changed
|
149
|
+
def check_all_files
|
150
|
+
needs_clean = false
|
151
|
+
@mapped_files.each {|p, f|
|
152
|
+
mtime = Chance.update_file_if_needed(f)
|
153
|
+
if @file_mtimes[p].nil? or mtime > @file_mtimes[p]
|
154
|
+
needs_clean = true
|
155
|
+
end
|
156
|
+
}
|
157
|
+
|
158
|
+
clean if needs_clean
|
159
|
+
end
|
113
160
|
|
114
161
|
# Using a path relative to this instance, gets an actual Chance file
|
115
162
|
# hash, with any necessary preprocessing already performed. For instance,
|
@@ -178,6 +225,9 @@ module Chance
|
|
178
225
|
def _render
|
179
226
|
return if @has_rendered
|
180
227
|
|
228
|
+
# Update the render cycle to invalidate sprites, slices, etc.
|
229
|
+
@render_cycle = @render_cycle + 1
|
230
|
+
|
181
231
|
@files = {}
|
182
232
|
begin
|
183
233
|
# SCSS code executing needs to know what the current instance of Chance is,
|
@@ -188,13 +238,25 @@ module Chance
|
|
188
238
|
# The output of this process is a "virtual" file that imports all of the
|
189
239
|
# SCSS files used by this Chance instance. This also sets up the @slices hash.
|
190
240
|
import_css = _preprocess
|
241
|
+
|
242
|
+
# Because we encapsulate with instance_id, we should not have collisions even IF another chance
|
243
|
+
# instance were running at the same time (which it couldn't; if it were, there'd be MANY other issues)
|
244
|
+
image_css_path = File.join('./tmp/chance/image_css', @options[:instance_id].to_s, '_image_css.scss')
|
245
|
+
FileUtils.mkdir_p(File.dirname(image_css_path))
|
246
|
+
|
247
|
+
file = File.new(image_css_path, "w")
|
248
|
+
file.write(_css_for_slices)
|
249
|
+
file.close
|
250
|
+
|
251
|
+
image_css_path = File.join('./tmp/chance/image_css', @options[:instance_id].to_s, 'image_css')
|
252
|
+
|
191
253
|
|
192
254
|
# STEP 2: Preparing input CSS
|
193
255
|
# The main CSS file we pass to the Sass Engine will have placeholder CSS for the
|
194
256
|
# slices (the details will be postprocessed out).
|
195
257
|
# After that, all of the individual files (using the import CSS generated
|
196
258
|
# in Step 1)
|
197
|
-
css =
|
259
|
+
css = "@import \"#{image_css_path}\";\n" + import_css
|
198
260
|
|
199
261
|
# Step 3: Apply Sass Engine
|
200
262
|
engine = Sass::Engine.new(css, Compass.sass_engine_options.merge({
|
@@ -218,17 +280,24 @@ module Chance
|
|
218
280
|
# slicing operation has not yet taken place. The postprocessing portion
|
219
281
|
# receives sliced versions.
|
220
282
|
def _css_for_slices
|
221
|
-
|
283
|
+
|
284
|
+
output = []
|
222
285
|
slices = @slices
|
223
286
|
|
224
287
|
slices.each do |name, slice|
|
225
|
-
#
|
226
|
-
output
|
227
|
-
|
228
|
-
|
288
|
+
# Write out comments specifying all the files the slice is used from
|
289
|
+
output << "/* Slice #{name}, used in: \n"
|
290
|
+
slice[:used_by].each {|used_by|
|
291
|
+
output << "\t#{used_by[:path]}\n"
|
292
|
+
}
|
293
|
+
output << "*/"
|
294
|
+
|
295
|
+
output << "." + slice[:css_name] + " { "
|
296
|
+
output << "_sc_chance: \"#{name}\";"
|
297
|
+
output << "} \n"
|
229
298
|
end
|
230
299
|
|
231
|
-
return output
|
300
|
+
return output.join ""
|
232
301
|
|
233
302
|
end
|
234
303
|
|
@@ -241,16 +310,63 @@ module Chance
|
|
241
310
|
# :sprited => whether to use spriting instead of data uris.
|
242
311
|
def _postprocess_css(opts)
|
243
312
|
if opts[:sprited]
|
244
|
-
postprocess_css_sprited(opts)
|
313
|
+
ret = postprocess_css_sprited(opts)
|
245
314
|
else
|
246
|
-
postprocess_css_dataurl(opts)
|
315
|
+
ret = postprocess_css_dataurl(opts)
|
247
316
|
end
|
317
|
+
|
318
|
+
ret = _strip_slice_class_names(ret)
|
319
|
+
end
|
320
|
+
|
321
|
+
#
|
322
|
+
# Strips dummy slice class names that were added by Chance so that SCSS could do its magic,
|
323
|
+
# but which are no longer needed.
|
324
|
+
#
|
325
|
+
def _strip_slice_class_names(css)
|
326
|
+
css.gsub! /\.__chance_slice[^{]*?,/, ""
|
327
|
+
css
|
248
328
|
end
|
249
329
|
|
250
330
|
|
251
331
|
#
|
252
332
|
# COMBINING CSS
|
253
333
|
#
|
334
|
+
|
335
|
+
# Determines the "Chance Header" to add at the beginning of the file. The
|
336
|
+
# Chance Header can set, for instance, the $theme variable.
|
337
|
+
#
|
338
|
+
# The Chance Header is loaded from the nearest _theme.css file in this folder
|
339
|
+
# or a containing folder (the file list specifically ignores such files; they are
|
340
|
+
# only used for this purpose)
|
341
|
+
#
|
342
|
+
# For backwards-compatibility, the fallback if no _theme.css file is present
|
343
|
+
# is to return code setting $theme to the now-deprecated @options[:theme]
|
344
|
+
# passed to Chance
|
345
|
+
def chance_header_for_file(file)
|
346
|
+
# 'file' is the name of a file, so we actually need to start at dirname(file)
|
347
|
+
dir = File.dirname(file)
|
348
|
+
|
349
|
+
# This should not be slow, as this is just a hash lookup
|
350
|
+
while dir.length > 0 and not dir == "."
|
351
|
+
header_file = @mapped_files[File.join(dir, "_theme.css")]
|
352
|
+
if not header_file.nil?
|
353
|
+
return Chance.get_file(header_file)
|
354
|
+
end
|
355
|
+
|
356
|
+
dir = File.dirname(dir)
|
357
|
+
end
|
358
|
+
|
359
|
+
# Make sure to look globally
|
360
|
+
header_file = @mapped_files["_theme.css"]
|
361
|
+
return Chance.get_file(header_file) if not header_file.nil?
|
362
|
+
|
363
|
+
{
|
364
|
+
# Never changes (without a restart, at least)
|
365
|
+
:mtime => 0,
|
366
|
+
:content => "$theme: '" + @options[:theme] + "';\n"
|
367
|
+
}
|
368
|
+
end
|
369
|
+
|
254
370
|
#
|
255
371
|
# _include_file is the recursive method in the depth-first-search
|
256
372
|
# that creates the ordered list of files.
|
@@ -262,6 +378,9 @@ module Chance
|
|
262
378
|
#
|
263
379
|
def _include_file(file)
|
264
380
|
return if not file =~ /\.css$/
|
381
|
+
|
382
|
+
# skip _theme.css files
|
383
|
+
return if file =~ /_theme\.css$/
|
265
384
|
|
266
385
|
file = Chance.get_file(file)
|
267
386
|
|
@@ -271,7 +390,13 @@ module Chance
|
|
271
390
|
requires = file[:requires]
|
272
391
|
file[:included] = @@generation
|
273
392
|
|
274
|
-
|
393
|
+
if not requires.nil?
|
394
|
+
requires.each {|r|
|
395
|
+
# Add the .css extension if needed. it is optional for sc_require
|
396
|
+
r = r + ".css" if not r =~ /\.css$/
|
397
|
+
_include_file(@mapped_files[r])
|
398
|
+
}
|
399
|
+
end
|
275
400
|
|
276
401
|
|
277
402
|
|
@@ -289,35 +414,55 @@ module Chance
|
|
289
414
|
@@generation = @@generation + 1
|
290
415
|
files = @mapped_files.values
|
291
416
|
@file_list = []
|
292
|
-
|
293
|
-
|
417
|
+
|
418
|
+
# We have to sort alphabetically first...
|
419
|
+
tmp_file_list = []
|
420
|
+
@mapped_files.each {|p, f| tmp_file_list.push([p, f]) }
|
421
|
+
tmp_file_list.sort_by! {|a| a[0] }
|
422
|
+
|
423
|
+
tmp_file_list.each {|paths|
|
424
|
+
p, f = paths
|
425
|
+
|
426
|
+
# Save the mtime for caching
|
427
|
+
mtime = Chance.update_file_if_needed(f)
|
428
|
+
@file_mtimes[p] = mtime
|
429
|
+
|
430
|
+
_include_file(f)
|
431
|
+
}
|
294
432
|
|
295
433
|
relative_paths = @mapped_files.invert
|
296
434
|
|
297
435
|
@file_list.map {|file|
|
298
|
-
#
|
299
|
-
#
|
300
|
-
#
|
301
|
-
|
436
|
+
# NOTE: WE MUST CALL CHANCE PARSER NOW, because it generates our slicses.
|
437
|
+
# We can't be picky and just call it if something has changed. Thankfully,
|
438
|
+
# parser is fast. Unlike SCSS.
|
439
|
+
header_file = chance_header_for_file(relative_paths[file[:path]])
|
440
|
+
|
302
441
|
content = "@_chance_file " + relative_paths[file[:path]] + ";\n"
|
303
|
-
content +=
|
442
|
+
content += header_file[:content]
|
304
443
|
content += file[:content]
|
305
444
|
|
306
445
|
parser = Chance::Parser.new(content, @options)
|
307
446
|
parser.parse
|
308
447
|
file[:parsed_css] = parser.css
|
448
|
+
|
449
|
+
# We used to use an md5 hash here, but this hides the original file name
|
450
|
+
# from SCSS, which makes the file name + line number comments useless.
|
451
|
+
#
|
452
|
+
# Instead, we sanitize the path.
|
453
|
+
path_safe = file[:path].gsub(/[^a-zA-Z0-9\-_\\\/]/, '-')
|
309
454
|
|
310
|
-
|
311
|
-
# i.e. colons in drive names on Windows
|
312
|
-
# Also removing leading slashes
|
313
|
-
cleaned_path = file[:path].gsub(/[^\w\/_-]+/,'_').sub(/^\//,'')
|
314
|
-
tmp_path = "./tmp/chance/#{cleaned_path}.scss"
|
455
|
+
tmp_path = "./tmp/chance/#{path_safe}.scss"
|
315
456
|
|
316
457
|
FileUtils.mkdir_p(File.dirname(tmp_path))
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
458
|
+
|
459
|
+
if (not file[:mtime] or not file[:wtime] or file[:wtime] < file[:mtime] or
|
460
|
+
not header_file[:mtime] or file[:wtime] < header_file[:mtime])
|
461
|
+
f = File.new(tmp_path, "w")
|
462
|
+
f.write(parser.css)
|
463
|
+
f.close
|
464
|
+
file[:wtime] = Time.now.to_f
|
465
|
+
end
|
321
466
|
|
322
467
|
css = "@import \"" + tmp_path + "\";"
|
323
468
|
|