guilded 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/History.txt +111 -0
- data/README.rdoc +219 -0
- data/Rakefile +56 -0
- data/VERSION +1 -0
- data/guilded.gemspec +90 -0
- data/lib/guilded.rb +79 -0
- data/lib/guilded/browser_detector.rb +217 -0
- data/lib/guilded/component_def.rb +24 -0
- data/lib/guilded/exceptions.rb +29 -0
- data/lib/guilded/guilder.rb +357 -0
- data/lib/guilded/rails.rb +4 -0
- data/lib/guilded/rails/active_record/human_attribute_hint.rb +41 -0
- data/lib/guilded/rails/active_record/human_attribute_override.rb +41 -0
- data/lib/guilded/rails/helpers.rb +123 -0
- data/lib/guilded/rails/inactive_record/human_attribute_hint.rb +26 -0
- data/lib/guilded/rails/view_helpers.rb +147 -0
- data/rails_generators/guilded_assets/guilded_assets_generator.rb +23 -0
- data/rails_generators/guilded_assets/templates/guilded.js +12 -0
- data/rails_generators/guilded_assets/templates/guilded.min.js +1 -0
- data/rails_generators/guilded_assets/templates/jquery-1.2.6.js +3549 -0
- data/rails_generators/guilded_assets/templates/jquery-1.2.6.min.js +32 -0
- data/rails_generators/guilded_assets/templates/jquery-1.3.2.js +4376 -0
- data/rails_generators/guilded_assets/templates/jquery-1.3.2.min.js +19 -0
- data/rails_generators/guilded_assets/templates/jquery-url.js +199 -0
- data/rails_generators/guilded_assets/templates/jquery-url.min.js +9 -0
- data/rails_generators/guilded_assets/templates/mootools-1.2.3.js +4036 -0
- data/rails_generators/guilded_assets/templates/mootools-1.2.3.min.js +356 -0
- data/rails_generators/guilded_assets/templates/reset-min.css +7 -0
- data/rails_generators/guilded_config/guilded_config_generator.rb +11 -0
- data/rails_generators/guilded_config/templates/load_guilded_settings.rb +13 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/tasks/rails.rake +8 -0
- data/tasks/rspec.rake +21 -0
- data/test/guilded/browser_detector_test.rb +1248 -0
- data/test/guilded/component_def_test.rb +26 -0
- data/test/guilded/guilder_test.rb +79 -0
- data/test/guilded/rails/helpers_test.rb +1450 -0
- data/test/guilded/rails/view_helpers_test.rb +97 -0
- data/test/guilded_test.rb +7 -0
- data/test/test_helper.rb +47 -0
- metadata +112 -0
data/lib/guilded.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
2
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
3
|
+
|
4
|
+
require 'guilded/browser_detector'
|
5
|
+
require 'guilded/component_def'
|
6
|
+
require 'guilded/guilder'
|
7
|
+
require 'guilded/exceptions'
|
8
|
+
require 'guilded/rails/helpers'
|
9
|
+
require 'guilded/rails/view_helpers'
|
10
|
+
require 'guilded/rails/active_record/human_attribute_hint'
|
11
|
+
require 'guilded/rails/active_record/human_attribute_override'
|
12
|
+
require 'guilded/rails/inactive_record/human_attribute_hint'
|
13
|
+
|
14
|
+
# Guilded is a framework for creating reusable UI components for web applications. Guilded provides the facilities to
|
15
|
+
# easily add components and all of their required assets to a page.
|
16
|
+
#
|
17
|
+
# A Guilded component is a set of XHTML, CSS and JavaScript that combine to create a rich UI. The Guilded component should be
|
18
|
+
# authored using progressive enhancement to enable users without CSS or JavaScript enabled to utilize the essential functionality
|
19
|
+
# of the component. The easiest way to accomplish this requirement is to write your behavior code as a jQuery plugin. Doing
|
20
|
+
# so will naturally guide your behavior code to be applied through progrssive enhancement and also allow your behavior code
|
21
|
+
# to be used without Guilded.
|
22
|
+
#
|
23
|
+
# To create a Guilded component at least four things must occur: writing a view helper, writing a JavaScript initialization
|
24
|
+
# function, writing a default stylesheet and writing either a rake task or generator to place these assets into a project's
|
25
|
+
# public directory. It is also probable that a jQuery plugin with the behavior code will need to be authored. If this is the
|
26
|
+
# case, then the JavaScript initialization function will most likely just call the jQuery plugin on the DOM element(s) that should
|
27
|
+
# have the behavior applied.
|
28
|
+
#
|
29
|
+
# The view helper should output the HTML necessary for the component. It must also add the component to a collection so that
|
30
|
+
# Guilded can collect its assets and add them to the page. This is accomplished through a call to the Guilder.add() method.
|
31
|
+
# The Guilder is a singleton, so you must access it like: Guilded::Guilder.instance.add( ... ). The Guilder.add() method adds
|
32
|
+
# element to a collection with it's options. Guilded automatically looks for CSS assets that obey the naming convention
|
33
|
+
# {component_name}/default.css. Guilded also automatically looks for a JavaScript asset named: guilded.{component_name}.js.
|
34
|
+
# This asset should at least include the initComponentName( options ). The Guilded.add() method can also add additional CSS and
|
35
|
+
# JavaScript assets necessary for a component. An example of an additional JavaScript asset is the jQuery plugin authored to
|
36
|
+
# contain the behavior of a component. The view helper must be called with an :id option as it is used to differentiate different
|
37
|
+
# instances of the same component on a single page from each other. It will also be used as the DOM element's id. A Guilded view
|
38
|
+
# helper should have a g_ appended to the beginning of it to help differentiate from normal view helepr sin a project.
|
39
|
+
#
|
40
|
+
# The JavaScript initialization function should be named init{ComponentName}( options ). The options hash from the view helper
|
41
|
+
# will automatically be passed to this function. The function should handle a before and after init callback to enable the user
|
42
|
+
# to set up anything necessary for the component and perform additional tasks. This function must also perform any other code
|
43
|
+
# necessary to set up the behavior for a compnent. An example fo this would be adding behavior to events or simply calling
|
44
|
+
# a jQuery plugin on element(s) of the component. Remember that any JavaScript relating to Guilded should be placed in the 'g'
|
45
|
+
# namespace that Guilded creates on every page. An example init function for a g_load_alerter would be:
|
46
|
+
#
|
47
|
+
# g.initLoadAlerter = function( options )
|
48
|
+
# {
|
49
|
+
# if( g.beforeInitLoadAlerter )
|
50
|
+
# g.beforeInitLoadAlerter( options );
|
51
|
+
#
|
52
|
+
# // Initialization code here...
|
53
|
+
#
|
54
|
+
# if( g.afterInitLoadAlerter )
|
55
|
+
# g.afterInitLoadAlerter( options );
|
56
|
+
# };
|
57
|
+
#
|
58
|
+
# For a user to implement these callback functions, they should create a JavaScript file with the functions and call it on
|
59
|
+
# any page they need it on utilizing Guilded's JavaScript include helper g_javascript_include_tag. This helper will add the
|
60
|
+
# JavaScript files after the jQuery and Guilded framework files, but within the component files in the order they were added.
|
61
|
+
# This will make the 'g' namespace available for use. Obviously this file must be included prior to calling the component's helper,
|
62
|
+
# or the callback functions will not be defined for use.
|
63
|
+
#
|
64
|
+
# The default stylesheet for a Guilded component should be the minimum amount of CSS for the component to function. When no :skin
|
65
|
+
# option is passed to the view helper when a component is added, Guilded will look for the default stylesheet. The assets
|
66
|
+
# used within the stylesheet (images) should be placed in a folder named default that is in the same directory as the default.css
|
67
|
+
# file. All asssets used in the stylesheet should use an absolute reference from the public directory: /stylesheets/guilded/{component_name}/default/{asset_name}.
|
68
|
+
#
|
69
|
+
# In order to create another skin for a component, simply create a {skin_name}.css file and a {skin_name} directory with the style
|
70
|
+
# assets in it. Be sure to reference the style assets with absolute paths from teh public directory so that the skin will work in
|
71
|
+
# all cases. Then call the component's view helper and use the :skin option:
|
72
|
+
#
|
73
|
+
# <%= g_load_alerter :skin => 'blueish', :id => 'load_alerter' %>
|
74
|
+
#
|
75
|
+
module Guilded
|
76
|
+
VERSION = '0.3.0'
|
77
|
+
end
|
78
|
+
|
79
|
+
ActionView::Base.send( :include, Guilded::Rails::ViewHelpers ) if defined?( ActionView )
|
@@ -0,0 +1,217 @@
|
|
1
|
+
module Guilded
|
2
|
+
|
3
|
+
# The BrowserDetector provides the ability to determine browser information from the user
|
4
|
+
# agent string.
|
5
|
+
#
|
6
|
+
class BrowserDetector
|
7
|
+
|
8
|
+
attr_reader :ua
|
9
|
+
|
10
|
+
def initialize( user_agent )
|
11
|
+
@ua = user_agent.downcase
|
12
|
+
@version_regex = /(\d*)\.(\d*)\.*(\d*)\.*(\d*)/
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns true if the browser matches the options ent in, otherwise returns false.
|
16
|
+
#
|
17
|
+
# === Request
|
18
|
+
# * +request+ - The request object.
|
19
|
+
#
|
20
|
+
# === Options
|
21
|
+
# * +:name+ - The name of the browser. For example 'ie' or :ie.
|
22
|
+
# * +:version+ - The version of the browser. For example '3.0.5'.
|
23
|
+
# * +:major_version+ - The major version of the browser. For example '3' or 3.
|
24
|
+
# * +:minor_version+ - The minor version of the browser. For example '0' or 0.
|
25
|
+
#
|
26
|
+
def browser_is?( options={} )
|
27
|
+
name = options[:name]
|
28
|
+
version = options[:version]
|
29
|
+
major_version = options[:major_version]
|
30
|
+
minor_version = options[:minor_version]
|
31
|
+
build_version = options[:build_version]
|
32
|
+
revision_version = options[:revision_version]
|
33
|
+
|
34
|
+
name ||= self.browser_name
|
35
|
+
version ||= self.browser_version
|
36
|
+
major_version ||= self.browser_version_major
|
37
|
+
minor_version ||= self.browser_version_minor
|
38
|
+
build_version ||= self.browser_version_build
|
39
|
+
revision_version ||= self.browser_version_revision
|
40
|
+
|
41
|
+
name = name.to_s.strip
|
42
|
+
version = version.to_s.strip
|
43
|
+
major_version = major_version.to_s.strip
|
44
|
+
minor_version = minor_version.to_s.strip
|
45
|
+
build_version = build_version.to_s.strip
|
46
|
+
revision_version = revision_version.to_s.strip
|
47
|
+
|
48
|
+
self.browser_name == name && self.browser_version == version && self.browser_version_major == major_version &&
|
49
|
+
self.browser_version_minor == minor_version #&& self.browser_version_build == build_version &&
|
50
|
+
#self.browser_version_revision == revision_version
|
51
|
+
end
|
52
|
+
|
53
|
+
# Returns the name of the browser that is making this request. For example 'ie'.
|
54
|
+
#
|
55
|
+
# === Request
|
56
|
+
# * +request+ - The request object.
|
57
|
+
#
|
58
|
+
def browser_name
|
59
|
+
begin
|
60
|
+
@browser_name ||= begin
|
61
|
+
ua = @ua
|
62
|
+
if ua.nil?
|
63
|
+
'unknown'
|
64
|
+
else
|
65
|
+
if ua.index( 'msie' ) && !ua.index( 'opera' ) && !ua.index( 'webtv' )
|
66
|
+
if ua.index( 'windows ce' )
|
67
|
+
'ie' + '_ce' #+ ua[ua.index( 'msie' ) + 5].chr
|
68
|
+
else
|
69
|
+
'ie' # + ua[ua.index( 'msie' ) + 5].chr
|
70
|
+
end
|
71
|
+
elsif ua.include?( 'opera' )
|
72
|
+
'opera'
|
73
|
+
elsif ua.include?( 'konqueror' )
|
74
|
+
'konqueror'
|
75
|
+
elsif ua.include?( 'applewebkit/' )
|
76
|
+
'safari'
|
77
|
+
elsif ua.include?( 'chrome' )
|
78
|
+
'chrome'
|
79
|
+
#elsif ua.include?( 'mozilla/' )
|
80
|
+
# 'firefox'
|
81
|
+
elsif ua.include?( 'firefox' )
|
82
|
+
'firefox'
|
83
|
+
#elsif ua.include?( 'gecko/' )
|
84
|
+
# 'firefox'
|
85
|
+
elsif ua.include?( 'netscape' )
|
86
|
+
'netscape'
|
87
|
+
else
|
88
|
+
'unknown'
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
rescue
|
93
|
+
'unknown'
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Returns the version of the browser that is making this request. For example '7'.
|
98
|
+
#
|
99
|
+
# === Request
|
100
|
+
# * +request+ - The request object.
|
101
|
+
#
|
102
|
+
def browser_version
|
103
|
+
@browser_version ||= begin
|
104
|
+
self.send( "resolve_version_for_#{self.browser_name}".to_sym )
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def browser_version_major
|
109
|
+
match = @version_regex.match( browser_version )
|
110
|
+
return match[1].to_i.to_s unless match.nil? || match.size < 2
|
111
|
+
'0'
|
112
|
+
end
|
113
|
+
|
114
|
+
def browser_version_minor
|
115
|
+
match = @version_regex.match( browser_version )
|
116
|
+
return match[2].to_i.to_s unless match.nil? || match.size < 3
|
117
|
+
'0'
|
118
|
+
end
|
119
|
+
|
120
|
+
def browser_version_build
|
121
|
+
match = @version_regex.match( browser_version )
|
122
|
+
return match[3].to_i.to_s unless match.nil? || match.size < 4 || match[3].empty? || match[3].nil?
|
123
|
+
'0'
|
124
|
+
end
|
125
|
+
|
126
|
+
def browser_version_revision
|
127
|
+
match = @version_regex.match( browser_version )
|
128
|
+
return match[4].to_i.to_s unless match.nil? || match.size < 5 || match[4].empty? || match[4].nil?
|
129
|
+
'0'
|
130
|
+
end
|
131
|
+
|
132
|
+
# Returns the browser name concatenated with the browser version. for example, 'ie7'.
|
133
|
+
#
|
134
|
+
# === Request
|
135
|
+
# * +request+ - The request object.
|
136
|
+
#
|
137
|
+
def browser_full_name
|
138
|
+
self.send( "browser_full_name_for_#{self.browser_name}".to_sym )
|
139
|
+
end
|
140
|
+
|
141
|
+
# Returns the browser name concatenated with the browser version. for example, 'ie7'.
|
142
|
+
#
|
143
|
+
# === Request
|
144
|
+
# * +request+ - The request object.
|
145
|
+
#
|
146
|
+
def browser_id
|
147
|
+
browser_name + browser_version.gsub( /\./, '' )
|
148
|
+
end
|
149
|
+
|
150
|
+
# Returns true if the current browser type can handle PNGs.
|
151
|
+
#
|
152
|
+
def can_use_png?
|
153
|
+
return browser_version.to_i >= 7 if browser_name== 'ie'
|
154
|
+
true
|
155
|
+
end
|
156
|
+
|
157
|
+
# A list of all the browser types that Guilded recognizes.
|
158
|
+
#
|
159
|
+
def self.all_browsers
|
160
|
+
%w( chrome firefox ie55 ie60 ie70 ie80 konqueror netscape opera safari )
|
161
|
+
end
|
162
|
+
|
163
|
+
# A list of all the mobile browser types that Guilded recognizes.
|
164
|
+
#
|
165
|
+
def self.all_mobile_browsers
|
166
|
+
%w( ie_ce4 iphone )
|
167
|
+
end
|
168
|
+
|
169
|
+
def self.user_agents
|
170
|
+
{
|
171
|
+
:ie55 => 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.1)',
|
172
|
+
:ie60 => 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)',
|
173
|
+
:ie70 => 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)',
|
174
|
+
:ie80 => 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)',
|
175
|
+
:firefox2 => 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.17) Gecko/20080829 Firefox/2.0.0.17',
|
176
|
+
:firefox3 => 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.0.11) Gecko/2009060214 Firefox/3.0.11',
|
177
|
+
:firefox35 => 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3',
|
178
|
+
:firefox35win => 'Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3 (.NET CLR 3.5.30729)',
|
179
|
+
:opera10 => 'Opera/9.80 (Macintosh; Intel Mac OS X; U; en) Presto/2.2.15 Version/10.00'
|
180
|
+
}
|
181
|
+
end
|
182
|
+
|
183
|
+
protected
|
184
|
+
|
185
|
+
def resolve_version_for_ie
|
186
|
+
match = /.*msie (.*); windows nt 5.1/.match( @ua )
|
187
|
+
return match.nil? ? '0' : match[1]
|
188
|
+
end
|
189
|
+
|
190
|
+
def resolve_version_for_firefox
|
191
|
+
match = /.*\((.*); u;.*firefox\/(.*) \(.net.*/.match( @ua )
|
192
|
+
if match.nil?
|
193
|
+
match = /.*\((.*); u;.*firefox\/(.*)/.match( @ua )
|
194
|
+
return match.nil? ? '0' : match[2]
|
195
|
+
end
|
196
|
+
return match.nil? ? '0' : match[2]
|
197
|
+
end
|
198
|
+
|
199
|
+
def resolve_version_for_opera
|
200
|
+
match = /.*\((.*); intel.*version\/(.*)/.match( @ua )
|
201
|
+
return match.nil? ? '0' : match[2]
|
202
|
+
end
|
203
|
+
|
204
|
+
def browser_full_name_for_ie
|
205
|
+
"Internet Explorer #{browser_version}"
|
206
|
+
end
|
207
|
+
|
208
|
+
def browser_full_name_for_firefox
|
209
|
+
"Firefox #{browser_version}"
|
210
|
+
end
|
211
|
+
|
212
|
+
def browser_full_name_for_opera
|
213
|
+
"Opera #{browser_version}"
|
214
|
+
end
|
215
|
+
|
216
|
+
end
|
217
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Guilded
|
2
|
+
class ComponentDef
|
3
|
+
|
4
|
+
attr_reader :kind, :options, :libs, :styles
|
5
|
+
attr_accessor :additional_js
|
6
|
+
|
7
|
+
def initialize( kind, options={}, libs=[], styles=[], additional_js='' )
|
8
|
+
@kind = kind
|
9
|
+
@options = options
|
10
|
+
@libs = libs
|
11
|
+
@styles = styles
|
12
|
+
@additional_js = additional_js
|
13
|
+
end
|
14
|
+
|
15
|
+
def exclude_css?
|
16
|
+
options.include?( :exclude_css ) && ( options[:exclude_css] == 'true' || options[:exclude_css] == true )
|
17
|
+
end
|
18
|
+
|
19
|
+
def exclude_js?
|
20
|
+
options.include?( :exclude_js ) && ( options[:exclude_js] == 'true' || options[:exclude_js] == true )
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Guilded
|
2
|
+
module Exceptions
|
3
|
+
|
4
|
+
class GuildedException < RuntimeError
|
5
|
+
def initialize( msg="" ) #:nodoc:
|
6
|
+
@msg = msg
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class IdMissing < GuildedException
|
11
|
+
def initialize #:nodoc:
|
12
|
+
@msg = ":id for element must be present in the options hash"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class DuplicateElementId < GuildedException
|
17
|
+
def initialize( id='' ) #:nodoc:
|
18
|
+
@msg = ":id #{id} for element is already in use on current page"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class MissingConfiguration < GuildedException
|
23
|
+
def initialize #:nodoc:
|
24
|
+
@msg = "There is no GUILDED_CONFIG instance. Please load Guilded configuration with your apps initialization."
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,357 @@
|
|
1
|
+
require 'digest'
|
2
|
+
require 'singleton'
|
3
|
+
require 'guilded/exceptions'
|
4
|
+
|
5
|
+
module Guilded
|
6
|
+
|
7
|
+
# Guilder is the worker for the entire Guilded framework. It collects all of the necessary components for a page
|
8
|
+
# through its add() method. When the g_apply_behavior() method is called at the end of a page, the Guilder writes
|
9
|
+
# HTML to include all of the necessary asset files (caching them in production). It also writes s JavaScript initialization
|
10
|
+
# function and fires the initialization function on page load.
|
11
|
+
#
|
12
|
+
# This initialization function calls the initialization function for each Guilded component that was added to the current
|
13
|
+
# page. For example, if a Guilded component named 'g_load_alerter' was added to a page, the Guilder would include this line
|
14
|
+
# in the initialization function it writes: g.initLoadAlerter( /* passing options hash here */ ); The g before the function
|
15
|
+
# is a JavaScript namespace that Guilded automatically creates to facilitate avoiding name collisions with other JavaScript
|
16
|
+
# libraries and code.
|
17
|
+
#
|
18
|
+
# Th options hash that is passed to the init functions for each Guilded component is simply the options hash from the
|
19
|
+
# component's view helper. The Guilder calls .to_json() on the options hash. Thus, if there are pairs in the options hash
|
20
|
+
# that need not go to the JavaScript init method they should be removed within the view helper.
|
21
|
+
#
|
22
|
+
class Guilder
|
23
|
+
include Singleton
|
24
|
+
|
25
|
+
GUILDED_NS = "guilded."
|
26
|
+
|
27
|
+
attr_reader :initialized_at, :jquery_js, :mootools_js
|
28
|
+
|
29
|
+
def initialize #:nodoc:
|
30
|
+
if defined?( GUILDED_CONFIG )
|
31
|
+
@config = GUILDED_CONFIG
|
32
|
+
else
|
33
|
+
raise Guilded::Exceptions::MissingConfiguration
|
34
|
+
end
|
35
|
+
configure_guilded
|
36
|
+
@initialized_at = Time.now
|
37
|
+
@g_elements = Hash.new
|
38
|
+
@g_data_elements = Hash.new
|
39
|
+
@combined_js_srcs = Array.new
|
40
|
+
@combined_css_srcs = Array.new
|
41
|
+
@assets_combined = false
|
42
|
+
# Make sure that the css reset file is first so that other files can override the reset,
|
43
|
+
# unless the user specified no reset to be included.
|
44
|
+
init_sources
|
45
|
+
end
|
46
|
+
|
47
|
+
# Adds an element with its options to the @g_elements hash to be used later.
|
48
|
+
#
|
49
|
+
def add( element, options={}, libs=[], styles=[] )
|
50
|
+
raise Guilded::Exceptions::IdMissing.new unless options.has_key?( :id )
|
51
|
+
raise Guilded::Exceptions::DuplicateElementId.new( options[:id] ) if @g_elements.has_key?( options[:id] )
|
52
|
+
@need_mootools = true if options[:mootools]
|
53
|
+
@g_elements[ options[:id].to_sym ] = Guilded::ComponentDef.new( element, options, libs, styles )
|
54
|
+
end
|
55
|
+
|
56
|
+
# Adds a data structure to be passed to the Guilded JavaScript environment for use on the client
|
57
|
+
# side. The data is passed using the ruby to_json method on the data structure provided.
|
58
|
+
#
|
59
|
+
# === Parameters
|
60
|
+
# * +name+ - The desired name of the variable on the client side.
|
61
|
+
# * +data+ - The data to pass to the Guilded JavaScript environment.
|
62
|
+
#
|
63
|
+
def add_data( name, data )
|
64
|
+
@g_data_elements.merge!( name.to_sym => data )
|
65
|
+
end
|
66
|
+
|
67
|
+
# Adds JavaScript sources to the libs collection by resolving them to the normal or min version
|
68
|
+
# based on the current running environment, development, production, etc.
|
69
|
+
#
|
70
|
+
def add_js_sources( *sources )
|
71
|
+
resolve_js_libs( *sources )
|
72
|
+
end
|
73
|
+
|
74
|
+
def count #:nodoc:
|
75
|
+
@g_elements.size
|
76
|
+
end
|
77
|
+
|
78
|
+
# The number of Guilded components to be renderred.
|
79
|
+
#
|
80
|
+
def component_count
|
81
|
+
count
|
82
|
+
end
|
83
|
+
|
84
|
+
# The current number of CSS assets necessary for the Guilded component set.
|
85
|
+
#
|
86
|
+
def style_count
|
87
|
+
@combined_css_srcs.size
|
88
|
+
end
|
89
|
+
|
90
|
+
# The current number of JavaScript assets necessary for the Guilded component set.
|
91
|
+
#
|
92
|
+
def script_count
|
93
|
+
@combined_js_srcs.size
|
94
|
+
end
|
95
|
+
|
96
|
+
# Returns true if the component type is included, otherwise false.
|
97
|
+
#
|
98
|
+
def include_component?( type )
|
99
|
+
@g_elements.has_key?( type.to_sym )
|
100
|
+
end
|
101
|
+
|
102
|
+
# The collection of JavaScript assets for the current Guilded component set.
|
103
|
+
#
|
104
|
+
def combined_js_srcs
|
105
|
+
#generate_asset_lists unless @assets_combined
|
106
|
+
@combined_js_srcs
|
107
|
+
end
|
108
|
+
|
109
|
+
# The collection of CSS assets for the current Guilded component set.
|
110
|
+
#
|
111
|
+
def combined_css_srcs
|
112
|
+
#generate_asset_lists unless @assets_combined
|
113
|
+
@combined_css_srcs
|
114
|
+
end
|
115
|
+
|
116
|
+
# Clears out all but the reset CSS and the base JavaScripts
|
117
|
+
#
|
118
|
+
def reset!
|
119
|
+
@combined_css_srcs.clear
|
120
|
+
@combined_js_srcs.clear
|
121
|
+
@g_elements.clear
|
122
|
+
@assets_combined = false
|
123
|
+
init_sources
|
124
|
+
@default_css_count = @combined_css_srcs.size
|
125
|
+
@default_js_count = @combined_js_srcs.size
|
126
|
+
end
|
127
|
+
|
128
|
+
def inject_css( *sources )
|
129
|
+
@combined_css_srcs.insert( @default_css_count, *sources )
|
130
|
+
end
|
131
|
+
|
132
|
+
def inject_js( *sources )
|
133
|
+
@combined_js_srcs.insert( @default_js_count, *sources )
|
134
|
+
end
|
135
|
+
|
136
|
+
# Generates the markup required to include all the assets necessary for the Guilded compoents in
|
137
|
+
# @g_elements collection. Use this if you are not interested in caching asset files.
|
138
|
+
#
|
139
|
+
def apply #:nodoc:
|
140
|
+
to_init = ""
|
141
|
+
generate_asset_lists unless @assets_combined
|
142
|
+
@combined_css_srcs.each { |css| to_init << "<link href=\"/stylesheets/#{css}\" media=\"screen\" rel=\"stylesheet\" type=\"text/css\" />" }
|
143
|
+
@combined_js_srcs.each { |js| to_init << "<script type=\"text/javascript\" src=\"/javascripts/#{js}\"></script>" }
|
144
|
+
to_init << generate_javascript_init
|
145
|
+
reset!
|
146
|
+
end
|
147
|
+
|
148
|
+
# Writes an initialization method that calls each Guilded components initialization method. This
|
149
|
+
# method will exceute on document load finish.
|
150
|
+
#
|
151
|
+
def generate_javascript_init #:nodoc:
|
152
|
+
code = "<script type=\"text/javascript\">"
|
153
|
+
code << "var initGuildedElements = function(){"
|
154
|
+
@g_data_elements.each do |name, data|
|
155
|
+
code << "g.#{name} = #{data.to_json};"
|
156
|
+
end
|
157
|
+
@g_elements.each_value do |guilded_def|
|
158
|
+
code << "g.#{guilded_def.kind.to_s.camelize( :lower )}Init(#{guilded_def.options.to_json});" unless guilded_def.exclude_js?
|
159
|
+
end
|
160
|
+
code << "jQuery('body').trigger('guildedInitialized');};jQuery('document').ready(initGuildedElements);</script>"
|
161
|
+
end
|
162
|
+
|
163
|
+
# Generates a name to use when caching the current set of Guilded component JavaScript assets. Sorts and concatenates
|
164
|
+
# the name of each JavaScript asset in @combined_js_srcs. Then hashes this string to generate a reproducible, unique
|
165
|
+
# and shorter string.
|
166
|
+
#
|
167
|
+
def js_cache_name
|
168
|
+
generate_js_cache_name( @combined_js_srcs )
|
169
|
+
end
|
170
|
+
|
171
|
+
# Generates a name to use when caching the current set of Guilded component CSS assets. Sorts and concatenates
|
172
|
+
# the name of each JavaScript asset in @combined_js_srcs. Then hashes this string to generate a reproducible, unique
|
173
|
+
# and shorter string.
|
174
|
+
#
|
175
|
+
def css_cache_name
|
176
|
+
generate_css_cache_name( @combined_css_srcs )
|
177
|
+
end
|
178
|
+
|
179
|
+
def generate_js_cache_name( sources ) #:nodoc:
|
180
|
+
generate_asset_lists unless @assets_combined
|
181
|
+
#return"#{controller.class.to_s.underscore}_#{controller.action_name}" if development?
|
182
|
+
sorted_srcs = sources.sort
|
183
|
+
stripped_srcs = sorted_srcs.map { |src| src.gsub( /.js/, '' ).gsub( /\//, '_') }
|
184
|
+
joined = stripped_srcs.join( "+" )
|
185
|
+
"#{Digest::MD5.hexdigest( joined )}"
|
186
|
+
end
|
187
|
+
|
188
|
+
def generate_css_cache_name( sources ) #:nodoc:
|
189
|
+
generate_asset_lists unless @assets_combined
|
190
|
+
#return "#{controller.class.to_s.underscore}_#{controller.action_name}" if development?
|
191
|
+
sorted_srcs = sources.sort
|
192
|
+
stripped_srcs = sorted_srcs.map { |src| src.gsub( /.css/, '' ).gsub( /\//, '_') }
|
193
|
+
joined = stripped_srcs.join( "+" )
|
194
|
+
"#{Digest::MD5.hexdigest( joined )}"
|
195
|
+
end
|
196
|
+
|
197
|
+
protected
|
198
|
+
|
199
|
+
def configure_guilded #:nodoc:
|
200
|
+
@js_path = @config[:js_path]
|
201
|
+
@js_folder = @config[:js_folder]
|
202
|
+
@jquery_js = @config[:jquery_js]
|
203
|
+
@mootools_js = @config[:mootools_js]
|
204
|
+
@jquery_folder = @config[:jquery_folder] || 'jquery/'
|
205
|
+
@mootools_folder = @config[:mootools_folder] || 'mootools/'
|
206
|
+
@guilded_js = 'guilded.min.js'
|
207
|
+
@url_js = 'jquery-url.min.js'
|
208
|
+
@css_path = @config[:css_path]
|
209
|
+
@css_folder = @config[:css_folder]
|
210
|
+
@reset_css = @config[:reset_css]
|
211
|
+
#@do_reset_css = @config[:do_reset_css]
|
212
|
+
@env = @config[:environment]
|
213
|
+
@env ||= :production
|
214
|
+
@js_path.freeze
|
215
|
+
@css_path.freeze
|
216
|
+
@js_folder.freeze
|
217
|
+
@guilded_js.freeze
|
218
|
+
@url_js.freeze
|
219
|
+
@jquery_js.freeze
|
220
|
+
@jquery_folder.freeze
|
221
|
+
@mootols_js.freeze
|
222
|
+
@mootools_folder.freeze
|
223
|
+
@guilded_js.freeze
|
224
|
+
@css_folder.freeze
|
225
|
+
@reset_css.freeze
|
226
|
+
#@do_reset_css.freeze
|
227
|
+
@env.freeze
|
228
|
+
end
|
229
|
+
|
230
|
+
# Adds the Guilded reset CSS file and the guilded.js and jQuery files to the respective sources
|
231
|
+
# collections.
|
232
|
+
#
|
233
|
+
def init_sources #:nodoc:
|
234
|
+
@combined_css_srcs << "#{@reset_css}" unless @reset_css.nil? || @reset_css.empty?
|
235
|
+
resolve_js_libs( "#{@jquery_js}", "#{@jquery_folder}#{@url_js}", "#{@js_folder}#{@guilded_js}" )
|
236
|
+
end
|
237
|
+
|
238
|
+
# Combines all JavaScript and CSS files into lists to include based on what Guilded components are on
|
239
|
+
# the current page.
|
240
|
+
#
|
241
|
+
def generate_asset_lists #:nodoc:
|
242
|
+
@assets_combined = true
|
243
|
+
@g_elements.each_value do |defi|
|
244
|
+
#TODO get stylesheet (skin) stuff using rails caching
|
245
|
+
combine_css_sources( defi.kind, defi.options[:skin], defi.styles ) unless defi.exclude_css?
|
246
|
+
|
247
|
+
# Combine all JavaScript sources so that the caching option can be used on
|
248
|
+
# the javascript_incldue_tag helper.
|
249
|
+
combine_js_sources( defi.kind, defi.libs ) unless defi.exclude_js?
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
# Helper method that takes the libs and component specific js files and puts them
|
254
|
+
# into one array so that the javascript_include_tag can correctly cache them. Automatically
|
255
|
+
# ignores files that have already been inlcuded.
|
256
|
+
#
|
257
|
+
# *parameters*
|
258
|
+
# combined_src (required) An array of the combined sorces for the page being renderred.
|
259
|
+
# component (required) The name of a guilded component.
|
260
|
+
# libs An array of JavaScript libraries that this component depends on. More than likely
|
261
|
+
# a jQuery plugin, etc.
|
262
|
+
#
|
263
|
+
def combine_js_sources( component, libs=[] ) #:nodoc:
|
264
|
+
libs << @mootools_js if @need_mootools
|
265
|
+
resolve_js_libs( *libs )
|
266
|
+
|
267
|
+
comp_src = add_guilded_js_path( component )
|
268
|
+
@combined_js_srcs.push( comp_src ) unless @combined_js_srcs.include?( comp_src )
|
269
|
+
end
|
270
|
+
|
271
|
+
# Helper method that adds the aditional JavaScript library icludes to the include set.
|
272
|
+
#
|
273
|
+
# If running development mode, it will try to remove any .pack, .min, or.compressed
|
274
|
+
# parts fo the name to try and get the debug version of the library. If it cannot
|
275
|
+
# find the debug version of the file, it will just remain what was initially provded.
|
276
|
+
#
|
277
|
+
def resolve_js_libs( *libs ) #:nodoc:
|
278
|
+
if development?
|
279
|
+
# Try to use an unpacked or unminimized version
|
280
|
+
libs.each do |lib|
|
281
|
+
debug_lib = lib.gsub( /.pack/, '' ).gsub( /.min/, '' ).gsub( /.compressed/, '' )
|
282
|
+
path = "#{RAILS_ROOT}/public/javascripts/#{debug_lib}"
|
283
|
+
if File.exist?( path )
|
284
|
+
@combined_js_srcs.push( debug_lib ) unless @combined_js_srcs.include?( debug_lib )
|
285
|
+
else
|
286
|
+
@combined_js_srcs.push( lib ) unless @combined_js_srcs.include?( lib )
|
287
|
+
end
|
288
|
+
end
|
289
|
+
else
|
290
|
+
libs.each { |lib| @combined_js_srcs.push( lib ) unless @combined_js_srcs.include?( lib ) }
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
# Helper method that takes an array of js sources and adds the correct guilded
|
295
|
+
# path to them. Returns an array with the new path resolved sources.
|
296
|
+
#
|
297
|
+
def map_guilded_js_paths( *sources ) #:nodoc:
|
298
|
+
sources.map { |source| add_guilded_js_path( source ) }
|
299
|
+
end
|
300
|
+
|
301
|
+
# Adds the guilded JS path to the the source name passed in. When not in development mode,
|
302
|
+
# it looks for a .pack.js, .min.jsm .compressed.js and chooses one of these over the
|
303
|
+
# development version.
|
304
|
+
#
|
305
|
+
def add_guilded_js_path( source ) #:nodoc:
|
306
|
+
part = "#{@js_folder}#{GUILDED_NS}#{source.to_s}"
|
307
|
+
ext = 'js'
|
308
|
+
|
309
|
+
return "#{part}.#{ext}" unless production?
|
310
|
+
|
311
|
+
possibles = [ "#{@js_path}#{part}.min.#{ext}", "#{@js_path}#{part}.pack.#{ext}", "#{@js_path}#{part}.compressed.#{ext}",
|
312
|
+
"#{@js_path}#{part}.#{ext}" ]
|
313
|
+
parts = [ "#{part}.min.#{ext}", "{part}.pack.#{ext}", "#{part}.compressed.#{ext}", "#{part}.#{ext}" ]
|
314
|
+
|
315
|
+
possibles.each_with_index do |full_path, i|
|
316
|
+
return parts[i] if File.exists?( full_path )
|
317
|
+
end
|
318
|
+
|
319
|
+
"" # Should never reach here
|
320
|
+
end
|
321
|
+
|
322
|
+
def combine_css_sources( component, skin, styles=[] ) #:nodoc:
|
323
|
+
# Get all of this components defined external styles
|
324
|
+
styles.each do |style|
|
325
|
+
@combined_css_srcs.push( style ) unless @combined_css_srcs.include?( style )
|
326
|
+
end
|
327
|
+
|
328
|
+
#Get the default or guilded skin styles for this component
|
329
|
+
comp_src = add_guilded_css_path( component, skin )
|
330
|
+
@combined_css_srcs.push( comp_src ) unless @combined_css_srcs.include?( comp_src ) || comp_src.empty?
|
331
|
+
user_src = add_guilded_css_path( component, "user" )
|
332
|
+
@combined_css_srcs.push( user_src ) unless @combined_css_srcs.include?( user_src ) || user_src.empty?
|
333
|
+
skin_user_src = add_guilded_css_path( component, "#{skin || 'default'}_user" )
|
334
|
+
@combined_css_srcs.push( skin_user_src ) unless @combined_css_srcs.include?( skin_user_src ) || skin_user_src.empty?
|
335
|
+
end
|
336
|
+
|
337
|
+
def add_guilded_css_path( source, skin ) #:nodoc:
|
338
|
+
skin = 'default' if skin.nil? || skin.empty?
|
339
|
+
part = "#{@css_folder}#{source.to_s}/#{skin}.css"
|
340
|
+
path = "#{@css_path}#{part}"
|
341
|
+
File.exists?( path ) ? part : ''
|
342
|
+
end
|
343
|
+
|
344
|
+
def development? #:nodoc:
|
345
|
+
@env.to_sym == :development
|
346
|
+
end
|
347
|
+
|
348
|
+
def production? #:nodoc:
|
349
|
+
@env.to_sym == :production
|
350
|
+
end
|
351
|
+
|
352
|
+
def test? #:nodoc:
|
353
|
+
@env.to_sym == :test
|
354
|
+
end
|
355
|
+
|
356
|
+
end
|
357
|
+
end
|