guilded 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|