phug-php/bemto

View on GitHub
src/templates/bemto_core.pug

Summary

Maintainability
Test Coverage
//- bemto
//- Copyright(c) 2012 Roman Komarov <kizu@kizu.ru>
//- MIT Licensed

//- Some global variables
-
  $bemto_chain = [];
  $bemto_chain_contexts = ['block'];

//- Block
mixin b($options)
  -
    $get_context = function ($ctx) { $ctx = empty($ctx['context']) ? '' : $ctx['context']; return is_string($ctx) ? $ctx : $ctx[0]; };
    $settings = $get_bemto_settings();
  //- TODO: should we make it generic way for other settings too?
  if is_array($options) && isset($options['prefix'])
    - $settings['prefix'] = $options['prefix']

  //- Rewriting the class for elements and modifiers
  -
    $tag = $options ? (is_string($options) ? $options : (isset($options['tag']) ? $options['tag'] : '')) : '';
    $options = (array) ($options ?: []);
    $isElement = $options && isset($options['isElement']) && $options['isElement'];
    $tagMetadata = $options && isset($options['metadata']) ? $options['metadata'] : null;
    $block_sets_context = false;

  if !empty($attributes['class'])
    //- Creating and normalizing bemto classes
    - $bemto_classes = $attributes['class']
    if is_array($bemto_classes)
      - $bemto_classes = implode(' ', $bemto_classes)
    - $bemto_classes = explode(' ', $bemto_classes)

    - $bemto_objects = []
    - $is_first_object = true
    - $new_context = []

    each $klass, $i in $bemto_classes
      - $bemto_object = []
      - $bemto_objects_count = count($bemto_objects)
      - $sets_context = false

      //- Catching the optional tag class
      - if (preg_match('/^[A-Z-]+[A-Z0-9-]?$/', $klass))
        - $tag = strtolower($klass)
        - continue


      //- Use block as a context for the first class if we're at element
      if $is_first_object && $isElement
        - $bemto_object['context'] = count($bemto_chain) ? $bemto_chain[count($bemto_chain) - 1] : null


      //- If the class is a modifier, add it to the previous object
      //- FIXME: `+b._mod._mod` — raw classes should be treated as raw ones
      - if (preg_match('/^(?!' . $settings['element'] . '[A-Za-z0-9])' . $settings['modifier'] . '(.+)$/', $klass, $modifier_class) && $bemto_objects_count && isset($bemto_objects[$bemto_objects_count - 1]['name']) && $bemto_objects[$bemto_objects_count - 1]['name'])
        if (!isset($bemto_objects[$bemto_objects_count - 1]['modifiers'])) || (!$bemto_objects[$bemto_objects_count - 1]['modifiers'])
          - $bemto_objects[$bemto_objects_count - 1]['modifiers'] = []
        - $bemto_objects[$bemto_objects_count - 1]['modifiers'][] = $modifier_class[1]
        - continue


      //- Use block as a context for the following classes if we have element delimiter at the start
      - if (preg_match('/^(?!' . $settings['modifier'] . '[A-Za-z0-9])' . $settings['element'] . '(.+)$/', $klass, $element_class))
        - $bemto_object['context'] = count($bemto_chain) ? $bemto_chain[count($bemto_chain) - 1] : null
        - $klass = $element_class[1]


      //- Set custom context for nested items
      - if (preg_match('/^(.*[A-Za-z0-9])(?!' . $settings['modifier'] . '$)' . $settings['element'] . '$/', $klass, $name_with_context))
        - $klass = $name_with_context[1]
        - $bemto_object['is_context'] = true
        - $sets_context = true
        - $block_sets_context = true
        - $isElement = false


      //- Apply the modifier from the classname if exist
      - if (preg_match('/^(.*?[A-Za-z0-9])(?!' . $settings['element'] . '[A-Za-z0-9])' . $settings['modifier'] . '(.+)$/', $klass, $name_with_modifier))
        - $klass = $name_with_modifier[1]

        if (!isset($bemto_object['modifiers'])) || (!$bemto_object['modifiers'])
          - $bemto_object['modifiers'] = []
        - $bemto_object['modifiers'][] = $name_with_modifier[2]

      - $found_prefix = ''
      - $prefix_regex_string = '()?'
      if $settings['prefix']
        - $prefix = $settings['prefix']
        if is_string($prefix)
          - $prefix = ['' => $prefix]

        - $prefix_regex_test = []
        if is_array($prefix)
          each $value, $key in $prefix
            if is_string($key) && ($key !== '') && (!in_array($key, $prefix_regex_test))
              - $prefix_regex_test[] = $key
            if is_string($value) && ($value !== '') && (!in_array($value, $prefix_regex_test))
              - $prefix_regex_test[] = $value

          - $prefix_regex_string = '(' . implode('|', $prefix_regex_test) . ')?'

        - if (preg_match('/^' . $prefix_regex_string . '([A-Za-z0-9]+.*)$/', $klass, $name_with_prefix))
          - $klass = $name_with_prefix[2]
          - $found_prefix = $name_with_prefix[1] ?: ''
          - $found_prefix = isset($prefix[$found_prefix]) ? $prefix[$found_prefix] : null
          if ($found_prefix === null) || ($found_prefix === true)
            - $found_prefix = $name_with_prefix[1]
      - $bemto_object['prefix'] = strtr($found_prefix ?: '', ['-' => '%DASH%', '_' => '%UNDERSCORE%'])


      - if ($sets_context && preg_match('/^[a-zA-Z0-9]+.*/', $klass))
        - $new_context[] = isset($bemto_object['context']) && $bemto_object['context'] ? ($get_context($bemto_object) . $settings['element'] . $klass) : ($bemto_object['prefix'] . $klass)

      - $bemto_object['name'] = $klass
      - $is_first_object = false

      if isset($bemto_object['context']) && count($bemto_object['context']) > 1
        each $subcontext in $bemto_object['context']
          - $sub_object = copyValue($bemto_object)
          - $sub_object['context'] = [$subcontext]
          - $bemto_objects[] = $sub_object
      else
        - $bemto_objects[] = $bemto_object

    //- If no custom context is set, use the first proper object
    - if (!$isElement && !count($new_context) && isset($bemto_objects[0]) && $bemto_objects[0] && isset($bemto_objects[0]['name']) && preg_match('/^[a-zA-Z0-9]+.*/', $bemto_objects[0]['name']))
      - $bemto_objects[0]['is_context'] = true
      - $new_context[] = isset($bemto_objects[0]['context']) && $bemto_objects[0]['context'] ? ($get_context($bemto_objects[0]) . $settings['element'] . $bemto_objects[0]['name']) : ($bemto_objects[0]['prefix'] . $bemto_objects[0]['name'])
      - $block_sets_context = true

    if count($new_context)
      //- Use only the block's name for context if we're at strict setting
      if $settings['flat_elements']
        each $subcontext, $i in $new_context
          - if ( preg_match('/^(.*?[A-Za-z0-9])(?!' . $settings['modifier'] . '[A-Za-z0-9])' . $settings['element'] . '.+$/', $subcontext, $context_with_element))
            - $new_context[$i] = $context_with_element[1]
      - $bemto_chain[] = $new_context

    //- Rendering the classes
    if count($bemto_objects)
      - $new_classes = []
      each $bemto_object in $bemto_objects
        if isset($bemto_object['name']) && $bemto_object['name']
          - $start = $bemto_object['prefix']
          if isset($bemto_object['context']) && $bemto_object['context']
            - $start = $get_context($bemto_object) . $settings['output_element']
          - $new_classes[] = $start . $bemto_object['name']
          if !empty($bemto_object['modifiers'])
            each $modifier in $bemto_object['modifiers']
              - $new_classes[] = $start . $bemto_object['name'] . $settings['output_modifier'] . $modifier

      - $delimiter = isset($settings['class_delimiter']) && $settings['class_delimiter'] ? (' ' . $settings['class_delimiter'] . ' ') : ' '
      - $attributes['class'] = strtr(implode($delimiter, $new_classes), ['%DASH%' => '-', '%UNDERSCORE%' => '_'])
    else
      - $attributes['class'] = null

  - $__pug_bemto_chain_splice = (!$isElement && $block_sets_context);

  if $block
    +bemto_tag($tag, $tagMetadata)&attributes($attributes): block
  else
    +bemto_tag($tag, $tagMetadata)&attributes($attributes)

  //- Closing actions (remove the current block from the chain)
  if $__pug_bemto_chain_splice
    - $bemto_chain = array_splice($bemto_chain, 0, -1)
  - $bemto_chain_contexts = array_splice($bemto_chain_contexts, 0, -1)

//- Element
mixin e($options)
  unless $options
    - $options = []
  else if is_string($options)
    - $options = ['tag' => $options]
  - $options['isElement'] = true
  if $block
    +b($options)&attributes($attributes): block
  else
    +b($options)&attributes($attributes)