rails_blocks 0.5.4.pre.alpha.pre.2

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.
Files changed (66) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +15 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +10 -0
  5. data/Gemfile +10 -0
  6. data/Guardfile +43 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +31 -0
  9. data/Rakefile +12 -0
  10. data/app/assets/javascripts/block.coffee +98 -0
  11. data/app/assets/javascripts/jblocks.coffee +95 -0
  12. data/app/assets/javascripts/jquery_bem.coffee +4 -0
  13. data/app/assets/javascripts/jquery_bem_copy.coffee +486 -0
  14. data/app/assets/javascripts/main.coffee +10 -0
  15. data/app/assets/javascripts/rails_blocks.js +5 -0
  16. data/app/assets/stylesheets/rails_blocks.sass +94 -0
  17. data/app/helpers/block_helper.rb +122 -0
  18. data/app/views/rails_blocks/element.slim +2 -0
  19. data/coffeelint.json +12 -0
  20. data/config/spring.rb +1 -0
  21. data/config.ru +7 -0
  22. data/lib/rails_blocks/blocks/block.rb +28 -0
  23. data/lib/rails_blocks/blocks/element.rb +6 -0
  24. data/lib/rails_blocks/blocks/renderer.rb +13 -0
  25. data/lib/rails_blocks/configuration.rb +27 -0
  26. data/lib/rails_blocks/engine.rb +29 -0
  27. data/lib/rails_blocks/exceptions.rb +4 -0
  28. data/lib/rails_blocks/initializers/rails_blocks.rb +0 -0
  29. data/lib/rails_blocks/levels.rb +7 -0
  30. data/lib/rails_blocks/names.rb +60 -0
  31. data/lib/rails_blocks/path.rb +108 -0
  32. data/lib/rails_blocks/version.rb +3 -0
  33. data/lib/rails_blocks.rb +24 -0
  34. data/lib/tasks/rails_blocks.rake +8 -0
  35. data/rails_blocks.gemspec +39 -0
  36. data/spec/helpers/block_helper_spec.rb +58 -0
  37. data/spec/internal/app/blocks/app/block3/_mod1.slim +0 -0
  38. data/spec/internal/app/blocks/app/block3/_mod2_value2.slim +0 -0
  39. data/spec/internal/app/blocks/app/block3/block3.slim +0 -0
  40. data/spec/internal/app/blocks/common/block1/_mod1.slim +0 -0
  41. data/spec/internal/app/blocks/common/block1/_mod2_value2.slim +0 -0
  42. data/spec/internal/app/blocks/common/block1/block1.slim +2 -0
  43. data/spec/internal/app/blocks/common/block2/__elem1.slim +0 -0
  44. data/spec/internal/app/blocks/common/block2/__elem1_mod1.slim +0 -0
  45. data/spec/internal/app/blocks/common/block2/__elem1_mod2_val2.slim +0 -0
  46. data/spec/internal/app/blocks/common/block2/block2.slim +0 -0
  47. data/spec/internal/app/blocks/common/block3/_mod1.slim +0 -0
  48. data/spec/internal/app/blocks/common/block3/_mod2_value2.slim +0 -0
  49. data/spec/internal/app/blocks/common/block3/block3.slim +0 -0
  50. data/spec/internal/app/controllers/admin/admin_test_controller.rb +2 -0
  51. data/spec/internal/app/controllers/admin_controller.rb +2 -0
  52. data/spec/internal/app/controllers/application_controller.rb +2 -0
  53. data/spec/internal/config/database.yml +3 -0
  54. data/spec/internal/config/initializers/rails_blocks.rb +7 -0
  55. data/spec/internal/config/routes.rb +3 -0
  56. data/spec/internal/db/schema.rb +3 -0
  57. data/spec/internal/log/.gitignore +1 -0
  58. data/spec/internal/log/test.log +8 -0
  59. data/spec/internal/public/favicon.ico +0 -0
  60. data/spec/rails_blocks/blocks/block_spec.rb +11 -0
  61. data/spec/rails_blocks/configuration_spec.rb +29 -0
  62. data/spec/rails_blocks/names_spec.rb +66 -0
  63. data/spec/rails_blocks/path_spec.rb +70 -0
  64. data/spec/rails_blocks_spec.rb +104 -0
  65. data/spec/spec_helper.rb +112 -0
  66. metadata +368 -0
@@ -0,0 +1,486 @@
1
+ ### @required jQuery ###
2
+
3
+ (($) ->
4
+
5
+ ###*
6
+ # Base BEM class.
7
+ # @constructor
8
+ ###
9
+
10
+ BEM = (config) ->
11
+
12
+ ###*
13
+ # Default configuration.
14
+ # @type {Object}
15
+ ###
16
+
17
+ @config = config or {}
18
+ @blockClassRe = @buildBlockClassRe()
19
+ @elemClassRe = @buildElemClassRe()
20
+ @modClassRe = @buildModClassRe()
21
+ return
22
+
23
+ ###*
24
+ # Get parent block of element.
25
+ # @public
26
+ #
27
+ # @param {Object} $this
28
+ # @return {Object}
29
+ ###
30
+
31
+ BEM::getBlock = ($this) ->
32
+ blockClass = @getBlockClass($this)
33
+ block = $this.closest('.' + blockClass)
34
+ block.selector = blockClass
35
+ block
36
+
37
+ ###*
38
+ # Switch block context.
39
+ # @public
40
+ #
41
+ # @param {Object} $this
42
+ # @param {String} block
43
+ # @param {String} [elem]
44
+ # @return {Object}
45
+ ###
46
+
47
+ BEM::switchBlock = ($this, block, elem) ->
48
+ `var elem`
49
+ elem = elem or null
50
+ if elem then ($this.selector = @buildSelector(
51
+ block: block
52
+ elem: elem)) else ($this.selector = @buildSelector(block: block))
53
+ $this
54
+
55
+ ###*
56
+ # Find element in block.
57
+ # @public
58
+ #
59
+ # @param {Object} $this DOM element
60
+ # @param {String} elemKey Element name
61
+ # @return {Object}
62
+ ###
63
+
64
+ BEM::findElem = ($this, elemKey) ->
65
+ blockClass = @getBlockClass($this)
66
+ elemName = @buildElemClass(blockClass, elemKey)
67
+ elem = $this.find('.' + elemName)
68
+ elem
69
+
70
+ ###*
71
+ # Get value of modifier.
72
+ # @public
73
+ #
74
+ # @param {Object} $this
75
+ # @param {String} modKey
76
+ # @return {String}
77
+ ###
78
+
79
+ BEM::getMod = ($this, modKey) ->
80
+ mods = @extractMods($this.first())
81
+ if mods[modKey] != undefined
82
+ return mods[modKey]
83
+ null
84
+
85
+ ###*
86
+ # Check modifier of element.
87
+ # @public
88
+ #
89
+ # @param {Object} $this
90
+ # @param {String} modKey
91
+ # @param {String} [modVal]
92
+ # @return {Boolean}
93
+ ###
94
+
95
+ BEM::hasMod = ($this, modKey, modVal) ->
96
+ mods = @extractMods($this.first())
97
+ if modVal
98
+ if mods[modKey] == modVal
99
+ return true
100
+ else
101
+ if mods[modKey]
102
+ return true
103
+ false
104
+
105
+ ###*
106
+ # Set modifier on element.
107
+ # @public
108
+ #
109
+ # @param {Object} $this
110
+ # @param {String} modKey
111
+ # @param {String} [modVal]
112
+ # @param {Object}
113
+ ###
114
+
115
+ BEM::setMod = ($this, modKey, modVal) ->
116
+ self = this
117
+ selector = $this.selector
118
+ $this.each ->
119
+ current = $(this)
120
+ current.selector = selector
121
+ mods = self.extractMods(current)
122
+ baseName = self.getBaseClass(current)
123
+ if mods[modKey] != undefined
124
+ oldModName = self.buildModClass(baseName, modKey, mods[modKey])
125
+ current.removeClass oldModName
126
+ if modVal != false
127
+ newModName = self.buildModClass(baseName, modKey, modVal)
128
+ current.addClass(newModName).trigger 'setmod', [
129
+ modKey
130
+ modVal
131
+ ]
132
+ return
133
+ $this
134
+
135
+ ###*
136
+ # Delete modifier on element.
137
+ # @public
138
+ #
139
+ # @param {Object} $this
140
+ # @param {String} modKey
141
+ # @param {String} [modVal]
142
+ # @param {Object}
143
+ ###
144
+
145
+ BEM::delMod = ($this, modKey, modVal) ->
146
+ self = this
147
+ selector = $this.selector
148
+ $this.each ->
149
+ `var modName`
150
+ current = $(this)
151
+ current.selector = selector
152
+ mods = self.extractMods(current)
153
+ baseName = self.getBaseClass(current)
154
+ if modVal
155
+ if mods[modKey] == modVal
156
+ modName = self.buildModClass(baseName, modKey, mods[modKey])
157
+ else
158
+ modName = self.buildModClass(baseName, modKey, mods[modKey])
159
+ current.removeClass(modName).trigger 'delmod', [
160
+ modKey
161
+ modVal
162
+ ]
163
+ return
164
+ $this
165
+
166
+ ###*
167
+ # Filtering elements by modifier.
168
+ # @public
169
+ #
170
+ # @param {Object} $this
171
+ # @param {String} modKey
172
+ # @param {String} [modVal]
173
+ # @param {Boolean} [inverse]
174
+ # @return {Object}
175
+ ###
176
+
177
+ BEM::byMod = ($this, modKey, modVal, inverse) ->
178
+ `var inverse`
179
+ `var modVal`
180
+ self = this
181
+ modVal = modVal or null
182
+ inverse = inverse or false
183
+ selector = $this.selector
184
+ result = $()
185
+ $this.each ->
186
+ `var modName`
187
+ current = $(this)
188
+ current.selector = selector
189
+ mods = self.extractMods(current)
190
+ baseName = self.getBaseClass(current)
191
+ if modVal
192
+ if mods[modKey] == modVal
193
+ modName = self.buildModClass(baseName, modKey, mods[modKey])
194
+ else
195
+ if mods[modKey] != undefined
196
+ modName = self.buildModClass(baseName, modKey, mods[modKey])
197
+ result = result.add(if inverse then current.not('.' + modName) else current.filter('.' + modName))
198
+ return
199
+ result.selector = selector
200
+ result
201
+
202
+ ###*
203
+ # Get block names from element.
204
+ # @protected
205
+ #
206
+ # @param {Object|String} $this
207
+ # @return {Object}
208
+ ###
209
+
210
+ BEM::extractBlocks = ($this) ->
211
+ self = this
212
+ result = []
213
+ selectors = @getClasses($this)
214
+ $.each selectors, (i, sel) ->
215
+ type = self.getClassType(sel)
216
+ if type == 'block'
217
+ result.push sel
218
+ else if type == 'elem'
219
+ elem = sel.split(self.config.elemPrefix)
220
+ result.push elem[0]
221
+ return
222
+ result
223
+
224
+ ###*
225
+ # Get element names from element.
226
+ # @protected
227
+ #
228
+ # @param {Object} $this
229
+ # @return {Object}
230
+ ###
231
+
232
+ BEM::extractElems = ($this) ->
233
+ self = this
234
+ result = []
235
+ $.each self.getClasses($this), (i, className) ->
236
+ if self.getClassType(className) == 'elem'
237
+ elemName = className.split(self.config.elemPrefix)
238
+ result.push elemName[1]
239
+ return
240
+ result
241
+
242
+ ###*
243
+ # Get modifiers from element.
244
+ # @protected
245
+ #
246
+ # @param {Object} $this
247
+ # @return {Object}
248
+ ###
249
+
250
+ BEM::extractMods = ($this) ->
251
+ self = this
252
+ result = {}
253
+ $this.each ->
254
+ `var $this`
255
+ $this = $(this)
256
+ $.each self.getClasses($this), (i, className) ->
257
+ `var modVal`
258
+ if self.getClassType(className) == 'mod'
259
+ re = self.buildModClassRe().exec(className)
260
+ modName = re[1].split(self.config.modDlmtr)
261
+ if modName[1] != undefined and modName[1] != false
262
+ modVal = modName[1]
263
+ else
264
+ modVal = true
265
+ result[modName[0]] = modVal
266
+ return
267
+ return
268
+ result
269
+
270
+ ###*
271
+ # Get classes names from element.
272
+ # @protected
273
+ #
274
+ # @param {Object} $this
275
+ # @return {Object}
276
+ ###
277
+
278
+ BEM::getClasses = ($this) ->
279
+ classes = undefined
280
+ result = []
281
+ if typeof $this == 'object'
282
+ if $this.selector.indexOf('.') == 0
283
+ classes = $this.selector.split('.')
284
+ else if $this.attr('class') != undefined
285
+ classes = $this.attr('class').split(' ')
286
+ else
287
+ return null
288
+ else
289
+ classes = $this.split('.')
290
+ $.each classes, (i, className) ->
291
+ if className != ''
292
+ result.push $.trim(className)
293
+ return
294
+ result
295
+
296
+ ###*
297
+ # Build regexp for blocks.
298
+ # @protected
299
+ #
300
+ # @return {RegExp}
301
+ ###
302
+
303
+ BEM::buildBlockClassRe = ->
304
+ new RegExp('^(' + @config.namePattern + ')$')
305
+
306
+ ###*
307
+ # Build regexp for elements.
308
+ # @protected
309
+ #
310
+ # @return {RegExp}
311
+ ###
312
+
313
+ BEM::buildElemClassRe = ->
314
+ new RegExp('^' + @config.namePattern + @config.elemPrefix + '(' + @config.namePattern + ')$')
315
+
316
+ ###*
317
+ # Build regexp for modifiers.
318
+ # @protected
319
+ #
320
+ # @return {RegExp}
321
+ ###
322
+
323
+ BEM::buildModClassRe = ->
324
+ new RegExp('^(?:' + @config.namePattern + '|' + @config.namePattern + @config.elemPrefix + @config.namePattern + ')' + @config.modPrefix + '(' + @config.namePattern + '((' + @config.modDlmtr + @config.namePattern + ')$|$))')
325
+
326
+ ###*
327
+ # Build class name for block.
328
+ # @protected
329
+ #
330
+ # @param {String} blockName
331
+ # @return {String}
332
+ ###
333
+
334
+ BEM::buildBlockClass = (blockName) ->
335
+ @config.blockPrefix + blockName
336
+
337
+ ###*
338
+ # Build class name for element.
339
+ # @protected
340
+ #
341
+ # @param {String} blockName
342
+ # @param {String} elemKey
343
+ # @return {String}
344
+ ###
345
+
346
+ BEM::buildElemClass = (blockName, elemKey) ->
347
+ blockName + @config.elemPrefix + elemKey
348
+
349
+ ###*
350
+ # Build class name for modifier.
351
+ # @protected
352
+ #
353
+ # @param {String} blockName
354
+ # @param {String} modKey
355
+ # @param {String} modVal
356
+ # @return {String}
357
+ ###
358
+
359
+ BEM::buildModClass = (baseClass, modKey, modVal) ->
360
+ if modVal != undefined and modVal != true
361
+ baseClass + @config.modPrefix + modKey + @config.modDlmtr + modVal
362
+ else
363
+ baseClass + @config.modPrefix + modKey
364
+
365
+ ###*
366
+ # Build selector from object or string.
367
+ # @private
368
+ #
369
+ # @param {String|Object}
370
+ # @param {String}
371
+ # @return {String}
372
+ ###
373
+
374
+ BEM::buildSelector = (selector, prefix) ->
375
+ `var prefix`
376
+ if prefix != ''
377
+ prefix = prefix or '.'
378
+ if typeof selector == 'object'
379
+ if selector.block != undefined
380
+ buildSelector = @buildBlockClass(selector.block)
381
+ if selector.elem != undefined
382
+ buildSelector = @buildElemClass(buildSelector, selector.elem)
383
+ if selector.mod != undefined
384
+ mod = selector.mod.split(':')
385
+ buildSelector = @buildModClass(buildSelector, mod[0], mod[1])
386
+ if buildSelector != undefined then prefix + buildSelector else prefix + selector
387
+
388
+ ###*
389
+ # Build class name for block.
390
+ # @protected
391
+ #
392
+ # @param {Object|String} $this
393
+ # @param {Number} [index]
394
+ # @return {String}
395
+ ###
396
+
397
+ BEM::getBlockClass = ($this, index) ->
398
+ `var index`
399
+ blockClasses = @extractBlocks($this)
400
+ index = index or 0
401
+ if index <= blockClasses.length - 1 then blockClasses[index] else null
402
+
403
+ ###*
404
+ # Get base class from element.
405
+ # @protected
406
+ #
407
+ # @param {Object} $this
408
+ # @return {String}
409
+ ###
410
+
411
+ BEM::getBaseClass = ($this) ->
412
+ self = this
413
+ baseClass = null
414
+ selectors = @getClasses($this)
415
+ $.each selectors, (i, sel) ->
416
+ classType = self.getClassType(sel)
417
+ if classType and classType != 'mod'
418
+ baseClass = sel
419
+ return
420
+ baseClass
421
+
422
+ ###*
423
+ # Get class type.
424
+ # @protected
425
+ #
426
+ # @param {String} className
427
+ # @return {String}
428
+ ###
429
+
430
+ BEM::getClassType = (className) ->
431
+ if @modClassRe.test(className)
432
+ return 'mod'
433
+ else if @elemClassRe.test(className)
434
+ return 'elem'
435
+ else if @blockClassRe.test(className)
436
+ return 'block'
437
+ null
438
+
439
+ ###*
440
+ # Create BEM instance.
441
+ ###
442
+
443
+ $.BEM = new BEM(
444
+ namePattern: '[a-zA-Z0-9-]+'
445
+ blockPrefix: 'b-'
446
+ elemPrefix: '__'
447
+ modPrefix: '--'
448
+ modDlmtr: '_')
449
+
450
+ ###*
451
+ # Extend jQuery object.
452
+ ###
453
+
454
+ $.fn.extend
455
+ block: ->
456
+ $.BEM.getBlock this
457
+ elem: (elemKey) ->
458
+ $.BEM.findElem this, elemKey
459
+ ctx: (block, elem) ->
460
+ $.BEM.switchBlock this, block, elem
461
+ mod: (modKey, modVal) ->
462
+ if typeof modVal == 'undefined'
463
+ modVal = null
464
+ if modVal == false
465
+ return $.BEM.delMod(this, modKey)
466
+ if modVal != null
467
+ $.BEM.setMod(this, modKey, modVal)
468
+ else
469
+ $.BEM.getMod(this, modKey)
470
+ setMod: (modKey, modVal) ->
471
+ $.BEM.setMod this, modKey, modVal
472
+ delMod: (modKey, modVal) ->
473
+ $.BEM.delMod this, modKey, modVal
474
+ hasMod: (modKey, modVal) ->
475
+ $.BEM.hasMod this, modKey, modVal
476
+ byMod: (modKey, modVal) ->
477
+ $.BEM.byMod this, modKey, modVal
478
+ byNotMod: (modKey, modVal) ->
479
+ $.BEM.byMod this, modKey, modVal, 'inverse'
480
+ toggleMod: (modKey, modVal1, modVal2) ->
481
+ if @hasMod(modKey, modVal1)
482
+ @delMod(modKey, modVal1).setMod modKey, modVal2
483
+ else
484
+ @delMod(modKey, modVal2).setMod modKey, modVal1
485
+ return
486
+ ) jQuery
@@ -0,0 +1,10 @@
1
+ $ ->
2
+ # $.extend $,
3
+ # RB:
4
+ # blocks: {}
5
+ # decl: (name, options) ->
6
+ # block = @createBlockDeclaration(name, options)
7
+ # if(options['init'] != undefined)
8
+ # options['init'].call(block)
9
+ # createBlockDeclaration: (name, options) ->
10
+ # return new Block name, options
@@ -0,0 +1,5 @@
1
+ //require 'jquery_bem_copy'
2
+ //=require 'jquery_bem'
3
+ //=require 'block'
4
+ //=require 'jblocks'
5
+ //=require 'main'
@@ -0,0 +1,94 @@
1
+ $bemBlockPrefix: 'b-'
2
+ $bemElementSeparator: '__'
3
+ $bemModifierSeparator: '--'
4
+
5
+ @function b-class($block)
6
+ @return ".#{$bemBlockPrefix+$block}"
7
+
8
+ @function selectorToString($selector)
9
+ $selector: inspect($selector) //cast to string
10
+ $selector: str-slice($selector, 2, -2) //remove bracket
11
+ @return $selector
12
+
13
+ @function containsModifier($selector)
14
+ $selector: selectorToString($selector)
15
+ @if str-index($selector, $bemModifierSeparator)
16
+ @return true
17
+ @else
18
+ @return false
19
+
20
+ @function containsPseudo($selector)
21
+ $selector: selectorToString($selector)
22
+ @if str-index($selector, ':')
23
+ @return true
24
+ @else
25
+ @return false
26
+
27
+ @function containsElement($selector)
28
+ $selector: selectorToString($selector)
29
+ @if str-index($selector, $bemElementSeparator)
30
+ @return true
31
+ @else
32
+ @return false
33
+
34
+ @function getBlock($selector)
35
+ $selector: selectorToString($selector)
36
+ $elementStart: str-index($selector, $bemElementSeparator)
37
+ $modifierStart: str-index($selector, $bemModifierSeparator)
38
+ $pseudoStart: str-index($selector, ':')
39
+ $start: if($elementStart, $elementStart - 1, if($modifierStart, $modifierStart - 1, $pseudoStart - 1))
40
+ @return str-slice($selector, 0, $start)
41
+
42
+ =b($block)
43
+ .#{$bemBlockPrefix+$block}
44
+ @content
45
+
46
+ =plus_b
47
+ @at-root
48
+ $block: &
49
+ #{$block} + #{$block}
50
+ @content
51
+
52
+ =hover_b
53
+ @at-root
54
+ $block: &
55
+ #{$block}:hover
56
+ @content
57
+
58
+ =e($element)
59
+ $selector: &
60
+ @at-root
61
+ @if containsModifier($selector) or containsPseudo($selector)
62
+ $block: getBlock($selector)
63
+ #{$selector}
64
+ #{$block+$bemElementSeparator+$element}
65
+ @content
66
+ @else
67
+ #{$selector+$bemElementSeparator+$element}
68
+ @content
69
+
70
+ =es($elements...)
71
+ @each $element in $elements
72
+ +e($element)
73
+ @content
74
+
75
+ =m($modifier)
76
+ @at-root
77
+ #{&}#{$bemModifierSeparator+$modifier}
78
+ @content
79
+
80
+ =icons-m($modifiers, $width, $height)
81
+ @for $i from 1 through length($modifiers)
82
+ +m(nth($modifiers, $i))
83
+ background-position: -($i - 1) * $width (0)
84
+ &:hover
85
+ background-position: -($i - 1)*$width (-$height)
86
+ &:active
87
+ background-position: -($i - 1) * $width (-2 * $height)
88
+
89
+ @function block-image-url($level, $image)
90
+ $selector: &
91
+ $selector: selectorToString($selector)
92
+ $block: if(containsModifier($selector) or containsPseudo($selector) or containsElement($selector), getBlock($selector), selectorToString($selector))
93
+ $block: str-slice($block, str-length($bemBlockPrefix) + 1)
94
+ @return image-url("#{$level}/#{$block}/images/#{$image}")
@@ -0,0 +1,122 @@
1
+ require 'rails_blocks/names'
2
+ require 'rails_blocks/path'
3
+
4
+ module BlockHelper
5
+ include RailsBlocks::Path
6
+ include RailsBlocks::Names
7
+
8
+ BEM_KEYS = [:tag, :class, :attrs, :mods, :mix, :data, :levels, :content]
9
+
10
+ def bem_page(options, &block)
11
+ @page_options = options
12
+ block_given? ? capture(&block) : ''
13
+ end
14
+
15
+ def page_options
16
+ defaults = {
17
+ levels: RailsBlocks.config.levels
18
+ }
19
+ defaults.merge @page_options || {}
20
+ end
21
+
22
+ #TODO бога ради, отрефактори это дерьмо
23
+ def b(b_name, options = {}, &block)
24
+ parent_block = context_block
25
+ push_context_block b_name
26
+ options = page_options.merge options
27
+ options[:parent_block] = parent_block if parent_block
28
+ template = block_template b_name, options
29
+ classes = block_classes b_name, options
30
+
31
+ result = element(classes, template, options, &block)
32
+ pop_context_block
33
+ result
34
+ end
35
+
36
+ def b_classes(b_name, options = {})
37
+ parent_block = context_block
38
+ push_context_block b_name
39
+ options = page_options.merge options
40
+ options[:parent_block] = parent_block if parent_block
41
+ classes = block_classes b_name, options
42
+ pop_context_block
43
+ classes
44
+ end
45
+
46
+ def b_context(b_name, &block)
47
+ push_context_block b_name
48
+ result = capture(&block)
49
+ pop_context_block
50
+ result
51
+ end
52
+
53
+ def e(e_name, options = {}, &block)
54
+ parent_block = options[:b] || context_block
55
+ raise RailsBlocks::NoBlockContextError unless parent_block
56
+ options = page_options.merge options
57
+ options[:parent_block] = parent_block
58
+ template = element_template parent_block, e_name, options
59
+ classes = element_classes(parent_block, e_name, options)
60
+ element(classes, template, options, &block)
61
+ end
62
+
63
+ def e_classes(e_name, options = {})
64
+ parent_block = options[:b] || context_block
65
+ raise RailsBlocks::NoBlockContextError unless parent_block
66
+ options = page_options.merge options
67
+ options[:parent_block] = parent_block
68
+ element_classes(parent_block, e_name, options).join(' ')
69
+ end
70
+
71
+ def element(classes, template, options, &block)
72
+ content = block ? capture(&block) : options[:content]
73
+ @attrs = {class: classes.join(' ')}
74
+ @attrs.merge! options[:attrs] if options[:attrs]
75
+ @attrs["data-bem"] = options[:data].to_json if options[:data]
76
+ @attrs[:tag] = options[:tag] || 'div'
77
+
78
+ template.nil? ? empty(content) : render(file: template, locals: {content: content, options: options})
79
+ end
80
+
81
+ #убрать после тестов производительности
82
+ # def empty(content)
83
+ # atrrs = @attrs.except(:tag).map do |key, value|
84
+ # key.to_s + '=\'' + value.to_s + "'"
85
+ # end
86
+ # "<#{@attrs[:tag]} #{atrrs.join(' ')}>#{content}</#{@attrs[:tag]}>".html_safe
87
+ # end
88
+
89
+ def empty(content)
90
+ content_tag bem_tag, content, bem_attrs_without_tag
91
+ end
92
+
93
+ def bem_tag
94
+ @attrs[:tag]
95
+ end
96
+
97
+ def bem_attrs
98
+ @attrs
99
+ end
100
+
101
+ def bem_attrs_without_tag
102
+ @attrs.except :tag
103
+ end
104
+
105
+ private
106
+
107
+ def blocks_stack
108
+ @blocks_stack = @blocks_stack || []
109
+ end
110
+
111
+ def context_block
112
+ blocks_stack.last
113
+ end
114
+
115
+ def push_context_block(b_name)
116
+ blocks_stack.push b_name
117
+ end
118
+
119
+ def pop_context_block
120
+ blocks_stack.pop
121
+ end
122
+ end
@@ -0,0 +1,2 @@
1
+ *bem_attrs
2
+ = content