widget_builder 0.1.0.alpha
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.rspec +1 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +141 -0
- data/Rakefile +8 -0
- data/app/assets/javascripts/widget_loader.js +79 -0
- data/lib/widget_builder/constants.rb +4 -0
- data/lib/widget_builder/version.rb +3 -0
- data/lib/widget_builder.rb +212 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/widget_builder_spec.rb +4 -0
- data/widget_builder.gemspec +28 -0
- metadata +158 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 90f4cc2d815c5777c210e44d1ba56ada0aaa31d6
|
4
|
+
data.tar.gz: b02ca2bee98891fcfd4ad0c67e6f5e777fe97ee1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d1d859a96e2c5304e143996285bfba1f281d2621edc076734dda1a91ffce298ece03e52d5c6c024892fa62b40698e3067a92609ae8be7192f03c50e4058a9b7a
|
7
|
+
data.tar.gz: 6a3da34735f718f98adaf536434dc9f06b8a146499581e09124e15a3ba070490128e0c5abb0ffe8f3ccd5b93189c7322e31374fb0f6704338eb4db072fe6a761
|
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Endri Gjiri
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
# WidgetBuilder
|
2
|
+
|
3
|
+
By: Endri Gjiri *www.name-reaction.com*
|
4
|
+
|
5
|
+
**WidgetBuilder** aims to be a simple way to create javascript widgets. It allows developers to work separately on the html, css, and javascript files for their widgets. WidgetBuilder combines all of these files into a single minified javascript file, ready to be loaded by the end user. WidgetBuilder also wraps everything with a javascript Widget class, namespacing everything, and allows the display of multiple widgets in the same page without conflicts.
|
6
|
+
#### Other Features include:
|
7
|
+
- Provides a simple and small snippet for the user on which to load the widget. It only consists of an anchor tag with a class of the specific ```widget_name``` and the script tag to load the generated widget javascript.
|
8
|
+
- The a tag on which the widget is loaded on top of can serve as a way to pass options to the widget js through the a tag's data attributes. This data can be used to customize the widget's function or style.
|
9
|
+
- Provides a ```validateReference``` function that checks if the developer's site is referenced properly SEO-wise and if not it destroys the widget. This function needs to be called explicitly in the developer's custom javascript.
|
10
|
+
- Provides a ```resetCSS``` function which minimizes style conflicts with the sites that the widget ultimately ends up in.
|
11
|
+
|
12
|
+
## Installation
|
13
|
+
|
14
|
+
Add this line to your application's Gemfile:
|
15
|
+
```ruby
|
16
|
+
gem 'widget_builder'
|
17
|
+
```
|
18
|
+
|
19
|
+
And then execute:
|
20
|
+
```console
|
21
|
+
$ bundle install
|
22
|
+
```
|
23
|
+
|
24
|
+
Or install it yourself as:
|
25
|
+
```console
|
26
|
+
$ gem install widget_builder
|
27
|
+
```
|
28
|
+
|
29
|
+
### Brief description of the Ruby classes
|
30
|
+
|
31
|
+
WidgetBuilder consists of a Ruby module of the same name which contains two classes named **Widget** and **Widgets** (plural).
|
32
|
+
|
33
|
+
The main class is the **Widget** class which needs 3 arguments, the html_path, css_path, and js_path respectively. It also has a forth optional argument which is an options hash. This class essentially reads all of these files, includes the css inline into the html, and then adds this combined html_and_css string into the javascript. This class also wraps the javascript with the gem's own ```widget_loader``` javascript which provides additional functionality to the widget. Instance methods include: ```save```, ```show_snippet```, ```report```, and ```compile```, among others.
|
34
|
+
|
35
|
+
The **Widgets** (plural) class is designed to create multiple widgets at once, relying on naming conventions. It also accepts html_path, css_path, and js_path as arguments but in this case they do not refer to the file paths but instead to directory paths. This class will first go to the html directory and get all the file names and try to match them to css and js files of the same name in their respective folders. It will then loop through the list of html files and create an instance of the Widget class by passing in the html, css, and js file. The final result is an array of widgets (instances of Widget). The Widgets class also responds to ```save```, ```report```, and ```compile``` and loops over the array of widgets and calls the appropriate method on the widget instance.
|
36
|
+
|
37
|
+
## Usage
|
38
|
+
|
39
|
+
#### The simplest way to get started with this gem is the following:
|
40
|
+
|
41
|
+
1. Place the html, css, and js files needed for the widget all in the same folder and navigate there in the console.
|
42
|
+
|
43
|
+
2. Load irb and require widget_builder
|
44
|
+
```console
|
45
|
+
$ irb
|
46
|
+
> require 'widget_builder'
|
47
|
+
```
|
48
|
+
|
49
|
+
3. Compile the widget directly through irb.
|
50
|
+
```ruby
|
51
|
+
WidgetBuilder::Widgets.new.compile
|
52
|
+
```
|
53
|
+
Note: When no paths are passed as attributes to the Widgets class, it defaults them to the current directory.
|
54
|
+
|
55
|
+
This will create a new javascript file which is the new widget file, named according to the widget_name. The widget_name gets extracted by the class of the first div in the html or it can be passed in through the options hash.
|
56
|
+
|
57
|
+
This command will also generate a report in the console, also including an html snippet that the end user can copy and place on their pages to display the widget.
|
58
|
+
|
59
|
+
A sample snippet is shown below:
|
60
|
+
```html
|
61
|
+
<a class="chemiphi_MMC" href="http://www.name-reaction.com"></a>
|
62
|
+
<script type="text/javascript">
|
63
|
+
var element = document.createElement('script');
|
64
|
+
element.type = 'text/javascript';
|
65
|
+
element.src = 'http://api.chemiphi.com/public_widgets/chemiphi_MMC.js';
|
66
|
+
document.getElementsByTagName('head')[0].appendChild(element);
|
67
|
+
</script>
|
68
|
+
```
|
69
|
+
|
70
|
+
## Usage with Rails
|
71
|
+
#### Building a widget by specifying the paths to the html, css, and js in a Rails app.
|
72
|
+
|
73
|
+
A simple way to build a widget in rails is to do it by creating a custom Task.
|
74
|
+
|
75
|
+
Let's create a new Ruby file "/lib/tasks/widget_compiler.rake" with the following code:
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
desc "Creates a single uglified widget JavaScript file containing the custom HTML, CSS, and JS"
|
79
|
+
task :create_widget do
|
80
|
+
html_path = File.join(Rails.root, 'app', 'views', 'widgets', 'my_widget.html')
|
81
|
+
css_path = File.join(Rails.root, 'app', 'assets', 'stylesheets', 'widgets', 'my_widget.css')
|
82
|
+
js_path = File.join(Rails.root, 'app', 'assets', 'javascripts', 'widgets', 'my_widget.js')
|
83
|
+
|
84
|
+
widget = WidgetBuilder::Widget.new(html_path, css_path, js_path)
|
85
|
+
|
86
|
+
export_path = File.join(Rails.root, 'public', 'widgets')
|
87
|
+
widget.compile(export_path)
|
88
|
+
end
|
89
|
+
```
|
90
|
+
In the above code we have specified that the final widget js should be placed in a public/widgets folder so before we run this task we need to first create the widgets folder.
|
91
|
+
|
92
|
+
We can then build the widget by running the following command from the console:
|
93
|
+
```console
|
94
|
+
$ rake create_widget
|
95
|
+
```
|
96
|
+
This will create the widget.js in the public/widgets folder, ready to be accessed by users and also displays in the console the HTML snippet required to display this widget.
|
97
|
+
|
98
|
+
## Options
|
99
|
+
|
100
|
+
#### The WidgetBuilder also accepts an options hash as a fourth argument.
|
101
|
+
|
102
|
+
Available options include:
|
103
|
+
- **compress** - *defaults to true* - specifies whether the compiled javascript file should be minified.
|
104
|
+
- **href** - *defaults to #* - specifies the url that the snippet anchor tag should link to. This has to be passed in as an option if the *validateReference* function is called from the js file.
|
105
|
+
- **source_path** - needed to point to the src of the compiled widget.js in the snippet. In the above example this could be *www.my_domain.com/widgets*.
|
106
|
+
|
107
|
+
**Example:**
|
108
|
+
```ruby
|
109
|
+
options = { compress: false, href: 'www.my_domain.com', source_path: 'www.my_domain.com/widgets' }
|
110
|
+
widget = WidgetBuilder::Widget.new(html_path, css_path, js_path, options)
|
111
|
+
widget.compile(export_path)
|
112
|
+
```
|
113
|
+
|
114
|
+
This would create a non-minified widget javascript and final HTML snippet that looks like this:
|
115
|
+
```html
|
116
|
+
<a class="my_widget" href="http://www.my_domain.com"></a>
|
117
|
+
<script type="text/javascript">
|
118
|
+
var element = document.createElement('script');
|
119
|
+
element.type = 'text/javascript';
|
120
|
+
element.src = 'http://www.my_domain.com/widgets/my_widget.js';
|
121
|
+
document.getElementsByTagName('head')[0].appendChild(element);
|
122
|
+
</script>
|
123
|
+
```
|
124
|
+
## JavaScript Utilities
|
125
|
+
#### The widget's functionality is determined in the custom javascript file that you develop.
|
126
|
+
##### This javascript get wrapped in the gem's ```widget_loader``` js code that extends it with additional functionality.
|
127
|
+
|
128
|
+
- ```var widget ``` becomes available to your custom javascript file and it stores the whole widget object. Outputting it to the console shows that it includes the widget ```id```, ```aTag```, ```dataset```, ```app```, and the ```validateRefence``` function.
|
129
|
+
- ```var w ``` is also available to the custom javascript and it holds the whole widget as a jQuery object. This can come in handy when trying to find elements within a particular widget and can be done using ```w.find('.my_element') ``` instead of searching it on the global scope as in ```$(.my_element) ```. This can be useful when it is desirable to have multiple widgets running on the same page without conflicting with each other.
|
130
|
+
|
131
|
+
## Future Work
|
132
|
+
- As of now the only file formats that are supported are html, css, js as well as scss, and sass. In the next release I would like to extend support for haml and coffeeScript.
|
133
|
+
- Current integration with Rails is quite raw and does not take advantage of the capabilities of Rails. In the future I want to create another gem, likely wiget_builder-rails, that is designed specifically for working in Rails.
|
134
|
+
|
135
|
+
## Contributing
|
136
|
+
|
137
|
+
1. Fork it
|
138
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
139
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
140
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
141
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
// START...
|
2
|
+
if (window.jQuery != undefined) { // If the user already has jQuery loaded on their site just start loading the widget
|
3
|
+
loadWidget();
|
4
|
+
} else { // Load jQuery
|
5
|
+
element = document.createElement('script');
|
6
|
+
element.setAttribute('type', 'text/javascript');
|
7
|
+
element.setAttribute('src', 'https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js'); // jQuery from Google
|
8
|
+
document.getElementsByTagName('head')[0].appendChild(element); // add jQuery to the head
|
9
|
+
element.onload = loadWidget; // once jQuery has loaded, start loading the chemiphi widget
|
10
|
+
}
|
11
|
+
|
12
|
+
// Loads the widget on top of <a> tags with a class of 'widget_name'
|
13
|
+
function loadWidget() {
|
14
|
+
jQuery(function($) {
|
15
|
+
// Note: The 'widget_name' below will be automatically replaced with the propper class from the ruby widget_builder script
|
16
|
+
$('a.widget_name').each(function(index, aTag) { // Creates a widget for every <a> tag with a class of widget_name
|
17
|
+
new CustomWidget(aTag);
|
18
|
+
});
|
19
|
+
});
|
20
|
+
}
|
21
|
+
|
22
|
+
// Custom Widget class that include the js code from the included js_path
|
23
|
+
function CustomWidget(aTag) {
|
24
|
+
var widget = new Widget(aTag); // Create an instance of the widget object
|
25
|
+
var w = widget.app; // 'w' is just a shortcut for the whole widget.app jQuery object
|
26
|
+
JAVASCRIPT_PLACEHOLDER // The rest of the javascript is then included
|
27
|
+
}
|
28
|
+
|
29
|
+
// The main Widget class.
|
30
|
+
function Widget(aTag) {
|
31
|
+
this.id = aTag.className + '_' + Math.round(Math.random()*10000); // generate a random number as the id of the widget
|
32
|
+
this.aTag = aTag;
|
33
|
+
this.dataset = $(aTag).data();
|
34
|
+
this.app = $('<div>HTML&CSS_PLACEHOLDER</div>').attr('id', this.id);
|
35
|
+
$(aTag).replaceWith(this.app); // Replace the <a> tag placeholder with the widget HTML
|
36
|
+
|
37
|
+
// Destroys the widget if the referring link has been altered. This functions needs to be called to take effect
|
38
|
+
this.validateReference = function validateReference() {
|
39
|
+
var a = $(aTag);
|
40
|
+
if (a.attr('href') != 'HREF_PLACEHOLDER' || a.attr('rel') == 'nofollow') {
|
41
|
+
this.app.remove();
|
42
|
+
delete this;
|
43
|
+
// Displays a console error alerting of the situation
|
44
|
+
console.error('The Widget widget_name was not loaded due to an invalid <a> tag reference.\nA valid tag would be: VALID_ATAG_PLACEHOLDER')
|
45
|
+
}
|
46
|
+
}
|
47
|
+
}
|
48
|
+
|
49
|
+
// Utility function that sets the CSS of elements to defaults if they are not already set
|
50
|
+
function resetCSS(element, andChildren) {
|
51
|
+
// if andChildren is true, reset the styles of the specified jQuery object and all its children
|
52
|
+
var elements = andChildren ? element.find('*').andSelf() : element;
|
53
|
+
elements.each( function() {
|
54
|
+
var defaultStyles = {
|
55
|
+
'margin-top': '0px',
|
56
|
+
'margin-bottom': '0px',
|
57
|
+
'margin-left': '0px',
|
58
|
+
'margin-right': '0px',
|
59
|
+
'padding-top': '0px',
|
60
|
+
'padding-bottom': '0px',
|
61
|
+
'padding-left': '0px',
|
62
|
+
'padding-right': '0px',
|
63
|
+
'font-size': 'normal',
|
64
|
+
'font-style': 'normal',
|
65
|
+
'font-variant': 'normal',
|
66
|
+
'font-weight': 'normal',
|
67
|
+
'line-height': 'normal',
|
68
|
+
'vertical-align': 'baseline',
|
69
|
+
'color': 'black',
|
70
|
+
'background-color': 'transparent'
|
71
|
+
}; // Need to reset borders, fonts etc.
|
72
|
+
for (var key in defaultStyles) {
|
73
|
+
if (!this.style[key])
|
74
|
+
this.style[key] = defaultStyles[key];
|
75
|
+
}
|
76
|
+
});
|
77
|
+
return element // return the jQuery object back for possible chaining
|
78
|
+
}
|
79
|
+
|
@@ -0,0 +1,212 @@
|
|
1
|
+
require 'widget_builder/constants'
|
2
|
+
require 'awesome_print'
|
3
|
+
require 'yui/compressor'
|
4
|
+
require 'premailer'
|
5
|
+
require 'sass'
|
6
|
+
require 'find'
|
7
|
+
|
8
|
+
module WidgetBuilder
|
9
|
+
|
10
|
+
# Creates a single Widget by passing in the path to the html, css, and js files.
|
11
|
+
class Widget
|
12
|
+
def initialize(html_path, css_path, js_path, options = {})
|
13
|
+
@html_path, @css_path, @js_path = html_path, css_path, js_path
|
14
|
+
|
15
|
+
defaults = { compress: true }
|
16
|
+
defaults.merge(options).each do |k, v|
|
17
|
+
instance_variable_set("@#{k}",v)
|
18
|
+
end
|
19
|
+
|
20
|
+
@html = html
|
21
|
+
@widget_name ||= widget_name # the widget name is either passed in as an option or extrapolated from the html
|
22
|
+
@href = href
|
23
|
+
|
24
|
+
@css = css
|
25
|
+
@js = js
|
26
|
+
end
|
27
|
+
|
28
|
+
def html
|
29
|
+
File.read @html_path
|
30
|
+
end
|
31
|
+
|
32
|
+
# Get the widget name from the class of the first div tag in the html
|
33
|
+
def widget_name
|
34
|
+
@html.match(/<div\s+?class=(['"])(\w+)(?:\s+\w*)*\1/i)[2]
|
35
|
+
end
|
36
|
+
|
37
|
+
def css
|
38
|
+
css = File.read @css_path # Reads the css or scss file
|
39
|
+
css_folder = File.dirname @css_path # Infers the css foler
|
40
|
+
|
41
|
+
# Scans the file for any @import rules and includes their content
|
42
|
+
css.scan(/(^\s*@import\s+(?:url[\( ])?(['"])([\w\.]+)\2.*;)/).each do |m|
|
43
|
+
Find.find(css_folder) do |path|
|
44
|
+
css.gsub!(m[0], File.read(path)) if path.match(m[2])
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Determines the suffics of the file
|
49
|
+
suffix = @css_path.split('.').last
|
50
|
+
if suffix == 'css' # Just return the css if it is a plain css file
|
51
|
+
css
|
52
|
+
elsif suffix =~ /^scss|sass$/ # handle Sass files with the Sass Engine
|
53
|
+
engine = Sass::Engine.new(css, syntax: suffix.to_sym)
|
54
|
+
engine.render # converts scss or sass to plain css
|
55
|
+
else
|
56
|
+
raise 'Invalid css format'
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def html_with_css
|
61
|
+
premailer = Premailer.new(@html, { with_html_string: true, remove_comments: true, css_string: @css })
|
62
|
+
html_with_css = premailer.to_inline_css # places all the css inline with the html code
|
63
|
+
html_with_css = WidgetBuilder.remove_excess_premailer_content(html_with_css) # cleans up excess styles
|
64
|
+
if @compress == true
|
65
|
+
WidgetBuilder.html_uglifier(html_with_css) # removes html comments and unnecessary spaces
|
66
|
+
else
|
67
|
+
html_with_css.gsub("\n", " \\\n") # returns the html as is but adds trailing backslashes after each line to allow the multiline string in JavaScript
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Properly formats the href for the widget a tag or returns '#' if not provided
|
72
|
+
def href
|
73
|
+
if href = @href
|
74
|
+
href.gsub!(/^http:\/\//, '') # removes leading http:// if present since it gets added in the next step
|
75
|
+
"http://#{href}"
|
76
|
+
else
|
77
|
+
'#'
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Generates the final js file with all included html & css
|
82
|
+
def js
|
83
|
+
js = File.read WidgetBuilder::WIDGET_LOADER_PATH # reads the widget_loader js
|
84
|
+
js.gsub!(/widget_name/, @widget_name) # adds the widget name to the js file
|
85
|
+
js.gsub!(/JAVASCRIPT_PLACEHOLDER/, File.read(@js_path)) # adds the custom js to the widget_loader js
|
86
|
+
js.gsub!(/HTML&CSS_PLACEHOLDER/, html_with_css) # includes the html & css
|
87
|
+
js.gsub!(/HREF_PLACEHOLDER/, @href) # adds the href to the js validateReference function
|
88
|
+
js.gsub!(/VALID_ATAG_PLACEHOLDER/, %Q{<a class="#{@widget_name}" href="#{@href}"></a>})
|
89
|
+
if @compress == true
|
90
|
+
YUI::JavaScriptCompressor.new(munge: true).compress(js) # uglifies the combined javascript
|
91
|
+
else
|
92
|
+
js # Otherwise returns the raw non-minified javascript
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Saves the final js file to the specified path
|
97
|
+
def save(path = File.dirname(@js_path))
|
98
|
+
new_js_path = File.join(path, @widget_name + '.js')
|
99
|
+
File.open(new_js_path, 'w') do |f|
|
100
|
+
f.write @js
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def show_snippet
|
105
|
+
# Properly format or generate the javascript widget src path
|
106
|
+
if source_path = @source_path
|
107
|
+
source_path.gsub!(/^http:\/\//, '') # removes leading http:// if present since it gets added later
|
108
|
+
source_path.gsub!(/\/$/, '') # removes trailing slash if present since it gets added later
|
109
|
+
else
|
110
|
+
source_path = 'SOURCE_PATH_PLACEHOLDER'
|
111
|
+
ap "NOTE: Make sure to replace the #{source_path} in the code snippet below.", color: {string: :redish}
|
112
|
+
end
|
113
|
+
|
114
|
+
ap "------------ Copy the following HTML snippet to display the widget. -------------", color: {string: :cyanish}
|
115
|
+
puts %Q{<a class="#{@widget_name}" href="#{@href}"></a>
|
116
|
+
<script type="text/javascript">
|
117
|
+
var element = document.createElement('script');
|
118
|
+
element.type = 'text/javascript';
|
119
|
+
element.src = 'http://#{source_path}/#{@widget_name}.js';
|
120
|
+
document.getElementsByTagName('head')[0].appendChild(element);
|
121
|
+
</script>}
|
122
|
+
ap "---------------------------------------------------------------------------------", color: {string: :cyanish}
|
123
|
+
end
|
124
|
+
|
125
|
+
# Outputs a nice report on the console
|
126
|
+
def report
|
127
|
+
puts
|
128
|
+
ap "Widget name: #{@widget_name}", color: {string: :redish}
|
129
|
+
ap "HTML Template: #{@html_path.split('/').last}", color: {string: :greenish}
|
130
|
+
ap "Javascript reference: #{@js_path.split('/').last}", color: {string: :greenish}
|
131
|
+
ap "Stylesheet reference: #{@css_path.split('/').last}", color: {string: :greenish}
|
132
|
+
ap "HTML with CSS:"
|
133
|
+
puts html_with_css
|
134
|
+
ap "Final Compilation of the JS File (includes html, css, and js):", color: {string: :greenish}
|
135
|
+
puts @js
|
136
|
+
show_snippet
|
137
|
+
end
|
138
|
+
|
139
|
+
def compile(path = File.dirname(@js_path))
|
140
|
+
save(path)
|
141
|
+
report
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
# Crates an array of Widgets by passing in the paths to the html, css, and js directories
|
146
|
+
class Widgets
|
147
|
+
def initialize(html_path = '.', css_path = '.', js_path = '.', options = {})
|
148
|
+
@html_path, @css_path, @js_path, @options = html_path, css_path, js_path, options
|
149
|
+
@widgets = widgets
|
150
|
+
end
|
151
|
+
|
152
|
+
def widgets
|
153
|
+
widgets = []
|
154
|
+
Dir.foreach(@html_path) do |file| # read all the files in the 'Widget html' directory
|
155
|
+
if (file.match(/\.html$/)) # only consider html files for now
|
156
|
+
html_path = File.join(@html_path, file)
|
157
|
+
|
158
|
+
# HTML, CSS, and JS files should have the same name but different extensions
|
159
|
+
filename = file.gsub('.html', '')
|
160
|
+
|
161
|
+
css_path = ''
|
162
|
+
Find.find(@css_path) do |path|
|
163
|
+
css_path = path if path.split('/').last.match(/^#{filename}.*?\.(?:css|scss|sass)$/)
|
164
|
+
end
|
165
|
+
|
166
|
+
js_path = ''
|
167
|
+
Find.find(@js_path) do |path|
|
168
|
+
js_path = path if path.split('/').last.match(/^#{filename}\.js$/) # NOTE: Needs to add CoffeeScript support
|
169
|
+
end
|
170
|
+
widgets << WidgetBuilder::Widget.new(html_path, css_path, js_path, @options)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
widgets
|
174
|
+
end
|
175
|
+
|
176
|
+
def save(path = @js_path)
|
177
|
+
widgets.each { |widget| widget.save(path) }
|
178
|
+
end
|
179
|
+
|
180
|
+
def report
|
181
|
+
widgets.each { |widget| widget.report }
|
182
|
+
end
|
183
|
+
|
184
|
+
def compile(path = File.dirname(@js_path))
|
185
|
+
widgets.each { |widget| widget.compile(path) }
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
# Utility methods
|
190
|
+
private
|
191
|
+
|
192
|
+
# removes styles that were added by default with the pre-mailer gem
|
193
|
+
def self.remove_excess_premailer_content(html)
|
194
|
+
html = html.gsub(/^.*?<body.*?>(.*?)<\/body>.*$/m,'\1') # removes created html and body tags
|
195
|
+
html = html.gsub(/\s*font-size:\s*normal\s*;\s*/, '')
|
196
|
+
html = html.gsub(/\s*font-style:\s*normal\s*;\s*/, '')
|
197
|
+
html = html.gsub(/\s*font-variant:\s*normal\s*;\s*/, '')
|
198
|
+
html = html.gsub(/\s*line-height:\s*normal\s*;\s*/, '')
|
199
|
+
html = html.gsub(/\s*font-weight:\s*normal\s*;\s*/, '')
|
200
|
+
end
|
201
|
+
|
202
|
+
# removes html comments and unnecessary spaces
|
203
|
+
def self.html_uglifier(html)
|
204
|
+
html = html.gsub(/<!--.*?-->/m, '') # remove html comments
|
205
|
+
html = html.gsub(/[\n\r\t]/m, '') # remove new lines, line returns, and tabs
|
206
|
+
html = html.gsub(/>\s+?</m, '><') # remove excess whitespace between tags
|
207
|
+
html = html.gsub(/\s+?/m, ' ') # remove excess whitespace between elements
|
208
|
+
html = html.gsub(/<\s+?/m, '<') # remove excess whitespace after <
|
209
|
+
html = html.gsub(/\s+?>/m, '>') # remove excess whitespace before >
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'widget_builder'
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'widget_builder/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "widget_builder"
|
8
|
+
spec.version = WidgetBuilder::VERSION
|
9
|
+
spec.authors = ["Endri Gjiri"]
|
10
|
+
spec.email = ["egjiri@gmail.com"]
|
11
|
+
spec.description = %q{A widget builder tool}
|
12
|
+
spec.summary = %q{WidgetBuilder}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
spec.add_development_dependency "rspec"
|
24
|
+
spec.add_dependency "awesome_print"
|
25
|
+
spec.add_dependency "sass"
|
26
|
+
spec.add_dependency "yui-compressor"
|
27
|
+
spec.add_dependency "premailer"
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,158 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: widget_builder
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0.alpha
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Endri Gjiri
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-05-24 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: awesome_print
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: sass
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: yui-compressor
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: premailer
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
description: A widget builder tool
|
112
|
+
email:
|
113
|
+
- egjiri@gmail.com
|
114
|
+
executables: []
|
115
|
+
extensions: []
|
116
|
+
extra_rdoc_files: []
|
117
|
+
files:
|
118
|
+
- .gitignore
|
119
|
+
- .rspec
|
120
|
+
- CHANGELOG.md
|
121
|
+
- Gemfile
|
122
|
+
- LICENSE.txt
|
123
|
+
- README.md
|
124
|
+
- Rakefile
|
125
|
+
- app/assets/javascripts/widget_loader.js
|
126
|
+
- lib/widget_builder.rb
|
127
|
+
- lib/widget_builder/constants.rb
|
128
|
+
- lib/widget_builder/version.rb
|
129
|
+
- spec/spec_helper.rb
|
130
|
+
- spec/widget_builder_spec.rb
|
131
|
+
- widget_builder.gemspec
|
132
|
+
homepage: ''
|
133
|
+
licenses:
|
134
|
+
- MIT
|
135
|
+
metadata: {}
|
136
|
+
post_install_message:
|
137
|
+
rdoc_options: []
|
138
|
+
require_paths:
|
139
|
+
- lib
|
140
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - '>='
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '0'
|
145
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
146
|
+
requirements:
|
147
|
+
- - '>'
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: 1.3.1
|
150
|
+
requirements: []
|
151
|
+
rubyforge_project:
|
152
|
+
rubygems_version: 2.0.3
|
153
|
+
signing_key:
|
154
|
+
specification_version: 4
|
155
|
+
summary: WidgetBuilder
|
156
|
+
test_files:
|
157
|
+
- spec/spec_helper.rb
|
158
|
+
- spec/widget_builder_spec.rb
|