evil-blocks-rails 0.3.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/ChangeLog CHANGED
@@ -1,3 +1,6 @@
1
+ == 0.4 (X-Ray, 14th April 1948)
2
+ * Add new object style.
3
+
1
4
  == 0.3.2 (Helen of Bikini, 25th July 1946)
2
5
  * Fix searching elements inside several blocks (by Andrei Miroshnik).
3
6
 
data/README.md CHANGED
@@ -17,8 +17,8 @@ and [role-rails](https://github.com/kossnocorp/role-rails) by Sasha Koss.
17
17
  .gallery-control.is-big
18
18
  // Evil Blocks add @data-role alias to Slim
19
19
  // .class to bind styles, @data-role to bind JavaScript
20
- a.gallery-left@next-photo href="#"
21
- a.gallery-right@prev-photo href="#"
20
+ a.gallery-left@nextPhoto href="#"
21
+ a.gallery-right@prevPhoto href="#"
22
22
  img src="photos/1.jpg"
23
23
  img src="photos/2.jpg"
24
24
  img src="photos/3.jpg"
@@ -46,32 +46,29 @@ and [role-rails](https://github.com/kossnocorp/role-rails) by Sasha Koss.
46
46
  ### CoffeeScript
47
47
 
48
48
  ```coffee
49
- # Will execute callback only if .gallery-control is in current page
50
- evil.block '.gallery-control', ($, b, block) ->
51
- current = 0
52
- showPhoto = (num) ->
53
- # b-function finds only inside .gallery-control
54
- b('img').hide()
55
- b("img:eql(#{ num })").show()
56
-
57
- initState: ->
58
- showPhoto(current)
59
-
60
- buttons: ->
61
- # Shortcuts for data-role="next-photo"
62
- b.nextPhoto.click ->
63
- showPhoto(current += 1)
64
-
65
- slideShow: ->
49
+ # Will execute init only if .gallery-control is in current page
50
+ evil.block '.gallery-control',
51
+ current: 0
52
+
53
+ showPhoto: (num) ->
54
+ @('img').hide().
55
+ filter("eql(#{ num })").show()
56
+
57
+ init: ->
58
+ @showPhoto(@current)
59
+
60
+ 'click on @nextPhoto', (link, event) ->
61
+ @showPhoto(current += 1)
62
+
63
+ 'on start-slideshow', ->
66
64
  # You can communicate between blocks by simple events
67
- block.on 'slideshow-start', ->
68
- setTimeout( -> b.nextPhoto.click() , 5000)
65
+ setTimeout( => @nextPhoto.click() , 5000)
69
66
 
70
- # Will execute callback only on user page, where .user-page exists
71
- evil.block '.user-page', ($, b, block) ->
67
+ # Will execute init only on user page, where .user-page exists
68
+ evil.block '.user-page',
72
69
 
73
- startSlidehow: ->
74
- b('.gallery-control').trigger('slideshow-start')
70
+ init: ->
71
+ @('.gallery-control').trigger('start-slideshow')
75
72
  ```
76
73
 
77
74
  ## Styles
@@ -96,20 +93,19 @@ evil.block '.user-page', ($, b, block) ->
96
93
  * Unobtrusive JavaScript.
97
94
  * Write animation and states in CSS. JavaScript just changes CSS classes.
98
95
  * Avoid rendering. Send from server HTML, not JSON.
99
- * Wrap scrips to revive blocks in `evil.block(selector, callback)`.
100
- It will execute `callback` only if block `selector` exists in current page.
101
- So you can be free to join all JS files in one.
102
- * `evil.block` will send to `callback` three arguments: `$` is jQuery,
103
- `b` is “b-function”, `block` is blocks found by `selector`.
104
- * B-function is like jQuery function, but find only inside finded block
105
- (alias `b('a') = $('a', selector)`).
96
+ * Split JS by widgets. Describe widget class in `evil.block(selector, klass)`.
97
+ It will create `klass` instance and call `init` method for each selectors,
98
+ which exist in current page. So you can be free to join all JS files in one.
99
+ * Describe events by `EVENTS on SELECTORS` methods
100
+ (like `keyup submit on @name, @family`). This methods save this and
101
+ receive jQuery node in first argument and event in second.
106
102
  * Bind JavaScript to `data-role` attribute to be free to change styles
107
103
  and classes without dangeros of breaking scripts.
108
- * You can easy find special`data-role` by b-function. It will has properties
109
- for all roles inside block (`@role-name` will be camelized to `b.roleName`).
110
- * If `callback` return object, `evil-block` will execute all it methods.
111
- It’s useful to split your script to several initializer with separated
112
- variables scope.
104
+ * Every tag with `data-role` will by as property in object with jQuery node.
105
+ * If you need to find elements inside block, use `@(selector)` function.
106
+ * If you need to communicate between blocks, use custom events and create
107
+ block events listeners by `on EVENTS` method. It will receive events object
108
+ as first argument and event parameters as next arguments.
113
109
 
114
110
  ## Install
115
111
 
@@ -53,68 +53,166 @@
53
53
  }
54
54
 
55
55
  /**
56
- * Call `callback` only if `selector` was founded on page.
57
- * `callback` will receive 3 arguments:
58
- * * `$` - jQuery.
59
- * * `b` - like jQuery, but find only inside founded blocks.
60
- * * `block` - blocks, founded by `selector`.
56
+ * Evil blocks list.
57
+ */
58
+ var vitalizers = [];
59
+
60
+ /**
61
+ * If onready event is already happend.
62
+ */
63
+ var ready = false;
64
+
65
+ /**
66
+ * Execute `callback` on every finded `selector` inside `base`.
67
+ */
68
+ var vitalize = function (base, selector, callback) {
69
+ var blocks = $().add( base.filter(selector) ).
70
+ add( base.find(selector) );
71
+
72
+ if ( blocks.length == 0 ) {
73
+ return;
74
+ }
75
+
76
+ for ( var i = 0; i < blocks.length; i++ ) {
77
+ var block = $(blocks[i]);
78
+
79
+ var b = (function (block) {
80
+ return function (subselector) {
81
+ return $(subselector, block);
82
+ };
83
+ })(block);
84
+
85
+ var actives = { };
86
+ block.find('[data-role]').each(function (_, el) {
87
+ var roles = el.attributes['data-role'].value.split(' ');
88
+ for ( var i = 0; i < roles.length; i++ ) {
89
+ var role = roles[i].replace(/-\w/g, function (s) {
90
+ return s[1].toUpperCase();
91
+ });
92
+ if ( !actives[role] ) {
93
+ actives[role] = [];
94
+ }
95
+ actives[role].push(el);
96
+ }
97
+ });
98
+
99
+ for ( var role in actives ) {
100
+ b[role] = b(actives[role]);
101
+ }
102
+
103
+ var inits = callback($, b, block);
104
+ if ( typeof(inits) == 'object' ) {
105
+ for ( var init in inits ) {
106
+ inits[init]($, b, block);
107
+ }
108
+ }
109
+ }
110
+ };
111
+
112
+ /**
113
+ * Convert block class to callback.
114
+ */
115
+ var convert = function (klass) {
116
+ return function ($, obj, block) {
117
+ obj.block = block;
118
+
119
+ for ( var prop in klass ) {
120
+ (function (prop) {
121
+ if ( prop.indexOf('on ') != -1 ) {
122
+ var parts = prop.split(' on ');
123
+ if ( parts[1] ) {
124
+ block.on(parts[0], parts[1], function () {
125
+ var arg = Array.prototype.slice.call(arguments);
126
+ var el = $(this);
127
+ arg.unshift(el);
128
+ klass[prop].apply(obj, arg);
129
+ });
130
+ } else {
131
+ block.on(parts[0], function () {
132
+ klass[prop].apply(obj, arguments);
133
+ });
134
+ }
135
+ } else {
136
+ obj[prop] = klass[prop];
137
+ }
138
+ })(prop);
139
+ }
140
+
141
+ if ( typeof(obj.init) == 'function' ) {
142
+ obj.init();
143
+ }
144
+ }
145
+ }
146
+
147
+ /**
148
+ * Create object for every `selector` finded in page and call their
149
+ * `init` method.
150
+ *
151
+ * evil.block '.user-page .buttons',
152
+ * init: ->
153
+ * @gallery.fotorama()
154
+ * delete: ->
155
+ * @deleteForm.submit ->
156
+ * $('user-status').trigger('deleted')
157
+ * 'click on @deleleLink': (link) ->
158
+ * link.addClass('is-loading')
159
+ * delete()
160
+ * 'on update': ->
161
+ * location.reload()
61
162
  *
62
- * All elements with `data-role` will be add as property to `b`.
163
+ * Every `data-role="aName"` in HTML will create in object `aName` property
164
+ * with jQuery node.
63
165
  *
64
- * `callback` can return hash of inititalizer functions,
65
- * `evil.block` will execute them. It is good way to isolate variables
66
- * in separated initializers.
166
+ * To bind delegate listener just create `on EVENT on SELECTOR` method.
167
+ * In first argument it will receive jQuery node of `e.currentTarget`,
168
+ * second will be event object and others will be parameters.
67
169
  *
68
- * evil.block '.user-page', ($, b, block) ->
170
+ * To communicate between blocks, just trigget custom events. To receive
171
+ * events from another blocks, create `on EVENT` method. Event object will
172
+ * be on first argument here.
69
173
  *
70
- * editUser: ->
71
- * # Click on `data-role="edit"` inside `.user-page`
72
- * b.edit.click ->
73
- * b('.edit-form').show()
174
+ * Block node will be in `@block` property and you can search only inside
175
+ * block by `@(selector)` method.
74
176
  *
75
- * delUser: ->
76
- * b.del.click -> b('.delete-form').submit()
177
+ * If your block contrain only `init` method, you can use shortcut:
77
178
  *
78
- * initGallery: ->
79
- * b.gallery.fotorama()
179
+ * evil.block '.block', ->
180
+ * # init method
80
181
  */
81
- window.evil.block = function (selector, callback) {
82
- $(function () {
83
- var blocks = $(selector);
84
- for ( var i = 0; i < blocks.length; i++ ) {
85
- var block = $(blocks[i]);
86
-
87
- var b = (function (block) {
88
- return function (subselector) {
89
- return $(subselector, block);
90
- };
91
- })(block);
92
- var actives = { };
93
- block.find('[data-role]').each(function (_, el) {
94
- var roles = el.attributes['data-role'].value.split(' ');
95
- for ( var i = 0; i < roles.length; i++ ) {
96
- var role = roles[i].replace(/-\w/g, function (s) {
97
- return s[1].toUpperCase();
98
- });
99
- if ( !actives[role] ) {
100
- actives[role] = [];
101
- }
102
- actives[role].push(el);
103
- }
104
- });
182
+ window.evil.block = function (selector, vitalizer) {
183
+ if ( typeof(vitalizer) != 'function' ) {
184
+ vitalizer = convert(vitalizer)
185
+ }
186
+ vitalizers.push([selector, vitalizer]);
105
187
 
106
- for ( var role in actives ) {
107
- b[role] = $(actives[role]);
108
- }
188
+ if ( ready ) {
189
+ vitalize($(document), selector, vitalizer);
190
+ }
191
+ };
109
192
 
110
- var inits = callback($, b, block);
111
- if ( typeof(inits) == 'object' ) {
112
- for ( var init in inits ) {
113
- inits[init]($, b, block);
114
- }
115
- }
116
- }
117
- });
193
+ /**
194
+ * Vitalize all current blocks inside base. You must call it on every
195
+ * new content from AJAX.
196
+ *
197
+ * 'on click on @load': ->
198
+ * $.get '/comments', (comments) =>
199
+ * evil.block.vitalize $(comments).applyTo(@comments)
200
+ */
201
+ window.evil.block.vitalize = function (base) {
202
+ base = $(base);
203
+
204
+ for ( var i = 0; i < vitalizers.length; i++ ) {
205
+ var vitalizer = vitalizers[i];
206
+ vitalize(base, vitalizer[0], vitalizer[1]);
207
+ }
118
208
  };
119
209
 
210
+ /*
211
+ * Run all blocks on load.
212
+ */
213
+ $(document).ready(function () {
214
+ ready = true;
215
+ evil.block.vitalize(document);
216
+ });
217
+
120
218
  })(jQuery);
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: evil-blocks-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.4.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-06-25 00:00:00.000000000 Z
12
+ date: 2013-09-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sprockets