github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/public/libs/vue-1.0.24/src/compiler/transclude.js (about)

     1  import { parseText } from '../parsers/text'
     2  import { parseTemplate } from '../parsers/template'
     3  import {
     4    warn,
     5    isTemplate,
     6    isFragment,
     7    prepend,
     8    extractContent,
     9    createAnchor,
    10    resolveAsset,
    11    toArray,
    12    addClass,
    13    hasBindAttr
    14  } from '../util/index'
    15  
    16  const specialCharRE = /[^\w\-:\.]/
    17  
    18  /**
    19   * Process an element or a DocumentFragment based on a
    20   * instance option object. This allows us to transclude
    21   * a template node/fragment before the instance is created,
    22   * so the processed fragment can then be cloned and reused
    23   * in v-for.
    24   *
    25   * @param {Element} el
    26   * @param {Object} options
    27   * @return {Element|DocumentFragment}
    28   */
    29  
    30  export function transclude (el, options) {
    31    // extract container attributes to pass them down
    32    // to compiler, because they need to be compiled in
    33    // parent scope. we are mutating the options object here
    34    // assuming the same object will be used for compile
    35    // right after this.
    36    if (options) {
    37      options._containerAttrs = extractAttrs(el)
    38    }
    39    // for template tags, what we want is its content as
    40    // a documentFragment (for fragment instances)
    41    if (isTemplate(el)) {
    42      el = parseTemplate(el)
    43    }
    44    if (options) {
    45      if (options._asComponent && !options.template) {
    46        options.template = '<slot></slot>'
    47      }
    48      if (options.template) {
    49        options._content = extractContent(el)
    50        el = transcludeTemplate(el, options)
    51      }
    52    }
    53    if (isFragment(el)) {
    54      // anchors for fragment instance
    55      // passing in `persist: true` to avoid them being
    56      // discarded by IE during template cloning
    57      prepend(createAnchor('v-start', true), el)
    58      el.appendChild(createAnchor('v-end', true))
    59    }
    60    return el
    61  }
    62  
    63  /**
    64   * Process the template option.
    65   * If the replace option is true this will swap the $el.
    66   *
    67   * @param {Element} el
    68   * @param {Object} options
    69   * @return {Element|DocumentFragment}
    70   */
    71  
    72  function transcludeTemplate (el, options) {
    73    var template = options.template
    74    var frag = parseTemplate(template, true)
    75    if (frag) {
    76      var replacer = frag.firstChild
    77      var tag = replacer.tagName && replacer.tagName.toLowerCase()
    78      if (options.replace) {
    79        /* istanbul ignore if */
    80        if (el === document.body) {
    81          process.env.NODE_ENV !== 'production' && warn(
    82            'You are mounting an instance with a template to ' +
    83            '<body>. This will replace <body> entirely. You ' +
    84            'should probably use `replace: false` here.'
    85          )
    86        }
    87        // there are many cases where the instance must
    88        // become a fragment instance: basically anything that
    89        // can create more than 1 root nodes.
    90        if (
    91          // multi-children template
    92          frag.childNodes.length > 1 ||
    93          // non-element template
    94          replacer.nodeType !== 1 ||
    95          // single nested component
    96          tag === 'component' ||
    97          resolveAsset(options, 'components', tag) ||
    98          hasBindAttr(replacer, 'is') ||
    99          // element directive
   100          resolveAsset(options, 'elementDirectives', tag) ||
   101          // for block
   102          replacer.hasAttribute('v-for') ||
   103          // if block
   104          replacer.hasAttribute('v-if')
   105        ) {
   106          return frag
   107        } else {
   108          options._replacerAttrs = extractAttrs(replacer)
   109          mergeAttrs(el, replacer)
   110          return replacer
   111        }
   112      } else {
   113        el.appendChild(frag)
   114        return el
   115      }
   116    } else {
   117      process.env.NODE_ENV !== 'production' && warn(
   118        'Invalid template option: ' + template
   119      )
   120    }
   121  }
   122  
   123  /**
   124   * Helper to extract a component container's attributes
   125   * into a plain object array.
   126   *
   127   * @param {Element} el
   128   * @return {Array}
   129   */
   130  
   131  function extractAttrs (el) {
   132    if (el.nodeType === 1 && el.hasAttributes()) {
   133      return toArray(el.attributes)
   134    }
   135  }
   136  
   137  /**
   138   * Merge the attributes of two elements, and make sure
   139   * the class names are merged properly.
   140   *
   141   * @param {Element} from
   142   * @param {Element} to
   143   */
   144  
   145  function mergeAttrs (from, to) {
   146    var attrs = from.attributes
   147    var i = attrs.length
   148    var name, value
   149    while (i--) {
   150      name = attrs[i].name
   151      value = attrs[i].value
   152      if (!to.hasAttribute(name) && !specialCharRE.test(name)) {
   153        to.setAttribute(name, value)
   154      } else if (name === 'class' && !parseText(value) && (value = value.trim())) {
   155        value.split(/\s+/).forEach(function (cls) {
   156          addClass(to, cls)
   157        })
   158      }
   159    }
   160  }