├── .gitignore ├── index.jade ├── index.pug ├── package.json ├── LICENSE ├── test ├── start.js ├── page.fix.html ├── page.pug ├── page.jade.html └── page.pug.html ├── core.pug ├── core.jade └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | Thumbs.db 4 | Desktop.ini 5 | .DS_Store* 6 | ehthumbs.db 7 | .npmignore -------------------------------------------------------------------------------- /index.jade: -------------------------------------------------------------------------------- 1 | 2 | 3 | //- Include core 4 | 5 | include core 6 | 7 | 8 | //- Element mixin 9 | 10 | mixin e( name, data, tag ) 11 | 12 | +b( name, data, tag )(isElement=true)&attributes(attributes): block 13 | 14 | 15 | //- Block mixin 16 | 17 | mixin b( name, data, tag ) 18 | 19 | - var myBlock = new BEMPUG.Block( name, data, tag, attributes ); 20 | 21 | - BEMPUG.addData( myBlock ); 22 | 23 | if myBlock.selfClosing 24 | 25 | #{myBlock.tag}(class=myBlock.classes)/&attributes(myBlock.attributes) 26 | 27 | else 28 | 29 | #{myBlock.tag}(class=myBlock.classes)&attributes(myBlock.attributes): block 30 | 31 | - BEMPUG.removeData( myBlock ); 32 | 33 | -------------------------------------------------------------------------------- /index.pug: -------------------------------------------------------------------------------- 1 | 2 | 3 | //- Include core 4 | 5 | include core 6 | 7 | 8 | //- Element mixin 9 | 10 | mixin e( name, data, tag ) 11 | 12 | +b( name, data, tag )(isElement=true)&attributes(attributes): block 13 | 14 | 15 | //- Block mixin 16 | 17 | mixin b( name, data, tag ) 18 | 19 | - var myBlock = new BEMPUG.Block( name, data, tag, attributes ); 20 | 21 | - BEMPUG.addData( myBlock ); 22 | 23 | if myBlock.selfClosing 24 | 25 | #{myBlock.tag}(class=myBlock.classes)&attributes(myBlock.attributes)/ 26 | 27 | else 28 | 29 | #{myBlock.tag}(class=myBlock.classes)&attributes(myBlock.attributes): block 30 | 31 | - BEMPUG.removeData( myBlock ); 32 | 33 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bempug", 3 | "version": "1.1.1", 4 | "description": "Simple mixins to help you writing code on BEM methodology in pug or jade projects.", 5 | "keywords": [ 6 | "pug", 7 | "jade", 8 | "bem", 9 | "mixins" 10 | ], 11 | "main": "index.pug", 12 | "scripts": { 13 | "test": "echo \"Error: no test specified\" && exit 1" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "git+https://github.com/werty1001/bempug.git" 18 | }, 19 | "author": "Oleg Krylov", 20 | "license": "MIT", 21 | "bugs": { 22 | "url": "https://github.com/werty1001/bempug/issues" 23 | }, 24 | "homepage": "https://github.com/werty1001/bempug#readme" 25 | } 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Oleg 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /test/start.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict'; 3 | 4 | (function() { 5 | 6 | let file = __dirname + '/page.pug'; 7 | 8 | let options = { 9 | pretty: '\t', 10 | doctype: 'html' 11 | }; 12 | 13 | try { 14 | 15 | var pug = require( 'pug' ); 16 | 17 | } catch( err ) { 18 | 19 | console.log( 'For Pug test you must install module [ npm i pug --save-dev ]' ); 20 | 21 | } 22 | 23 | try { 24 | 25 | var jade = require( 'jade' ); 26 | 27 | } catch( err ) { 28 | 29 | console.log( 'For Jade test you must install module [ npm i jade --save-dev ]' ); 30 | 31 | } 32 | 33 | if ( pug ) { 34 | 35 | let PugCompiled = pug.renderFile( file, options ); 36 | 37 | let selfClosing = ['img','input','hr','br','wbr','source','area','col','colgroup','meta','link']; 38 | 39 | let fixCompiled = PugCompiled.replace( /\/>/gi, '>' ).replace( /(<[A-Z][A-Z0-9]*\b[^>]*>)([^<>]*)(<\/[A-Z][A-Z0-9]*>)/gi, function(str, start, content, end) { 40 | 41 | let tag = start.replace( /<|>/gi, '' ).split( ' ' )[0]; 42 | 43 | return start + ( ( selfClosing.indexOf( tag ) === -1 ) ? content.trim() : content ) + end; 44 | }); 45 | 46 | require( 'fs' ).writeFileSync( __dirname + '/page.pug.html', PugCompiled + '', 'utf8' ); 47 | require( 'fs' ).writeFileSync( __dirname + '/page.fix.html', fixCompiled + '', 'utf8' ); 48 | 49 | } 50 | 51 | if ( jade ) { 52 | 53 | let JadeCompiled = jade.renderFile( file, options ); 54 | 55 | require( 'fs' ).writeFileSync( __dirname + '/page.jade.html', JadeCompiled + '', 'utf8' ); 56 | 57 | } 58 | 59 | })(); 60 | -------------------------------------------------------------------------------- /core.pug: -------------------------------------------------------------------------------- 1 | - 2 | const BEMPUG = { 3 | 4 | // bempug by Oleg Krylov [olegkrylov.pro] 5 | 6 | version: '1.1.1', 7 | 8 | tree: [], 9 | 10 | blocks: [], 11 | 12 | tagByName: {}, 13 | 14 | beforeParse: {}, 15 | 16 | afterParse: {}, 17 | 18 | tagByAttr: { href: 'a', alt: 'img', for: 'label' }, 19 | 20 | selfClosingTags: ['img','input','hr','br','wbr','source','area','col','colgroup'], 21 | 22 | forSpanTags: ['abbr','a','b','bdo','cite','dfn','em','i','kbd','q','s','span','sub','sup','samp','small','strong','u','var','mark','p','h1','h2','h3','h4','h5','h6','time','bdi','button','li','label'], 23 | 24 | isExternal: function( str ) { 25 | return /^(?:https?\:)?\/\//i.test( str ); 26 | }, 27 | 28 | isObject: function( obj ) { 29 | return ( typeof obj === 'object' && obj !== null && ! Array.isArray( obj ) ) ? true : false; 30 | }, 31 | 32 | isString: function( str ) { 33 | return ( str && typeof str === 'string' && !!str.trim() ) ? true : false; 34 | }, 35 | 36 | getCurrentBlock: function() { 37 | return this.blocks[ this.blocks.length - 1 ] || ''; 38 | }, 39 | 40 | getCurrentParent: function() { 41 | return this.tree[ this.tree.length - 1 ] || {}; 42 | }, 43 | 44 | addData: function( block ) { 45 | if ( block.type === 'block' ) this.blocks[ this.blocks.length ] = block.name; 46 | this.tree[ this.tree.length ] = block; 47 | }, 48 | 49 | removeData: function( block ) { 50 | if ( block.type === 'block' ) this.blocks.pop(); 51 | this.tree.pop(); 52 | }, 53 | 54 | blockProto: { 55 | 56 | setName: function( name, parent ) { 57 | 58 | var blockName = BEMPUG.isString( name ) ? name.trim() : false, 59 | parentName = BEMPUG.isString( parent ) ? parent.trim() : ( BEMPUG.getCurrentBlock() + '' ); 60 | 61 | if ( this.type === 'element' ) 62 | blockName = parentName + this.sep.element + ( blockName || 'element' ); 63 | 64 | this.name = ( blockName || 'block' ); 65 | this.classes.push( this.name ); 66 | 67 | return this; 68 | }, 69 | 70 | identifyTag: function( tag, name, attr ) { 71 | 72 | if ( BEMPUG.isString( tag ) ) return this.setTag( tag ); 73 | 74 | if ( name && BEMPUG.isString( BEMPUG.tagByName[ name ] ) ) { 75 | 76 | return this.setTag( BEMPUG.tagByName[ name ] ); 77 | } 78 | 79 | if ( attr.href || attr.alt || attr.for ) { 80 | 81 | var attribute = attr.href ? 'href' : ( attr.alt ? 'alt' : 'for' ); 82 | 83 | return this.setTag( BEMPUG.tagByAttr[ attribute ] ); 84 | } 85 | 86 | if ( this.parent.tag && this.parent.tag !== 'div' ) { 87 | 88 | if ( this.parent.tag === 'select' ) return this.setTag( 'option' ); 89 | 90 | if ( this.parent.tag === 'dl' ) return this.setTag( 'dd' ); 91 | 92 | if ( ['ul','ol'].indexOf( this.parent.tag ) !== -1 ) return this.setTag( 'li' ); 93 | 94 | if ( BEMPUG.forSpanTags.indexOf( this.parent.tag ) !== -1 ) return this.setTag( 'span' ); 95 | } 96 | 97 | return this.setTag( 'div' ); 98 | 99 | }, 100 | 101 | setTag: function( tag ) { 102 | 103 | if ( tag ) this.tag = tag.trim().toLowerCase(); 104 | 105 | this.selfClosing = ( BEMPUG.selfClosingTags.indexOf( this.tag ) !== -1 ); 106 | 107 | return this; 108 | 109 | }, 110 | 111 | setSeparators: function( sep ) { 112 | 113 | var separator = BEMPUG.isString( sep ) ? sep.split( '|' ) : [], 114 | modifier = separator[0] || ( this.parent.sep ? this.parent.sep.modifier : BEMPUG.modifier ), 115 | element = separator[1] || ( this.parent.sep ? this.parent.sep.element : BEMPUG.element ); 116 | 117 | this.sep.modifier = BEMPUG.isString( modifier ) ? modifier.trim() : '--'; 118 | this.sep.element = BEMPUG.isString( element ) ? element.trim() : '__'; 119 | 120 | return this; 121 | }, 122 | 123 | addModifier: function( mod, name ) { 124 | 125 | if ( ! BEMPUG.isString( mod ) ) return this; 126 | 127 | mod.split( '.' ).forEach( function( val ) { 128 | 129 | var blockName = BEMPUG.isString( name ) ? name.trim() : this.name, 130 | modifier = BEMPUG.isString( val ) ? val.trim() : false; 131 | 132 | if ( ! modifier || ! blockName ) return; 133 | 134 | this.classes.push( blockName + this.sep.modifier + modifier ); 135 | 136 | }, this); 137 | 138 | return this; 139 | 140 | }, 141 | 142 | addMix: function( data, isElementMix ) { 143 | 144 | if ( ! data ) return this; 145 | 146 | var array = Array.isArray( data ) ? data : [ data ]; 147 | 148 | array.forEach( function( val ) { 149 | 150 | var name, mix = ( val === true || val === 1 ) ? ( BEMPUG.getCurrentBlock() + '' ) : val; 151 | 152 | if ( ! BEMPUG.isString( mix ) ) return; 153 | 154 | name = mix.split( '|' )[0]; 155 | name = name.replace( '&', ( BEMPUG.getCurrentBlock() + '' ) ); 156 | 157 | if ( ! BEMPUG.isString( name ) ) return; 158 | 159 | name = name.trim(); 160 | 161 | if ( isElementMix ) { 162 | 163 | var elementOf = name.split( ':' )[0]; 164 | var elementName = name.split( ':' )[1]; 165 | 166 | if ( ! elementName ) 167 | elementName = this.type === 'element' ? this.name.split( this.sep.element )[1] : this.name; 168 | 169 | if ( ! ( BEMPUG.isString( elementOf ) && BEMPUG.isString( elementName ) ) ) return; 170 | 171 | name = elementOf.trim() + this.sep.element + elementName.trim(); 172 | } 173 | 174 | this.classes.push( name ); 175 | this.addModifier( mix.split( '|' )[1], name ); 176 | 177 | }, this); 178 | 179 | return this; 180 | 181 | } 182 | 183 | }, 184 | 185 | Block: function( name, data, tag, attr ) { 186 | 187 | this.__proto__ = BEMPUG.blockProto; 188 | 189 | this.name = name; 190 | 191 | this.data = BEMPUG.isObject( data ) ? data : {m: data}; 192 | 193 | this.attributes = attr; 194 | 195 | this.isElement = !!this.attributes.isElement; 196 | 197 | this.parent = BEMPUG.getCurrentParent(); 198 | 199 | if ( this.isElement ) delete this.attributes.isElement; 200 | 201 | if ( typeof this.data.t === 'undefined' ) this.data.t = tag; 202 | 203 | if ( typeof BEMPUG.beforeParse[ name ] === 'function' ) BEMPUG.beforeParse[ name ]( this ); 204 | 205 | this.type = this.isElement ? 'element' : 'block' + ( ( this.data.p === false || this.data.p === 0 ) ? 'Off' : '' ); 206 | 207 | this.sep = {}; 208 | 209 | this.classes = []; 210 | 211 | this.identifyTag( this.data.t, this.name, this.attributes ); 212 | 213 | this.setSeparators( this.data.s ); 214 | 215 | this.setName( this.name, this.data.p ); 216 | 217 | this.addModifier( this.data.m ); 218 | 219 | this.addMix( this.data.b ).addMix( this.data.e, true ); 220 | 221 | delete this.data; 222 | 223 | if ( typeof BEMPUG.afterParse[ name ] === 'function' ) BEMPUG.afterParse[ name ]( this ); 224 | 225 | } 226 | 227 | }; -------------------------------------------------------------------------------- /core.jade: -------------------------------------------------------------------------------- 1 | - 2 | const BEMPUG = { 3 | 4 | // bempug by Oleg Krylov [olegkrylov.pro] 5 | 6 | version: '1.1.1', 7 | 8 | tree: [], 9 | 10 | blocks: [], 11 | 12 | tagByName: {}, 13 | 14 | beforeParse: {}, 15 | 16 | afterParse: {}, 17 | 18 | tagByAttr: { href: 'a', alt: 'img', for: 'label' }, 19 | 20 | selfClosingTags: ['img','input','hr','br','wbr','source','area','col','colgroup'], 21 | 22 | forSpanTags: ['abbr','a','b','bdo','cite','dfn','em','i','kbd','q','s','span','sub','sup','samp','small','strong','u','var','mark','p','h1','h2','h3','h4','h5','h6','time','bdi','button','li','label'], 23 | 24 | isExternal: function( str ) { 25 | return /^(?:https?\:)?\/\//i.test( str ); 26 | }, 27 | 28 | isObject: function( obj ) { 29 | return ( typeof obj === 'object' && obj !== null && ! Array.isArray( obj ) ) ? true : false; 30 | }, 31 | 32 | isString: function( str ) { 33 | return ( str && typeof str === 'string' && !!str.trim() ) ? true : false; 34 | }, 35 | 36 | getCurrentBlock: function() { 37 | return this.blocks[ this.blocks.length - 1 ] || ''; 38 | }, 39 | 40 | getCurrentParent: function() { 41 | return this.tree[ this.tree.length - 1 ] || {}; 42 | }, 43 | 44 | addData: function( block ) { 45 | if ( block.type === 'block' ) this.blocks[ this.blocks.length ] = block.name; 46 | this.tree[ this.tree.length ] = block; 47 | }, 48 | 49 | removeData: function( block ) { 50 | if ( block.type === 'block' ) this.blocks.pop(); 51 | this.tree.pop(); 52 | }, 53 | 54 | blockProto: { 55 | 56 | setName: function( name, parent ) { 57 | 58 | var blockName = BEMPUG.isString( name ) ? name.trim() : false, 59 | parentName = BEMPUG.isString( parent ) ? parent.trim() : ( BEMPUG.getCurrentBlock() + '' ); 60 | 61 | if ( this.type === 'element' ) 62 | blockName = parentName + this.sep.element + ( blockName || 'element' ); 63 | 64 | this.name = ( blockName || 'block' ); 65 | this.classes.push( this.name ); 66 | 67 | return this; 68 | }, 69 | 70 | identifyTag: function( tag, name, attr ) { 71 | 72 | if ( BEMPUG.isString( tag ) ) return this.setTag( tag ); 73 | 74 | if ( name && BEMPUG.isString( BEMPUG.tagByName[ name ] ) ) { 75 | 76 | return this.setTag( BEMPUG.tagByName[ name ] ); 77 | } 78 | 79 | if ( attr.href || attr.alt || attr.for ) { 80 | 81 | var attribute = attr.href ? 'href' : ( attr.alt ? 'alt' : 'for' ); 82 | 83 | return this.setTag( BEMPUG.tagByAttr[ attribute ] ); 84 | } 85 | 86 | if ( this.parent.tag && this.parent.tag !== 'div' ) { 87 | 88 | if ( this.parent.tag === 'select' ) return this.setTag( 'option' ); 89 | 90 | if ( this.parent.tag === 'dl' ) return this.setTag( 'dd' ); 91 | 92 | if ( ['ul','ol'].indexOf( this.parent.tag ) !== -1 ) return this.setTag( 'li' ); 93 | 94 | if ( BEMPUG.forSpanTags.indexOf( this.parent.tag ) !== -1 ) return this.setTag( 'span' ); 95 | } 96 | 97 | return this.setTag( 'div' ); 98 | 99 | }, 100 | 101 | setTag: function( tag ) { 102 | 103 | if ( tag ) this.tag = tag.trim().toLowerCase(); 104 | 105 | this.selfClosing = ( BEMPUG.selfClosingTags.indexOf( this.tag ) !== -1 ); 106 | 107 | return this; 108 | 109 | }, 110 | 111 | setSeparators: function( sep ) { 112 | 113 | var separator = BEMPUG.isString( sep ) ? sep.split( '|' ) : [], 114 | modifier = separator[0] || ( this.parent.sep ? this.parent.sep.modifier : BEMPUG.modifier ), 115 | element = separator[1] || ( this.parent.sep ? this.parent.sep.element : BEMPUG.element ); 116 | 117 | this.sep.modifier = BEMPUG.isString( modifier ) ? modifier.trim() : '--'; 118 | this.sep.element = BEMPUG.isString( element ) ? element.trim() : '__'; 119 | 120 | return this; 121 | }, 122 | 123 | addModifier: function( mod, name ) { 124 | 125 | if ( ! BEMPUG.isString( mod ) ) return this; 126 | 127 | mod.split( '.' ).forEach( function( val ) { 128 | 129 | var blockName = BEMPUG.isString( name ) ? name.trim() : this.name, 130 | modifier = BEMPUG.isString( val ) ? val.trim() : false; 131 | 132 | if ( ! modifier || ! blockName ) return; 133 | 134 | this.classes.push( blockName + this.sep.modifier + modifier ); 135 | 136 | }, this); 137 | 138 | return this; 139 | 140 | }, 141 | 142 | addMix: function( data, isElementMix ) { 143 | 144 | if ( ! data ) return this; 145 | 146 | var array = Array.isArray( data ) ? data : [ data ]; 147 | 148 | array.forEach( function( val ) { 149 | 150 | var name, mix = ( val === true || val === 1 ) ? ( BEMPUG.getCurrentBlock() + '' ) : val; 151 | 152 | if ( ! BEMPUG.isString( mix ) ) return; 153 | 154 | name = mix.split( '|' )[0]; 155 | name = name.replace( '&', ( BEMPUG.getCurrentBlock() + '' ) ); 156 | 157 | if ( ! BEMPUG.isString( name ) ) return; 158 | 159 | name = name.trim(); 160 | 161 | if ( isElementMix ) { 162 | 163 | var elementOf = name.split( ':' )[0]; 164 | var elementName = name.split( ':' )[1]; 165 | 166 | if ( ! elementName ) 167 | elementName = this.type === 'element' ? this.name.split( this.sep.element )[1] : this.name; 168 | 169 | if ( ! ( BEMPUG.isString( elementOf ) && BEMPUG.isString( elementName ) ) ) return; 170 | 171 | name = elementOf.trim() + this.sep.element + elementName.trim(); 172 | } 173 | 174 | this.classes.push( name ); 175 | this.addModifier( mix.split( '|' )[1], name ); 176 | 177 | }, this); 178 | 179 | return this; 180 | 181 | } 182 | 183 | }, 184 | 185 | Block: function( name, data, tag, attr ) { 186 | 187 | this.__proto__ = BEMPUG.blockProto; 188 | 189 | this.name = name; 190 | 191 | this.data = BEMPUG.isObject( data ) ? data : {m: data}; 192 | 193 | this.attributes = attr; 194 | 195 | this.isElement = !!this.attributes.isElement; 196 | 197 | this.parent = BEMPUG.getCurrentParent(); 198 | 199 | if ( this.isElement ) delete this.attributes.isElement; 200 | 201 | if ( typeof this.data.t === 'undefined' ) this.data.t = tag; 202 | 203 | if ( typeof BEMPUG.beforeParse[ name ] === 'function' ) BEMPUG.beforeParse[ name ]( this ); 204 | 205 | this.type = this.isElement ? 'element' : 'block' + ( ( this.data.p === false || this.data.p === 0 ) ? 'Off' : '' ); 206 | 207 | this.sep = {}; 208 | 209 | this.classes = []; 210 | 211 | this.identifyTag( this.data.t, this.name, this.attributes ); 212 | 213 | this.setSeparators( this.data.s ); 214 | 215 | this.setName( this.name, this.data.p ); 216 | 217 | this.addModifier( this.data.m ); 218 | 219 | this.addMix( this.data.b ).addMix( this.data.e, true ); 220 | 221 | delete this.data; 222 | 223 | if ( typeof BEMPUG.afterParse[ name ] === 'function' ) BEMPUG.afterParse[ name ]( this ); 224 | 225 | } 226 | 227 | }; -------------------------------------------------------------------------------- /test/page.fix.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Test page 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
Text
17 |
18 | 19 | 20 | 21 |
22 |
23 | 24 |
25 |
26 | 27 |
28 |
29 | 30 |
31 |
32 | 33 | 34 | 35 |
36 |
Content
37 |
38 | 39 | 40 | 41 |
42 |
Content
43 |
44 | 45 | 46 | 47 |
48 |
Success
49 |
50 | 51 | 52 | 53 |
54 |
Success
55 |
56 | 57 | 58 | 59 |
Success
60 | 61 | 62 | 63 |
64 |

Title

65 |
66 | 67 |
68 |

Title

69 |
70 | 71 | 72 | 73 | 78 | 79 | 80 | My text 81 | 82 | 83 | 84 | 85 | 89 | 90 |
91 |
Fields
92 |
93 | 94 | 95 | 96 |
Title
97 | 98 | 99 | 100 |
Title
101 | 102 | 103 | 104 |
Title
105 | 106 | 107 | 108 |
109 |
Title
110 |
111 | 112 |
113 |
Title
114 |
115 | 116 | 117 | 118 |
119 |
Title
120 |
Text
121 |
122 | 123 | 124 | 125 |
Title
126 | 127 | 128 | 129 | 132 | 133 | 134 | 135 | 138 | 139 | 140 | 141 |
Content
142 | 143 | 144 | 145 |
Content
146 | 147 | 148 | 149 |
Content
150 | 151 | 152 | 153 |
154 |
Text
155 |
156 | 157 | 158 | 159 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 |
175 | 185 |
186 | 187 | 188 | 189 | 190 |
191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 |
205 |
With space
206 |
207 | 208 |
209 |
210 |
211 | 212 |
213 |
Without anything
214 |
215 | 216 |
217 |
[]
218 |
219 | 220 |
221 |
{}
222 |
223 | 224 |
225 |
('')
226 |
227 | 228 |
229 |
(' ')
230 |
231 | 232 |
233 |
null
234 |
235 | 236 |
237 |
false
238 |
239 | 240 |
241 |
true
242 |
243 | 244 |
245 |
1
246 |
247 | 248 |
249 |
0
250 |
251 | 252 |
253 |
{[]}
254 |
255 | 256 |
257 |
{{}}
258 |
259 | 260 |
261 |
{0}
262 |
263 | 264 |
265 |
{1}
266 |
267 | 268 |
269 |
{null}
270 |
271 | 272 |
273 |
{false}
274 |
275 | 276 |
277 |
{true}
278 |
279 | 280 |
281 |
{''}
282 |
283 | 284 |
285 |
{' '}
286 |
287 | 288 | 289 | 290 | -------------------------------------------------------------------------------- /test/page.pug: -------------------------------------------------------------------------------- 1 | 2 | - var n = '\n'; 3 | 4 | include ../index 5 | 6 | - 7 | BEMPUG.modifier = '--'; 8 | BEMPUG.element = '__'; 9 | 10 | BEMPUG.tagByName = {list: 'ul', form: 'form', fields: 'fieldset'}; 11 | 12 | BEMPUG.beforeParse[ 'input' ] = function( block ) { 13 | 14 | if ( typeof block.data.m === 'undefined' ) block.data.m = 'default'; 15 | block.tag = 'input'; 16 | 17 | }; 18 | 19 | BEMPUG.afterParse[ 'page' ] = function( block ) { 20 | 21 | block.setTag( 'body' ); 22 | block.addModifier( 'test' ); 23 | block.attributes.itemscope = true; 24 | block.attributes.itemtype = 'http://schema.org/WebPage'; 25 | 26 | }; 27 | 28 | doctype 29 | +b('html', 'no-js', 'html')(lang='en') 30 | head 31 | meta(charset='utf-8') 32 | meta(http-equiv='X-UA-Compatible' content='IE=edge') 33 | meta(name='viewport' content='width=device-width, initial-scale=1, shrink-to-fit=no') 34 | 35 | = n 36 | 37 | title Test page 38 | meta(name='description' content='This HTML code compiled from Pug.') 39 | 40 | 41 | +b('page') 42 | 43 | 44 | 45 | = n + n 46 | // Simple example 47 | 48 | +b('block') 49 | +e('element') Text 50 | 51 | 52 | = n + n 53 | // You can disable parent mode and element will ignore this block 54 | 55 | +b('header') 56 | +b('grid', {p: false}) 57 | +e('logo') Logo 58 | 59 | = n 60 | 61 | +b('header') 62 | +b('grid', {p:0}) 63 | +e('logo') Logo 64 | 65 | 66 | = n + n 67 | // Element depends on parent block 68 | 69 | +b('content') 70 | +e('layout') Content 71 | 72 | 73 | = n + n 74 | // You can set element directly 75 | 76 | +b('content') 77 | +e('layout', {p: 'page'}) Content 78 | 79 | 80 | = n + n 81 | // Block and element have modifier 82 | 83 | +b('alert', 'success') 84 | +e('text', 'bolder') Success 85 | 86 | 87 | = n + n 88 | // Block and element have more than one modifier 89 | 90 | +b('alert', 'success.active') 91 | +e('text', 'bolder.italic') Success 92 | 93 | 94 | = n + n 95 | // Also, you can set modifiers in data argument 96 | 97 | +b('alert', {m: 'success.active'}) Success 98 | 99 | 100 | = n + n 101 | // Default tag is div, but you can set it directly 102 | 103 | +b('news', {}, 'article') 104 | +e('title', {}, 'h1') Title 105 | 106 | = n 107 | 108 | +b('news', {t: 'article'}) 109 | +e('title', {t: 'h1'}) Title 110 | 111 | 112 | = n + n 113 | // Sometimes mixin can be smart and tag depends on parent or attributes 114 | 115 | +b('list', {t: 'ul'}) 116 | +e('item') My item 1 117 | +e('item') My item 2 118 | +e('item') My item 3 119 | 120 | = n 121 | 122 | +b('link')(href='https://www.npmjs.com/package/bempug') 123 | +b('text') My text 124 | 125 | 126 | = n + n 127 | // Also, you can use tagByName global option for set default tag by name 128 | 129 | +b('list') 130 | +e('item') Item 131 | +e('item') Item 132 | 133 | = n 134 | 135 | +b('form') 136 | +e('fields') Fields 137 | 138 | 139 | = n + n 140 | // Block is mixed with element 141 | 142 | +b('title', {e: 'article'}) Title 143 | 144 | 145 | = n + n 146 | // You can set name of element in mix with colon 147 | 148 | +b('title', {e: 'article:my-name'}) Title 149 | 150 | 151 | = n + n 152 | // Block is mixed with two elements 153 | 154 | +b('title', {e: ['article', 'content']}) Title 155 | 156 | 157 | = n + n 158 | // Block is mixed with element of parent block 159 | 160 | +b('news') 161 | +b('title', {e: true}) Title 162 | 163 | = n 164 | 165 | +b('news') 166 | +b('title', {e:1}) Title 167 | 168 | 169 | = n + n 170 | // Also, you can use ampersand & sign as parent block reference 171 | 172 | +b('news') 173 | +b('title', {e: '&'}) Title 174 | +b('text', {e: '&:description'}) Text 175 | 176 | 177 | = n + n 178 | // Block is mixed with element which has modifiers 179 | 180 | +b('title', {e: 'news|bolder.size-m'}) Title 181 | 182 | 183 | = n + n 184 | // Element is mixed with another element 185 | 186 | +b( 'footer' ) 187 | +e( 'bottom', {e: 'page'} ) 188 | 189 | 190 | = n + n 191 | // Element is mixed with block 192 | 193 | +b( 'footer' ) 194 | +e( 'bottom', {b: 'grid'} ) 195 | 196 | 197 | = n + n 198 | // Block is mixed with another block 199 | 200 | +b('article', {b: 'news'}) Content 201 | 202 | 203 | = n + n 204 | // Block is mixed with another block which has modifiers 205 | 206 | +b('article', {b: 'news|first'}) Content 207 | 208 | 209 | = n + n 210 | // Block is mixed with two blocks which have modifiers 211 | 212 | +b('article', {b: ['news|first','fixed|active']}) Content 213 | 214 | 215 | = n + n 216 | // Also, you can set separators in data argument 'modifier|element' and ignore global settings 217 | 218 | +b('news', {e: 'content', m: 'first', s: '---|___' }) 219 | +b('text', {e: true, m: 'bolder'}) Text 220 | 221 | 222 | = n + n 223 | // You can get current block name 224 | 225 | +b('nav') 226 | +e('item')= 'Item of ' + BEMPUG.getCurrentBlock() 227 | 228 | +b('myblock') 229 | +e('item')= 'Item of ' + BEMPUG.getCurrentBlock() 230 | 231 | 232 | 233 | 234 | = n + n 235 | // Self closing tags 236 | 237 | +b('image','','img') 238 | +b('field',{t: 'input'}) 239 | 240 | 241 | = n + n 242 | // Default tag depends on parent tag for any descendant 243 | 244 | +b('description') 245 | +e('list',{}, 'ul') 246 | +e('item') My item 1 247 | +e('item') My item 2 248 | +e('item') 249 | +e('mark') My mark 250 | +e('item') 251 | +b('text') My item 4 252 | 253 | 254 | 255 | 256 | = n + n 257 | // Before parse callback 258 | 259 | +b('input', {m: 'search'}) 260 | +b('input') 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | = n + n + n + n + n + n + n + n 270 | // 271 | // Crash test 272 | // 273 | 274 | = n + n 275 | 276 | +b(' block ',' mod ',' div ') 277 | +e(' el ',' mod ',' div ') With space 278 | 279 | = n 280 | 281 | +b(0,{m: ' big . small ', e: [' page | ', ' content : test | active '], b: ' text | bold . small ' },0) 282 | +e(0,{m: ' big . small . bold ', p: ' content '},0) 283 | 284 | = n 285 | 286 | +b 287 | +e Without anything 288 | 289 | = n 290 | 291 | +b([],[],[]) 292 | +e([],[],[]) [] 293 | 294 | = n 295 | 296 | +b({},{},{}) 297 | +e({},{},{}) {} 298 | 299 | = n 300 | 301 | +b('','','') 302 | +e('','','') ('') 303 | 304 | = n 305 | 306 | +b(' ',' ',' ') 307 | +e(' ',' ',' ') (' ') 308 | 309 | = n 310 | 311 | +b(null,null,null) 312 | +e(null,null,null) null 313 | 314 | = n 315 | 316 | +b(false,false,false) 317 | +e(false,false,false) false 318 | 319 | = n 320 | 321 | +b(true,true,true) 322 | +e(true,true,true) true 323 | 324 | = n 325 | 326 | +b(1,1,1) 327 | +e(1,1,1) 1 328 | 329 | = n 330 | 331 | +b(0,0,0) 332 | +e(0,0,0) 0 333 | 334 | = n 335 | 336 | +b([],{m: [], p: [], e: [], b: [], s: [], t: [] },[]) 337 | +e([],{m: [], p: [], e: [], b: [], s: [], t: [] },[]) {[]} 338 | 339 | = n 340 | 341 | +b({},{m: {}, p: {}, e: {}, b: {}, s: {}, t: {} },{}) 342 | +e({},{m: {}, p: {}, e: {}, b: {}, s: {}, t: {} },{}) {{}} 343 | 344 | = n 345 | 346 | +b(0,{m: 0, p: 0, e: 0, b: 0, s: 0, t: 0 },0) 347 | +e(0,{m: 0, p: 0, e: 0, b: 0, s: 0, t: 0 },0) {0} 348 | 349 | = n 350 | 351 | +b(1,{m: 1, p: 1, e: 1, b: 1, s: 1, t: 1 },1) 352 | +e(1,{m: 1, p: 1, e: 1, b: 1, s: 1, t: 1 },1) {1} 353 | 354 | = n 355 | 356 | +b(null,{m: null, p: null, e: null, b: null, s: null, t: null },null) 357 | +e(null,{m: null, p: null, e: null, b: null, s: null, t: null },null) {null} 358 | 359 | = n 360 | 361 | +b(false,{m: false, p: false, e: false, b: false, s: false },false) 362 | +e(false,{m: false, p: false, e: false, b: false, s: false },false) {false} 363 | 364 | = n 365 | 366 | +b(true,{m: true, p: true, e: true, b: true, s: true },true) 367 | +e(true,{m: true, p: true, e: true, b: true, s: true },true) {true} 368 | 369 | 370 | = n 371 | 372 | +b('',{m: '', p: '', e: '', b: '', s: '' },'') 373 | +e('',{m: '', p: '', e: '', b: '', s: '' },'') {''} 374 | 375 | 376 | = n 377 | 378 | +b(' ',{m: ' ', p: ' ', e: ' ', b: ' ', s: ' ' },' ') 379 | +e(' ',{m: ' ', p: ' ', e: ' ', b: ' ', s: ' ' },' ') {' '} 380 | 381 | 382 | 383 | = n + n 384 | 385 | -------------------------------------------------------------------------------- /test/page.jade.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Test page 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
Text 17 |
18 |
19 | 20 | 21 | 22 |
23 |
24 | 26 |
27 |
28 | 29 |
30 |
31 | 33 |
34 |
35 | 36 | 37 | 38 |
39 |
Content 40 |
41 |
42 | 43 | 44 | 45 |
46 |
Content 47 |
48 |
49 | 50 | 51 | 52 |
53 |
Success 54 |
55 |
56 | 57 | 58 | 59 |
60 |
Success 61 |
62 |
63 | 64 | 65 | 66 |
Success 67 |
68 | 69 | 70 | 71 |
72 |

Title 73 |

74 |
75 | 76 |
77 |

Title 78 |

79 |
80 | 81 | 82 | 83 | 91 | 92 | 93 | My text 94 | 95 | 96 | 97 | 98 | 99 | 105 | 106 |
107 |
Fields 108 |
109 |
110 | 111 | 112 | 113 |
Title 114 |
115 | 116 | 117 | 118 |
Title 119 |
120 | 121 | 122 | 123 |
Title 124 |
125 | 126 | 127 | 128 |
129 |
Title 130 |
131 |
132 | 133 |
134 |
Title 135 |
136 |
137 | 138 | 139 | 140 |
141 |
Title 142 |
143 |
Text 144 |
145 |
146 | 147 | 148 | 149 |
Title 150 |
151 | 152 | 153 | 154 | 158 | 159 | 160 | 161 | 165 | 166 | 167 | 168 |
Content 169 |
170 | 171 | 172 | 173 |
Content 174 |
175 | 176 | 177 | 178 |
Content 179 |
180 | 181 | 182 | 183 |
184 |
Text 185 |
186 |
187 | 188 | 189 | 190 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 |
207 | 221 |
222 | 223 | 224 | 225 | 227 |
228 |
229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 |
243 |
With space 244 |
245 |
246 | 247 |
248 |
249 |
250 |
251 | 252 |
253 |
Without anything 254 |
255 |
256 | 257 |
258 |
[] 259 |
260 |
261 | 262 |
263 |
{} 264 |
265 |
266 | 267 |
268 |
('') 269 |
270 |
271 | 272 |
273 |
(' ') 274 |
275 |
276 | 277 |
278 |
null 279 |
280 |
281 | 282 |
283 |
false 284 |
285 |
286 | 287 |
288 |
true 289 |
290 |
291 | 292 |
293 |
1 294 |
295 |
296 | 297 |
298 |
0 299 |
300 |
301 | 302 |
303 |
{[]} 304 |
305 |
306 | 307 |
308 |
{{}} 309 |
310 |
311 | 312 |
313 |
{0} 314 |
315 |
316 | 317 |
318 |
{1} 319 |
320 |
321 | 322 |
323 |
{null} 324 |
325 |
326 | 327 |
328 |
{false} 329 |
330 |
331 | 332 |
333 |
{true} 334 |
335 |
336 | 337 |
338 |
{''} 339 |
340 |
341 | 342 |
343 |
{' '} 344 |
345 |
346 | 347 | 348 | 349 | -------------------------------------------------------------------------------- /test/page.pug.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Test page 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
Text 17 |
18 |
19 | 20 | 21 | 22 |
23 |
24 | 26 |
27 |
28 | 29 |
30 |
31 | 33 |
34 |
35 | 36 | 37 | 38 |
39 |
Content 40 |
41 |
42 | 43 | 44 | 45 |
46 |
Content 47 |
48 |
49 | 50 | 51 | 52 |
53 |
Success 54 |
55 |
56 | 57 | 58 | 59 |
60 |
Success 61 |
62 |
63 | 64 | 65 | 66 |
Success 67 |
68 | 69 | 70 | 71 |
72 |

Title 73 |

74 |
75 | 76 |
77 |

Title 78 |

79 |
80 | 81 | 82 | 83 | 91 | 92 | 93 | My text 94 | 95 | 96 | 97 | 98 | 99 | 105 | 106 |
107 |
Fields 108 |
109 |
110 | 111 | 112 | 113 |
Title 114 |
115 | 116 | 117 | 118 |
Title 119 |
120 | 121 | 122 | 123 |
Title 124 |
125 | 126 | 127 | 128 |
129 |
Title 130 |
131 |
132 | 133 |
134 |
Title 135 |
136 |
137 | 138 | 139 | 140 |
141 |
Title 142 |
143 |
Text 144 |
145 |
146 | 147 | 148 | 149 |
Title 150 |
151 | 152 | 153 | 154 | 158 | 159 | 160 | 161 | 165 | 166 | 167 | 168 |
Content 169 |
170 | 171 | 172 | 173 |
Content 174 |
175 | 176 | 177 | 178 |
Content 179 |
180 | 181 | 182 | 183 |
184 |
Text 185 |
186 |
187 | 188 | 189 | 190 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 |
207 | 221 |
222 | 223 | 224 | 225 | 227 |
228 |
229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 |
243 |
With space 244 |
245 |
246 | 247 |
248 |
249 |
250 |
251 | 252 |
253 |
Without anything 254 |
255 |
256 | 257 |
258 |
[] 259 |
260 |
261 | 262 |
263 |
{} 264 |
265 |
266 | 267 |
268 |
('') 269 |
270 |
271 | 272 |
273 |
(' ') 274 |
275 |
276 | 277 |
278 |
null 279 |
280 |
281 | 282 |
283 |
false 284 |
285 |
286 | 287 |
288 |
true 289 |
290 |
291 | 292 |
293 |
1 294 |
295 |
296 | 297 |
298 |
0 299 |
300 |
301 | 302 |
303 |
{[]} 304 |
305 |
306 | 307 |
308 |
{{}} 309 |
310 |
311 | 312 |
313 |
{0} 314 |
315 |
316 | 317 |
318 |
{1} 319 |
320 |
321 | 322 |
323 |
{null} 324 |
325 |
326 | 327 |
328 |
{false} 329 |
330 |
331 | 332 |
333 |
{true} 334 |
335 |
336 | 337 |
338 |
{''} 339 |
340 |
341 | 342 |
343 |
{' '} 344 |
345 |
346 | 347 | 348 | 349 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # BemPug 2 | 3 | [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)](https://raw.githubusercontent.com/werty1001/bempug/master/LICENSE) [![npm](https://img.shields.io/npm/v/bempug.svg?style=flat-square)](https://www.npmjs.com/package/bempug) [![npm](https://img.shields.io/npm/dt/bempug.svg?style=flat-square)](https://www.npmjs.com/package/bempug) 4 | 5 | Simple mixins to help you writing code on [BEM](https://en.bem.info/) methodology in [pug](https://pugjs.org/) or jade projects. 6 | 7 | --- 8 | 9 | > You like BEM? Try [BemGo](https://github.com/werty1001/bemgo) — starter kit for developing BEM apps using Gulp and Webpack. 10 | 11 | --- 12 | 13 | ### Anchors 14 | [Install](#install) | [Mixins](#mixins) | [Examples](#examples) | [Helpers](#helpers) | [Changelog](#changelog) 15 | 16 | --- 17 | 18 | ### Install 19 | 20 | Install from npm: 21 | ```sh 22 | npm i bempug -D 23 | ``` 24 | Then include `index` file to your pug or jade project: 25 | ```Jade 26 | include ../../node_modules/bempug/index 27 | ``` 28 | 29 | --- 30 | 31 | ### Mixins 32 | 33 | Block mixin: 34 | 35 | ```Pug 36 | +b( name, data, tag ) 37 | ``` 38 | 39 | - **name** `String` 40 | - **data** `String or Object` 41 | - **data.m** `String` — block modifier 42 | - **data.p** `Boolean` — disable parent mode 43 | - **data.e** `Array or String` — mix block with element 44 | - **data.b** `Array or String` — mix block with another block 45 | - **data.t** `String` — block tag 46 | - **data.s** `String` — block separators 47 | - **tag** `String` 48 | 49 | > If data argument is String it will be a modifier. 50 | 51 |
52 | 53 | Element mixin: 54 | 55 | ```Pug 56 | +e( name, data, tag ) 57 | ``` 58 | 59 | - **name** `String` 60 | - **data** `String or Object` 61 | - **data.m** `String` — element modifier 62 | - **data.p** `String` — parent block 63 | - **data.e** `Array or String` — mix element with another element 64 | - **data.b** `Array or String` — mix element with block 65 | - **data.t** `String` — element tag 66 | - **data.s** `String` — element separators 67 | - **tag** `String` 68 | 69 | > If data argument is String it will be a modifier. 70 | 71 | --- 72 | 73 | ### Examples 74 | [Block](#block) | [Element](#element) | [Modifier](#modifier) | [Tag](#tag) | [Mix](#mix) | [Separators](#separators) 75 | 76 | --- 77 | 78 | ### Block 79 | Simple example: 80 | ```Pug 81 | +b( 'block' ) 82 | +e( 'element' ) Text 83 | ``` 84 | ```HTML 85 |
86 |
Text
87 |
88 | ``` 89 | 90 | You can to disable parent mode and element will ignore this block: 91 | ```Pug 92 | +b( 'header' ) 93 | +b( 'grid', {p: false} ) // or short {p:0} 94 | +e( 'logo' ) Logo 95 | ``` 96 | ```HTML 97 |
98 |
99 | 100 |
101 |
102 | ``` 103 | 104 | --- 105 | 106 | ### Element 107 | 108 | Element depends on parent block: 109 | ```Pug 110 | +b( 'content' ) 111 | +e( 'layout' ) Content 112 | ``` 113 | ```HTML 114 |
115 |
Content
116 |
117 | ``` 118 | You can set parent block for element directly: 119 | ```Pug 120 | +b( 'content' ) 121 | +e( 'layout', {p: 'page'} ) Content 122 | ``` 123 | ```HTML 124 |
125 |
Content
126 |
127 | ``` 128 | 129 | --- 130 | 131 | ### Modifier 132 | 133 | Block and element have modifier: 134 | ```Pug 135 | +b( 'alert', 'success' ) 136 | +e( 'text', 'bolder' ) Success 137 | ``` 138 | ```HTML 139 |
140 |
Success
141 |
142 | ``` 143 | 144 | Block and element have more than one modifier: 145 | ```Pug 146 | +b( 'alert', 'success.active' ) 147 | +e( 'text', 'bolder.italic' ) Success 148 | ``` 149 | ```HTML 150 |
151 |
Success
152 |
153 | ``` 154 | 155 | Also, you can set modifiers in `Object`: 156 | ```Pug 157 | +b( 'alert', {m: 'success.active'} ) Success 158 | ``` 159 | ```HTML 160 |
Success
161 | ``` 162 | 163 | --- 164 | 165 | ### Tag 166 | 167 | Default tag is **div**, but you can set it directly: 168 | ```Pug 169 | +b( 'news', {}, 'article' ) 170 | +e( 'title', {}, 'h1' ) Title 171 | 172 | // Or in data Object 173 | 174 | +b( 'news', {t: 'article'} ) 175 | +e( 'title', {t: 'h1'} ) Title 176 | ``` 177 | ```HTML 178 |
179 |

Title

180 |
181 | ``` 182 | 183 | Sometimes mixin can be smart and tag depends on parent or attributes: 184 | ```Pug 185 | +b( 'list', {t: 'ul'} ) 186 | +e( 'item' ) My item 1 187 | +e( 'item' ) My item 2 188 | +e( 'item' ) My item 3 189 | 190 | +b( 'link' )(href='https://www.npmjs.com/package/bempug') 191 | +b( 'text' ) My text 192 | ``` 193 | ```HTML 194 | 199 | 200 | 201 | My text 202 | 203 | ``` 204 | 205 | Also, you can use `tagByName` global option for set default tag by name: 206 | 207 | ```Pug 208 | - BEMPUG.tagByName = {list: 'ul', form: 'form', fields: 'fieldset'}; 209 | 210 | +b( 'list' ) 211 | +e( 'item' ) Item 212 | +e( 'item' ) Item 213 | 214 | +b( 'form' ) 215 | +e( 'fields' ) Fields 216 | ``` 217 | ```HTML 218 | 222 | 223 |
224 |
Fields
225 |
226 | ``` 227 | 228 | --- 229 | 230 | ### Mix 231 | 232 | Block is mixed with element: 233 | ```Jade 234 | +b( 'title', {e: 'article'} ) Title 235 | ``` 236 | ```HTML 237 |
Title
238 | ``` 239 | 240 | You can set name of element in mix with colon: 241 | ```Pug 242 | +b( 'title', {e: 'article:my-name'} ) Title 243 | ``` 244 | ```HTML 245 |
Title
246 | ``` 247 | 248 | Block is mixed with two elements: 249 | ```Pug 250 | +b( 'title', {e: ['article', 'content']} ) Title 251 | ``` 252 | ```HTML 253 |
Title
254 | ``` 255 | 256 | Also, you can use ampersand `&` sign as parent block reference: 257 | ```Pug 258 | +b( 'news' ) 259 | +b( 'title', {e: '&'} ) Title 260 | +b( 'text', {e: '&:description'} ) Text 261 | ``` 262 | ```HTML 263 |
264 |
Title
265 |
Text
266 |
267 | ``` 268 | 269 | Block is mixed with element which has modifiers: 270 | ```Pug 271 | +b( 'title', {e: 'news|bolder.size-m'} ) Title 272 | ``` 273 | ```HTML 274 |
Title
275 | ``` 276 | 277 | Element is mixed with another element: 278 | ```Pug 279 | +b( 'footer' ) 280 | +e( 'bottom', {e: 'page'} ) 281 | ``` 282 | ```HTML 283 | 286 | ``` 287 | 288 | Element is mixed with block: 289 | ```Pug 290 | +b( 'footer' ) 291 | +e( 'bottom', {b: 'grid'} ) 292 | ``` 293 | ```HTML 294 | 297 | ``` 298 | 299 | Block is mixed with another block: 300 | ```Pug 301 | +b( 'article', {b: 'news'} ) Content 302 | ``` 303 | ```HTML 304 |
Content
305 | ``` 306 | 307 | Block is mixed with another block which has modifiers: 308 | ```Pug 309 | +b( 'article', {b: 'news|first'} ) Content 310 | ``` 311 | ```HTML 312 |
Content
313 | ``` 314 | 315 | Block is mixed with two blocks which have modifiers: 316 | ```Pug 317 | +b( 'article', {b: ['news|first','fixed|active']} ) Content 318 | ``` 319 | ```HTML 320 |
Content
321 | ``` 322 | 323 | --- 324 | 325 | ### Separators 326 | You can change global separators: 327 | ```Pug 328 | - BEMPUG.modifier = '_'; 329 | - BEMPUG.element = '__'; 330 | 331 | +b( 'alert', 'success.active' ) 332 | +e( 'text', 'bolder.italic' ) Success 333 | ``` 334 | ```HTML 335 |
336 |
Success
337 |
338 | ``` 339 | 340 | Also, you can set separators for each block and ignore global settings `'modifier|element'`: 341 | ```Pug 342 | +b( 'news', {e: 'content', m: 'first', s: '---|___' } ) 343 | +b( 'text', {e: true, m: 'bolder'} ) Text 344 | ``` 345 | ```HTML 346 |
347 |
Text
348 |
349 | ``` 350 | 351 | --- 352 | 353 | ### Helpers 354 | [Get current block](#get-current-block) | [Get current parent](#get-current-parent) | [Callbacks](#callbacks) 355 | 356 | --- 357 | 358 | ### Get current block 359 | You can get current block name: 360 | ```Pug 361 | +b( 'nav' ) 362 | +e( 'item' ) 363 | - console.log( BEMPUG.getCurrentBlock() ); // 'nav' 364 | +b( 'img' ) 365 | - console.log( BEMPUG.getCurrentBlock() ); // 'img' 366 | ``` 367 | 368 | --- 369 | 370 | ### Get current parent 371 | You can get current parent `Object`: 372 | ```Pug 373 | +b( 'html', 'no-js', 'html' )(lang='en') 374 | - console.log( BEMPUG.getCurrentParent() ); 375 | ``` 376 | ```JS 377 | { type: 'block', 378 | name: 'html', 379 | tag: 'html', 380 | attributes: { lang: 'en' }, 381 | sep: { modifier: '--', element: '__' }, 382 | classes: [ 'html', 'html--no-js' ], 383 | parent: {}, 384 | selfClosing: false } 385 | ``` 386 | 387 | --- 388 | 389 | ### Callbacks 390 | You can set `beforeParse` callback: 391 | ```Pug 392 | - BEMPUG.beforeParse[ 'input' ] = function( block ) { 393 | 394 | if ( typeof block.data.m === 'undefined' ) block.data.m = 'default'; 395 | } 396 | 397 | +b( 'input', {m: 'search'} ) // Have modifier 'search' 398 | 399 | +b( 'input' ) // No modifier, but we set modifier 'default' by callback 400 | ``` 401 | ```HTML 402 | 403 | 404 | ``` 405 | 406 | You can set `afterParse` callback: 407 | ```Pug 408 | - BEMPUG.afterParse[ 'page' ] = function( block ) { 409 | 410 | block.setTag( 'body' ); 411 | block.addModifier( 'test' ); 412 | block.attributes.itemscope = true; 413 | block.attributes.itemtype = 'http://schema.org/WebPage'; 414 | } 415 | 416 | +b( 'page' ) My page 417 | ``` 418 | ```HTML 419 | My page 420 | ``` 421 | 422 | --- 423 | 424 | ### Changelog 425 | 426 | #### 1.1.1 427 | * **Fixed**: disable parent mode not work in cb 428 | * **Fixed**: name of element in mix with another element 429 | 430 | #### 1.1.0 431 | * **Add**: ampersand sign for mix 432 | * **Add**: mix element with blocks and another elements 433 | 434 | #### 1.0.2 435 | * **Add**: some global helpers 436 | * **Add**: before / after parse callback 437 | * **Fixed**: block and element separators work for any descendant 438 | * **Fixed**: default tag depends on parent tag for any descendant 439 | 440 | #### 1.0.1 441 | * **Add**: disable parent mode for blocks 442 | 443 | #### 1.0.0 444 | * **Release version** 445 | 446 | --- 447 | 448 | ### Thanks 449 | 450 | Many thanks to Roman Komarov for the [original idea](https://github.com/kizu/bemto). 451 | 452 | --------------------------------------------------------------------------------