function( eventaur, settings ) {
  var gith = this;
  this.settings = settings || {};

  // make this bad boy an event emitter
  EventEmitter2.call( this, {
    delimiter: ':',
    maxListeners: 0
  });

  // handle bound payloads
  eventaur.on( 'payload', function( originalPayload ) {

    // make a simpler payload
    var payload = gith.simplifyPayload( originalPayload );

    // bother doing anything?
    if ( filterSettings( settings, payload ) ) {

      // all the things
      gith.emit( 'all', payload );

      // did we do any branch work?
      if ( originalPayload.created && originalPayload.forced && payload.branch ) {
        gith.emit( 'branch:add', payload );
      }
      if (  originalPayload.deleted && originalPayload.forced && payload.branch ) {
        gith.emit( 'branch:delete', payload );
      }

      // how about files?
      if ( payload.files.added.length > 0 ) {
        gith.emit( 'file:add', payload );
      }
      if ( payload.files.deleted.length > 0 ) {
        gith.emit( 'file:delete', payload );
      }
      if ( payload.files.modified.length > 0 ) {
        gith.emit( 'file:modify', payload );
      }
      if ( payload.files.all.length > 0 ) {
        gith.emit( 'file:all', payload );
      }

      // tagging?
      if ( payload.tag && originalPayload.created ) {
        gith.emit( 'tag:add', payload );
      }
      if ( payload.tag && originalPayload.deleted ) {
        gith.emit( 'tag:delete', payload );
      }
    }
  });
}

function
(
eventaur
,
settings
)
{
var
gith
=
this
;
this
.
settings
=
settings
||
{
}
;
// make this bad boy an event emitter
EventEmitter2
.
call
(
this
,
{
delimiter
:
':'
,
maxListeners
:
0
}
)
;
// handle bound payloads
eventaur
.
on
(
'payload'
,
function
(
originalPayload
)
{
// make a simpler payload
var
payload
=
gith
.
simplifyPayload
(
originalPayload
)
;
// bother doing anything?
if
(
filterSettings
(
settings
,
payload
)
)
{
// all the things
gith
.
emit
(
'all'
,
payload
)
;
// did we do any branch work?
if
(
originalPayload
.
created
&&
originalPayload
.
forced
&&
payload
.
branch
)
{
gith
.
emit
(
'branch:add'
,
payload
)
;
}
if
(
originalPayload
.
deleted
&&
originalPayload
.
forced
&&
payload
.
branch
)
{
gith
.
emit
(
'branch:delete'
,
payload
)
;
}
// how about files?
if
(
payload
.
files
.
added
.
length
>
0
)
{
gith
.
emit
(
'file:add'
,
payload
)
;
}
if
(
payload
.
files
.
deleted
.
length
>
0
)
{
gith
.
emit
(
'file:delete'
,
payload
)
;
}
if
(
payload
.
files
.
modified
.
length
>
0
)
{
gith
.
emit
(
'file:modify'
,
payload
)
;
}
if
(
payload
.
files
.
all
.
length
>
0
)
{
gith
.
emit
(
'file:all'
,
payload
)
;
}
// tagging?
if
(
payload
.
tag
&&
originalPayload
.
created
)
{
gith
.
emit
(
'tag:add'
,
payload
)
;
}
if
(
payload
.
tag
&&
originalPayload
.
deleted
)
{
gith
.
emit
(
'tag:delete'
,
payload
)
;
}
}
}
)
;
}

Used by exports.module.create's returned function to create new gith objects that hold settings and emit events

Used by exports . module . create s returned function to create new gith objects that hold settings and emit events


function buildConfig(wantedEnv) {
  let isValid = wantedEnv && wantedEnv.length > 0 && allowedEnvs.indexOf(wantedEnv) !== -1;
  let validEnv = isValid ? wantedEnv : 'dev';
  let config = require(path.join(__dirname, 'cfg/' + validEnv));
  return config;
}

function buildConfig ( wantedEnv ) { let isValid = wantedEnv && wantedEnv . length > 0 && allowedEnvs . indexOf ( wantedEnv ) !== - 1 ; let validEnv = isValid ? wantedEnv : 'dev' ; let config = require ( path . join ( __dirname , 'cfg/' + validEnv ) ) ; return config ; }

Build the webpack configuration
@param  {String} wantedEnv The wanted environment
@return {Object} Webpack config


function createImageData(image) {
  const canvas = document.createElement('canvas')
  const ctx = canvas.getContext('2d')
  const width = image.naturalWidth
  const height = image.naturalHeight

  canvas.width = width
  canvas.height = height

  ctx.drawImage(image, 0, 0)

  return ctx.getImageData(0, 0, image.naturalWidth, image.naturalHeight)
}

function createImageData ( image ) { const canvas = document . createElement ( 'canvas' ) const ctx = canvas . getContext ( '2d' ) const width = image . naturalWidth const height = image . naturalHeight canvas . width = width canvas . height = height ctx . drawImage ( image , 0 , 0 ) return ctx . getImageData ( 0 , 0 , image . naturalWidth , image . naturalHeight ) }

Creates image data from HTML image
@param {HTMLImageElement} image HTML Image element


async function getImageDataFromSource(source) {
  const isStringSource = typeof source === 'string'
  const isURLSource = isStringSource ? isUrl(source) : false
  const { tagName } = source

  return new Promise((resolve, reject) => {
    // String source
    if (isStringSource) {
      // Read file in Node.js
      if (isNode) {
        Jimp.read(
          isURLSource ? { url: source, headers: {} } : source,
          (err, image) => {
            if (err) {
              reject(err)
            } else {
              const { data, width, height } = image.bitmap
              resolve({
                data: data.toJSON().data,
                width,
                height,
              })
            }
          }
        )
      } else if (isURLSource) {
        // Load Image from source
        const img = new Image()
        img.onerror = reject
        img.onload = () => resolve(createImageData(img))
        img.src = source
      } else {
        // Find Elment by ID
        const imgElem = document.getElementById(source)
        if (imgElem) {
          resolve(createImageData(imgElem))
        }

        reject(new Error('Invalid image source specified!'))
      }
    } else if (tagName) {
      // HTML Image element
      if (tagName === 'IMG') {
        resolve(createImageData(source))
      }
      // HTML Canvas element
      else if (tagName === 'CANVAS') {
        resolve(
          source
            .getContext('2d')
            .getImageData(0, 0, source.naturalWidth, source.naturalHeight)
        )
      }

      reject(new Error('Invalid image source specified!'))
    }
    // Pixel Data
    else if (source.data && source.width && source.height) {
      resolve(source)
    } else {
      reject(new Error('Invalid image source specified!'))
    }
  })
}

async
function
getImageDataFromSource
(
source
)
{
const
isStringSource
=
typeof
source
===
'string'
const
isURLSource
=
isStringSource
isUrl
(
source
)
:
false
const
{
tagName
}
=
source
return
new
Promise
(
(
resolve
,
reject
)
=>
{
// String source
if
(
isStringSource
)
{
// Read file in Node.js
if
(
isNode
)
{
Jimp
.
read
(
isURLSource
{
url
:
source
,
headers
:
{
}
}
:
source
,
(
err
,
image
)
=>
{
if
(
err
)
{
reject
(
err
)
}
else
{
const
{
data
,
width
,
height
}
=
image
.
bitmap
resolve
(
{
data
:
data
.
toJSON
(
)
.
data
,
width
,
height
,
}
)
}
}
)
}
else
if
(
isURLSource
)
{
// Load Image from source
const
img
=
new
Image
(
)
img
.
onerror
=
reject
img
.
onload
=
(
)
=>
resolve
(
createImageData
(
img
)
)
img
.
src
=
source
}
else
{
// Find Elment by ID
const
imgElem
=
document
.
getElementById
(
source
)
if
(
imgElem
)
{
resolve
(
createImageData
(
imgElem
)
)
}
reject
(
new
Error
(
'Invalid image source specified!'
)
)
}
}
else
if
(
tagName
)
{
// HTML Image element
if
(
tagName
===
'IMG'
)
{
resolve
(
createImageData
(
source
)
)
}
// HTML Canvas element
else
if
(
tagName
===
'CANVAS'
)
{
resolve
(
source
.
getContext
(
'2d'
)
.
getImageData
(
0
,
0
,
source
.
naturalWidth
,
source
.
naturalHeight
)
)
}
reject
(
new
Error
(
'Invalid image source specified!'
)
)
}
// Pixel Data
else
if
(
source
.
data
&&
source
.
width
&&
source
.
height
)
{
resolve
(
source
)
}
else
{
reject
(
new
Error
(
'Invalid image source specified!'
)
)
}
}
)
}

Reads image source and returns imageData as only callback parameter
@param {*} source Image source
@param {Function} callback Callback to pass the imageData


function stdopts (opts) {
  opts = opts || {}
  opts.keys = opts.keys !== false // default keys to true
  opts.values = opts.values !== false // default values to true
  return opts
}

function
stdopts
(
opts
)
{
opts
=
opts
||
{
}
opts
.
keys
=
opts
.
keys
!==
false
// default keys to true
opts
.
values
=
opts
.
values
!==
false
// default values to true
return
opts
}

opts standardized to work like levelup api


function update_time(element)
    {
        var settings = element.data("easydate.settings");

        var element_id = $.data(element[0]);
        elements[element_id] = element;
        delete updates[element_id];

        var date = get_date(element, settings);

        if(isNaN(date))
            return;

        element.html(format_date(date, settings));

        if(settings.live)
        {
            var timeout = get_timeout_delay(date, settings);
            if(!isNaN(timeout))
            {
                if(timeout > 2147483647)
                    timeout = 2147483647; // max Firefox timeout delay

                var id = setTimeout(
                    function() { update_time(element); },
                    Math.round(timeout)
                );
                updates[element_id] = id;
            }
        }
    }

function
update_time
(
element
)
{
var
settings
=
element
.
data
(
"easydate.settings"
)
;
var
element_id
=
$
.
data
(
element
[
0
]
)
;
elements
[
element_id
]
=
element
;
delete
updates
[
element_id
]
;
var
date
=
get_date
(
element
,
settings
)
;
if
(
isNaN
(
date
)
)
return
;
element
.
html
(
format_date
(
date
,
settings
)
)
;
if
(
settings
.
live
)
{
var
timeout
=
get_timeout_delay
(
date
,
settings
)
;
if
(
!
isNaN
(
timeout
)
)
{
if
(
timeout
>
2147483647
)
timeout
=
2147483647
;
// max Firefox timeout delay
var
id
=
setTimeout
(
function
(
)
{
update_time
(
element
)
;
}
,
Math
.
round
(
timeout
)
)
;
updates
[
element_id
]
=
id
;
}
}
}

Updates the given element's innerHTML based on the time it represents.

Updates the given element s innerHTML based on the time it represents .


function(type) {
        var qp = {error: type, state: props.state};
        res.redirect(props.redirect_uri + "?" + qs.stringify(qp));
    }

function ( type ) { var qp = { error : type , state : props . state } ; res . redirect ( props . redirect_uri + "?" + qs . stringify ( qp ) ) ; }


function(props) {
            var inst,
                cls = this,
                key = props[cls.keyAttr];

            if (key && _.has(cls.cache, key)) {

                inst = cls.cache[key];
                // Check the updated flag
                inst.merge(props);

            } else {
                inst = new cls(props);

                if (key) {
                    cls.cache[key] = inst;
                }

                inst.on("change:"+cls.keyAttr, function(model, key) {
                    var oldKey = model.previous(cls.keyAttr);
                    if (oldKey && _.has(cls.cache, oldKey)) {
                        delete cls.cache[oldKey];
                    }
                    cls.cache[key] = inst;
                });
            }

            return inst;
        }

function
(
props
)
{
var
inst
,
cls
=
this
,
key
=
props
[
cls
.
keyAttr
]
;
if
(
key
&&
_
.
has
(
cls
.
cache
,
key
)
)
{
inst
=
cls
.
cache
[
key
]
;
// Check the updated flag
inst
.
merge
(
props
)
;
}
else
{
inst
=
new
cls
(
props
)
;
if
(
key
)
{
cls
.
cache
[
key
]
=
inst
;
}
inst
.
on
(
"change:"
+
cls
.
keyAttr
,
function
(
model
,
key
)
{
var
oldKey
=
model
.
previous
(
cls
.
keyAttr
)
;
if
(
oldKey
&&
_
.
has
(
cls
.
cache
,
oldKey
)
)
{
delete
cls
.
cache
[
oldKey
]
;
}
cls
.
cache
[
key
]
=
inst
;
}
)
;
}
return
inst
;
}

works for activities and activityobjects


function(range, touchingIsIntersecting) {
            assertRangeValid(this);

            if (getRangeDocument(range) != getRangeDocument(this)) {
                throw new DOMException("WRONG_DOCUMENT_ERR");
            }

            var startComparison = dom.comparePoints(this.startContainer, this.startOffset, range.endContainer, range.endOffset),
                endComparison = dom.comparePoints(this.endContainer, this.endOffset, range.startContainer, range.startOffset);

            return touchingIsIntersecting ? startComparison <= 0 && endComparison >= 0 : startComparison < 0 && endComparison > 0;
        }

function ( range , touchingIsIntersecting ) { assertRangeValid ( this ) ; if ( getRangeDocument ( range ) != getRangeDocument ( this ) ) { throw new DOMException ( "WRONG_DOCUMENT_ERR" ) ; } var startComparison = dom . comparePoints ( this . startContainer , this . startOffset , range . endContainer , range . endOffset ) , endComparison = dom . comparePoints ( this . endContainer , this . endOffset , range . startContainer , range . startOffset ) ; return touchingIsIntersecting ? startComparison <= 0 && endComparison >= 0 : startComparison < 0 && endComparison > 0 ; }

The methods below are non-standard and invented by me. Sharing a boundary start-to-end or end-to-start does not count as intersection.

The methods below are non - standard and invented by me . Sharing a boundary start - to - end or end - to - start does not count as intersection .


function(sel, range) {
        var ranges = sel.getAllRanges(), removed = false;
        sel.removeAllRanges();
        for (var i = 0, len = ranges.length; i < len; ++i) {
            if (removed || range !== ranges[i]) {
                sel.addRange(ranges[i]);
            } else {
                // According to the draft WHATWG Range spec, the same range may be added to the selection multiple
                // times. removeRange should only remove the first instance, so the following ensures only the first
                // instance is removed
                removed = true;
            }
        }
        if (!sel.rangeCount) {
            updateEmptySelection(sel);
        }
    }


function(needle) {
      if (arr.indexOf) {
        return arr.indexOf(needle) !== -1;
      } else {
        for (var i=0, length=arr.length; i<length; i++) {
          if (arr[i] === needle) { return true; }
        }
        return false;
      }
    }

function ( needle ) { if ( arr . indexOf ) { return arr . indexOf ( needle ) !== - 1 ; } else { for ( var i = 0 , length = arr . length ; i < length ; i ++ ) { if ( arr [ i ] === needle ) { return true ; } } return false ; } }

Check whether a given object exists in an array

@example
wysihtml5.lang.array([1, 2]).contains(1);
// => true


function _wrapMatchesInNode(textNode) {
    var parentNode  = textNode.parentNode,
        tempElement = _getTempElement(parentNode.ownerDocument);

    // We need to insert an empty/temporary  to fix IE quirks
    // Elsewise IE would strip white space in the beginning
    tempElement.innerHTML = "" + _convertUrlsToLinks(textNode.data);
    tempElement.removeChild(tempElement.firstChild);

    while (tempElement.firstChild) {
      // inserts tempElement.firstChild before textNode
      parentNode.insertBefore(tempElement.firstChild, textNode);
    }
    parentNode.removeChild(textNode);
  }

// We need to insert an empty/temporary <span /> to fix IE quirks

Replaces the original text nodes with the newly auto-linked dom tree

Replaces the original text nodes with the newly auto - linked dom tree


function parse(elementOrHtml, rules, context, cleanUp) {
    wysihtml5.lang.object(currentRules).merge(defaultRules).merge(rules).get();

    context           = context || elementOrHtml.ownerDocument || document;
    var fragment      = context.createDocumentFragment(),
        isString      = typeof(elementOrHtml) === "string",
        element,
        newNode,
        firstChild;

    if (isString) {
      element = wysihtml5.dom.getAsDom(elementOrHtml, context);
    } else {
      element = elementOrHtml;
    }

    while (element.firstChild) {
      firstChild  = element.firstChild;
      element.removeChild(firstChild);
      newNode = _convert(firstChild, cleanUp);
      if (newNode) {
        fragment.appendChild(newNode);
      }
    }

    // Clear element contents
    element.innerHTML = "";

    // Insert new DOM tree
    element.appendChild(fragment);

    return isString ? wysihtml5.quirks.getCorrectInnerHTML(element) : element;
  }

function
parse
(
elementOrHtml
,
rules
,
context
,
cleanUp
)
{
wysihtml5
.
lang
.
object
(
currentRules
)
.
merge
(
defaultRules
)
.
merge
(
rules
)
.
get
(
)
;
context
=
context
||
elementOrHtml
.
ownerDocument
||
document
;
var
fragment
=
context
.
createDocumentFragment
(
)
,
isString
=
typeof
(
elementOrHtml
)
===
"string"
,
element
,
newNode
,
firstChild
;
if
(
isString
)
{
element
=
wysihtml5
.
dom
.
getAsDom
(
elementOrHtml
,
context
)
;
}
else
{
element
=
elementOrHtml
;
}
while
(
element
.
firstChild
)
{
firstChild
=
element
.
firstChild
;
element
.
removeChild
(
firstChild
)
;
newNode
=
_convert
(
firstChild
,
cleanUp
)
;
if
(
newNode
)
{
fragment
.
appendChild
(
newNode
)
;
}
}
// Clear element contents
element
.
innerHTML
=
""
;
// Insert new DOM tree
element
.
appendChild
(
fragment
)
;
return
isString
wysihtml5
.
quirks
.
getCorrectInnerHTML
(
element
)
:
element
;
}

Iterates over all childs of the element, recreates them, appends them into a document fragment
which later replaces the entire body content

Iterates over all childs of the element recreates them appends them into a document fragment which later replaces the entire body content


function(iframe) {
      // don't resume when the iframe got unloaded (eg. by removing it from the dom)
      if (!wysihtml5.dom.contains(doc.documentElement, iframe)) {
        return;
      }

      var that           = this,
          iframeWindow   = iframe.contentWindow,
          iframeDocument = iframe.contentWindow.document,
          charset        = doc.characterSet || doc.charset || "utf-8",
          sandboxHtml    = this._getHtml({
            charset:      charset,
            stylesheets:  this.config.stylesheets
          });

      // Create the basic dom tree including proper DOCTYPE and charset
      iframeDocument.open("text/html", "replace");
      iframeDocument.write(sandboxHtml);
      iframeDocument.close();

      this.getWindow = function() { return iframe.contentWindow; };
      this.getDocument = function() { return iframe.contentWindow.document; };

      // Catch js errors and pass them to the parent's onerror event
      // addEventListener("error") doesn't work properly in some browsers
      // TODO: apparently this doesn't work in IE9!
      iframeWindow.onerror = function(errorMessage, fileName, lineNumber) {
        throw new Error("wysihtml5.Sandbox: " + errorMessage, fileName, lineNumber);
      };

      if (!wysihtml5.browser.supportsSandboxedIframes()) {
        // Unset a bunch of sensitive variables
        // Please note: This isn't hack safe!
        // It more or less just takes care of basic attacks and prevents accidental theft of sensitive information
        // IE is secure though, which is the most important thing, since IE is the only browser, who
        // takes over scripts & styles into contentEditable elements when copied from external websites
        // or applications (Microsoft Word, ...)
        var i, length;
        for (i=0, length=windowProperties.length; i<length; i++) {
          this._unset(iframeWindow, windowProperties[i]);
        }
        for (i=0, length=windowProperties2.length; i<length; i++) {
          this._unset(iframeWindow, windowProperties2[i], wysihtml5.EMPTY_FUNCTION);
        }
        for (i=0, length=documentProperties.length; i<length; i++) {
          this._unset(iframeDocument, documentProperties[i]);
        }
        // This doesn't work in Safari 5
        // See http://stackoverflow.com/questions/992461/is-it-possible-to-override-document-cookie-in-webkit
        this._unset(iframeDocument, "cookie", "", true);
      }

      this.loaded = true;

      // Trigger the callback
      setTimeout(function() { that.callback(that); }, 0);
    }

Callback for when the iframe has finished loading


function(html) {
      var range     = rangy.createRange(this.doc),
          node      = range.createContextualFragment(html),
          lastChild = node.lastChild;
      this.insertNode(node);
      if (lastChild) {
        this.setAfter(lastChild);
      }
    }

function ( html ) { var range = rangy . createRange ( this . doc ) , node = range . createContextualFragment ( html ) , lastChild = node . lastChild ; this . insertNode ( node ) ; if ( lastChild ) { this . setAfter ( lastChild ) ; } }

Insert html at the caret position and move the cursor after the inserted html

@param {String} html HTML string to insert
@example
selection.insertHTML("
foobar
");


function(node) {
      var range = this.getRange();
      if (!range) {
        return;
      }

      try {
        // This only works when the range boundaries are not overlapping other elements
        range.surroundContents(node);
        this.selectNode(node);
      } catch(e) {
        // fallback
        node.appendChild(range.extractContents());
        range.insertNode(node);
      }
    }

Wraps current selection with the given node

@param {Object} node The node to surround the selected elements with


function(textNodes, range) {
      var firstNode = textNodes[0], lastNode = textNodes[textNodes.length - 1];

      var merges = [], currentMerge;

      var rangeStartNode = firstNode, rangeEndNode = lastNode;
      var rangeStartOffset = 0, rangeEndOffset = lastNode.length;

      var textNode, precedingTextNode;

      for (var i = 0, len = textNodes.length; i < len; ++i) {
        textNode = textNodes[i];
        precedingTextNode = this.getAdjacentMergeableTextNode(textNode.parentNode, false);
        if (precedingTextNode) {
          if (!currentMerge) {
            currentMerge = new Merge(precedingTextNode);
            merges.push(currentMerge);
          }
          currentMerge.textNodes.push(textNode);
          if (textNode === firstNode) {
            rangeStartNode = currentMerge.firstTextNode;
            rangeStartOffset = rangeStartNode.length;
          }
          if (textNode === lastNode) {
            rangeEndNode = currentMerge.firstTextNode;
            rangeEndOffset = currentMerge.getLength();
          }
        } else {
          currentMerge = null;
        }
      }

      // Test whether the first node after the range needs merging
      var nextTextNode = this.getAdjacentMergeableTextNode(lastNode.parentNode, true);
      if (nextTextNode) {
        if (!currentMerge) {
          currentMerge = new Merge(lastNode);
          merges.push(currentMerge);
        }
        currentMerge.textNodes.push(nextTextNode);
      }

      // Do the merges
      if (merges.length) {
        for (i = 0, len = merges.length; i < len; ++i) {
          merges[i].doMerge();
        }
        // Set the range boundaries
        range.setStart(rangeStartNode, rangeStartOffset);
        range.setEnd(rangeEndNode, rangeEndOffset);
      }
    }

Normalizes nodes after applying a CSS class to a Range.

Normalizes nodes after applying a CSS class to a Range .


function(command) {
    var obj     = wysihtml5.commands[command],
        method  = obj && obj.value;
    if (method) {
      return method.call(obj, this.composer, command);
    } else {
      try {
        // try/catch for buggy firefox
        return this.doc.queryCommandValue(command);
      } catch(e) {
        return null;
      }
    }
  }

function
(
command
)
{
var
obj
=
wysihtml5
.
commands
[
command
]
,
method
=
obj
&&
obj
.
value
;
if
(
method
)
{
return
method
.
call
(
obj
,
this
.
composer
,
command
)
;
}
else
{
try
{
// try/catch for buggy firefox
return
this
.
doc
.
queryCommandValue
(
command
)
;
}
catch
(
e
)
{
return
;
}
}
}

Get the current command's value

@param {String} command The command string which to check (eg. "formatBlock")
@return {String} The command value
@example
var currentBlockElement = commands.value("formatBlock");


function _isBlankTextNode(node) {
    return node.nodeType === wysihtml5.TEXT_NODE && !wysihtml5.lang.string(node.data).trim();
  }

function _isBlankTextNode ( node ) { return node . nodeType === wysihtml5 . TEXT_NODE && ! wysihtml5 . lang . string ( node . data ) . trim ( ) ; }

Check whether given node is a text node and whether it's empty

Check whether given node is a text node and whether it s empty


function _getPreviousSiblingThatIsNotBlank(node) {
    var previousSibling = node.previousSibling;
    while (previousSibling && _isBlankTextNode(previousSibling)) {
      previousSibling = previousSibling.previousSibling;
    }
    return previousSibling;
  }

function _getPreviousSiblingThatIsNotBlank ( node ) { var previousSibling = node . previousSibling ; while ( previousSibling && _isBlankTextNode ( previousSibling ) ) { previousSibling = previousSibling . previousSibling ; } return previousSibling ; }

Returns previous sibling node that is not a blank text node


function _getNextSiblingThatIsNotBlank(node) {
    var nextSibling = node.nextSibling;
    while (nextSibling && _isBlankTextNode(nextSibling)) {
      nextSibling = nextSibling.nextSibling;
    }
    return nextSibling;
  }

function _getNextSiblingThatIsNotBlank ( node ) { var nextSibling = node . nextSibling ; while ( nextSibling && _isBlankTextNode ( nextSibling ) ) { nextSibling = nextSibling . nextSibling ; } return nextSibling ; }

Returns next sibling node that is not a blank text node


function _removeLineBreakBeforeAndAfter(node) {
    var nextSibling     = _getNextSiblingThatIsNotBlank(node),
        previousSibling = _getPreviousSiblingThatIsNotBlank(node);

    if (nextSibling && _isLineBreak(nextSibling)) {
      nextSibling.parentNode.removeChild(nextSibling);
    }
    if (previousSibling && _isLineBreak(previousSibling)) {
      previousSibling.parentNode.removeChild(previousSibling);
    }
  }

function _removeLineBreakBeforeAndAfter ( node ) { var nextSibling = _getNextSiblingThatIsNotBlank ( node ) , previousSibling = _getPreviousSiblingThatIsNotBlank ( node ) ; if ( nextSibling && _isLineBreak ( nextSibling ) ) { nextSibling . parentNode . removeChild ( nextSibling ) ; } if ( previousSibling && _isLineBreak ( previousSibling ) ) { previousSibling . parentNode . removeChild ( previousSibling ) ; } }

Removes line breaks before and after the given node


function _execCommand(doc, command, nodeName, className) {
    if (className) {
      var eventListener = dom.observe(doc, "DOMNodeInserted", function(event) {
        var target = event.target,
            displayStyle;
        if (target.nodeType !== wysihtml5.ELEMENT_NODE) {
          return;
        }
        displayStyle = dom.getStyle("display").from(target);
        if (displayStyle.substr(0, 6) !== "inline") {
          // Make sure that only block elements receive the given class
          target.className += " " + className;
        }
      });
    }
    doc.execCommand(command, false, nodeName);
    if (eventListener) {
      eventListener.stop();
    }
  }

Execute native query command
and if necessary modify the inserted node's className

Execute native query command and if necessary modify the inserted node s className


function(avoidHiddenFields) {
      var field,
          fieldName,
          newValue,
          focusedElement = document.querySelector(":focus"),
          fields         = this.container.querySelectorAll(SELECTOR_FIELDS),
          length         = fields.length,
          i              = 0;
      for (; i<length; i++) {
        field = fields[i];

        // Never change elements where the user is currently typing in
        if (field === focusedElement) {
          continue;
        }

        // Don't update hidden fields
        // See https://github.com/xing/wysihtml5/pull/14
        if (avoidHiddenFields && field.type === "hidden") {
          continue;
        }

        fieldName = field.getAttribute(ATTRIBUTE_FIELDS);
        newValue  = this.elementToChange ? (this.elementToChange[fieldName] || "") : field.defaultValue;
        field.value = newValue;
      }
    }

Takes the attributes of the "elementToChange"
and inserts them in their corresponding dialog input fields

Assume the "elementToChange" looks like this:
foo

and we have the following dialog:
<input type="text" data-wysihtml5-dialog-field="href" value="">
<input type="text" data-wysihtml5-dialog-field="target" value="">

after calling _interpolate() the dialog will look like this
<input type="text" data-wysihtml5-dialog-field="href" value="http://www.google.com">
<input type="text" data-wysihtml5-dialog-field="target" value="_blank">

Basically it adopted the attribute values into the corresponding input fields

Takes the attributes of the elementToChange and inserts them in their corresponding dialog input fields


function(elementToChange) {
      var that        = this,
          firstField  = this.container.querySelector(SELECTOR_FORM_ELEMENTS);
      this.elementToChange = elementToChange;
      this._observe();
      this._interpolate();
      if (elementToChange) {
        this.interval = setInterval(function() { that._interpolate(true); }, 500);
      }
      dom.addClass(this.link, CLASS_NAME_OPENED);
      this.container.style.display = "";
      this.fire("show");
      if (firstField && !elementToChange) {
        try {
          firstField.focus();
        } catch(e) {}
      }
    }

function ( elementToChange ) { var that = this , firstField = this . container . querySelector ( SELECTOR_FORM_ELEMENTS ) ; this . elementToChange = elementToChange ; this . _observe ( ) ; this . _interpolate ( ) ; if ( elementToChange ) { this . interval = setInterval ( function ( ) { that . _interpolate ( true ) ; } , 500 ) ; } dom . addClass ( this . link , CLASS_NAME_OPENED ) ; this . container . style . display = "" ; this . fire ( "show" ) ; if ( firstField && ! elementToChange ) { try { firstField . focus ( ) ; } catch ( e ) { } } }


function() {
      this.observe("paste:composer", function() {
        var keepScrollPosition  = true,
            that                = this;
        that.composer.selection.executeAndRestore(function() {
          wysihtml5.quirks.cleanPastedHTML(that.composer.element);
          that.parse(that.composer.element);
        }, keepScrollPosition);
      });

      this.observe("paste:textarea", function() {
        var value   = this.textarea.getValue(),
            newValue;
        newValue = this.parse(value);
        this.textarea.setValue(newValue);
      });
    }

function ( ) { this . observe ( "paste:composer" , function ( ) { var keepScrollPosition = true , that = this ; that . composer . selection . executeAndRestore ( function ( ) { wysihtml5 . quirks . cleanPastedHTML ( that . composer . element ) ; that . parse ( that . composer . element ) ; } , keepScrollPosition ) ; } ) ; this . observe ( "paste:textarea" , function ( ) { var value = this . textarea . getValue ( ) , newValue ; newValue = this . parse ( value ) ; this . textarea . setValue ( newValue ) ; } ) ; }

Prepare html parser logic
- Observes for paste and drop


function getParameterList(parameters) {
        if (parameters == null) {
            return [];
        }
        if (typeof parameters != "object") {
            return OAuth.decodeForm(parameters + "");
        }
        if (parameters instanceof Array) {
            return parameters;
        }
        var list = [];
        for (var p in parameters) {
            list.push([p, parameters[p]]);
        }
        return list;
    }

function getParameterList ( parameters ) { if ( parameters == null ) { return [ ] ; } if ( typeof parameters != "object" ) { return OAuth . decodeForm ( parameters + "" ) ; } if ( parameters instanceof Array ) { return parameters ; } var list = [ ] ; for ( var p in parameters ) { list . push ( [ p , parameters [ p ] ] ) ; } return list ; }

Convert the given parameters to an Array of name-value pairs.

Convert the given parameters to an Array of name - value pairs .


function getParameterMap(parameters) {
        if (parameters == null) {
            return {};
        }
        if (typeof parameters != "object") {
            return OAuth.getParameterMap(OAuth.decodeForm(parameters + ""));
        }
        if (parameters instanceof Array) {
            var map = {};
            for (var p = 0; p < parameters.length; ++p) {
                var key = parameters[p][0];
                if (map[key] === undefined) { // first value wins
                    map[key] = parameters[p][1];
                }
            }
            return map;
        }
        return parameters;
    }

function
getParameterMap
(
parameters
)
{
if
(
parameters
==
)
{
return
{
}
;
}
if
(
typeof
parameters
!=
"object"
)
{
return
OAuth
.
getParameterMap
(
OAuth
.
decodeForm
(
parameters
+
""
)
)
;
}
if
(
parameters
instanceof
Array
)
{
var
map
=
{
}
;
for
(
var
p
=
0
;
p
<
parameters
.
length
;
++
p
)
{
var
key
=
parameters
[
p
]
[
0
]
;
if
(
map
[
key
]
===
undefined
)
{
// first value wins
map
[
key
]
=
parameters
[
p
]
[
1
]
;
}
}
return
map
;
}
return
parameters
;
}

Convert the given parameters to a map from name to value.

Convert the given parameters to a map from name to value .


function getAuthorizationHeader(realm, parameters) {
        var header = 'OAuth realm="' + OAuth.percentEncode(realm) + '"';
        var list = OAuth.getParameterList(parameters);
        for (var p = 0; p < list.length; ++p) {
            var parameter = list[p];
            var name = parameter[0];
            if (name.indexOf("oauth_") == 0) {
                header += ',' + OAuth.percentEncode(name) + '="' + OAuth.percentEncode(parameter[1]) + '"';
            }
        }
        return header;
    }

function
getAuthorizationHeader
(
realm
,
parameters
)
{
var
header
=
'OAuth realm="'
+
OAuth
.
percentEncode
(
realm
)
+
'"'
;
var
list
=
OAuth
.
getParameterList
(
parameters
)
;
for
(
var
p
=
0
;
p
<
list
.
length
;
++
p
)
{
var
parameter
=
list
[
p
]
;
var
name
=
parameter
[
0
]
;
if
(
name
.
indexOf
(
"oauth_"
)
==
0
)
{
header
+=
','
+
OAuth
.
percentEncode
(
name
)
+
'="'
+
OAuth
.
percentEncode
(
parameter
[
1
]
)
+
'"'
;
}
}
return
header
;
}

Construct the value of the Authorization header for an HTTP request.

Construct the value of the Authorization header for an HTTP request .


function correctTimestampFromSrc(parameterName) {
        parameterName = parameterName || "oauth_timestamp";
        var scripts = document.getElementsByTagName('script');
        if (scripts == null || !scripts.length) return;
        var src = scripts[scripts.length-1].src;
        if (!src) return;
        var q = src.indexOf("?");
        if (q < 0) return;
        parameters = OAuth.getParameterMap(OAuth.decodeForm(src.substring(q+1)));
        var t = parameters[parameterName];
        if (t == null) return;
        OAuth.correctTimestamp(t);
    }

function correctTimestampFromSrc ( parameterName ) { parameterName = parameterName || "oauth_timestamp" ; var scripts = document . getElementsByTagName ( 'script' ) ; if ( scripts == null || ! scripts . length ) return ; var src = scripts [ scripts . length - 1 ] . src ; if ( ! src ) return ; var q = src . indexOf ( "?" ) ; if ( q < 0 ) return ; parameters = OAuth . getParameterMap ( OAuth . decodeForm ( src . substring ( q + 1 ) ) ) ; var t = parameters [ parameterName ] ; if ( t == null ) return ; OAuth . correctTimestamp ( t ) ; }

Correct the time using a parameter from the URL from which the last script was loaded.

Correct the time using a parameter from the URL from which the last script was loaded .


function sign(message) {
        var baseString = OAuth.SignatureMethod.getBaseString(message);
        var signature = this.getSignature(baseString);
        OAuth.setParameter(message, "oauth_signature", signature);
        return signature; // just in case someone's interested
    }

function
sign
(
message
)
{
var
baseString
=
OAuth
.
SignatureMethod
.
getBaseString
(
message
)
;
var
signature
=
this
.
getSignature
(
baseString
)
;
OAuth
.
setParameter
(
message
,
"oauth_signature"
,
signature
)
;
return
signature
;
// just in case someone's interested
}


function initialize(name, accessor) {
        var consumerSecret;
        if (accessor.accessorSecret != null
            && name.length > 9
            && name.substring(name.length-9) == "-Accessor")
        {
            consumerSecret = accessor.accessorSecret;
        } else {
            consumerSecret = accessor.consumerSecret;
        }
        this.key = OAuth.percentEncode(consumerSecret)
             +"&"+ OAuth.percentEncode(accessor.tokenSecret);
    }

function initialize ( name , accessor ) { var consumerSecret ; if ( accessor . accessorSecret != null && name . length > 9 && name . substring ( name . length - 9 ) == "-Accessor" ) { consumerSecret = accessor . accessorSecret ; } else { consumerSecret = accessor . consumerSecret ; } this . key = OAuth . percentEncode ( consumerSecret ) + "&" + OAuth . percentEncode ( accessor . tokenSecret ) ; }


function newMethod(name, accessor) {
        var impl = OAuth.SignatureMethod.REGISTERED[name];
        if (impl != null) {
            var method = new impl();
            method.initialize(name, accessor);
            return method;
        }
        var err = new Error("signature_method_rejected");
        var acceptable = "";
        for (var r in OAuth.SignatureMethod.REGISTERED) {
            if (acceptable != "") acceptable += '&';
            acceptable += OAuth.percentEncode(r);
        }
        err.oauth_acceptable_signature_methods = acceptable;
        throw err;
    }

function newMethod ( name , accessor ) { var impl = OAuth . SignatureMethod . REGISTERED [ name ] ; if ( impl != null ) { var method = new impl ( ) ; method . initialize ( name , accessor ) ; return method ; } var err = new Error ( "signature_method_rejected" ) ; var acceptable = "" ; for ( var r in OAuth . SignatureMethod . REGISTERED ) { if ( acceptable != "" ) acceptable += '&' ; acceptable += OAuth . percentEncode ( r ) ; } err . oauth_acceptable_signature_methods = acceptable ; throw err ; }

Instantiate a SignatureMethod for the given method name.

Instantiate a SignatureMethod for the given method name .


function makeSubclass(getSignatureFunction) {
        var superClass = OAuth.SignatureMethod;
        var subClass = function() {
            superClass.call(this);
        };
        subClass.prototype = new superClass();
        // Delete instance variables from prototype:
        // delete subclass.prototype... There aren't any.
        subClass.prototype.getSignature = getSignatureFunction;
        subClass.prototype.constructor = subClass;
        return subClass;
    }

Create a subclass of OAuth.SignatureMethod, with the given getSignature function.

Create a subclass of OAuth . SignatureMethod with the given getSignature function .


function processInitialData(value, name) {
            if (name == View.prototype.modelName) {
                options.model = def.models[name].unique(value);
            } else if (def.models[name]) {
                    options.data[name] = def.models[name].unique(value);
            } else {
                    options.data[name] = value;
            }
        }

function processInitialData ( value , name ) { if ( name == View . prototype . modelName ) { options . model = def . models [ name ] . unique ( value ) ; } else if ( def . models [ name ] ) { options . data [ name ] = def . models [ name ] . unique ( value ) ; } else { options . data [ name ] = value ; } }

When I say "view" the crowd say "selector"


function vendor(el, prop) {
    var s = el.style
      , pp
      , i

    if(s[prop] !== undefined) return prop
    prop = prop.charAt(0).toUpperCase() + prop.slice(1)
    for(i=0; i<prefixes.length; i++) {
      pp = prefixes[i]+prop
      if(s[pp] !== undefined) return pp
    }
  }

function vendor ( el , prop ) { var s = el . style , pp , i if ( s [ prop ] !== undefined ) return prop prop = prop . charAt ( 0 ) . toUpperCase ( ) + prop . slice ( 1 ) for ( i = 0 ; i < prefixes . length ; i ++ ) { pp = prefixes [ i ] + prop if ( s [ pp ] !== undefined ) return pp } }

Tries various vendor prefixes and returns the first supported property.

Tries various vendor prefixes and returns the first supported property .


function css(el, prop) {
    for (var n in prop)
      el.style[vendor(el, n)||n] = prop[n]

    return el
  }

function css ( el , prop ) { for ( var n in prop ) el . style [ vendor ( el , n ) || n ] = prop [ n ] return el }

Sets multiple style properties at once .


function merge(obj) {
    for (var i=1; i < arguments.length; i++) {
      var def = arguments[i]
      for (var n in def)
        if (obj[n] === undefined) obj[n] = def[n]
    }
    return obj
  }

function merge ( obj ) { for ( var i = 1 ; i < arguments . length ; i ++ ) { var def = arguments [ i ] for ( var n in def ) if ( obj [ n ] === undefined ) obj [ n ] = def [ n ] } return obj }


function pos(el) {
    var o = { x:el.offsetLeft, y:el.offsetTop }
    while((el = el.offsetParent))
      o.x+=el.offsetLeft, o.y+=el.offsetTop

    return o
  }

function pos ( el ) { var o = { x : el . offsetLeft , y : el . offsetTop } while ( ( el = el . offsetParent ) ) o . x += el . offsetLeft , o . y += el . offsetTop return o }

Returns the absolute page-offset of the given element.

Returns the absolute page - offset of the given element .


function splitVal(string, separator) {
        var val, i, l;
        if (string === null || string.length < 1) return [];
        val = string.split(separator);
        for (i = 0, l = val.length; i < l; i = i + 1) val[i] = $.trim(val[i]);
        return val;
    }

function splitVal ( string , separator ) { var val , i , l ; if ( string === null || string . length < 1 ) return [ ] ; val = string . split ( separator ) ; for ( i = 0 , l = val . length ; i < l ; i = i + 1 ) val [ i ] = $ . trim ( val [ i ] ) ; return val ; }

Splits the string into an array of values, trimming each value. An empty array is returned for nulls or empty
strings
@param string
@param separator

Splits the string into an array of values trimming each value . An empty array is returned for nulls or empty strings


function installFilteredMouseMove(element) {
        element.on("mousemove", function (e) {
            var lastpos = lastMousePosition;
            if (lastpos === undefined || lastpos.x !== e.pageX || lastpos.y !== e.pageY) {
                $(e.target).trigger("mousemove-filtered", e);
            }
        });
    }

function installFilteredMouseMove ( element ) { element . on ( "mousemove" , function ( e ) { var lastpos = lastMousePosition ; if ( lastpos === undefined || lastpos . x !== e . pageX || lastpos . y !== e . pageY ) { $ ( e . target ) . trigger ( "mousemove-filtered" , e ) ; } } ) ; }

filters mouse events so an event is fired only if the mouse moved.

filters out mouse events that occur when mouse is stationary but
the elements under the pointer are scrolled.

filters mouse events so an event is fired only if the mouse moved .


function thunk(formula) {
        var evaluated = false,
            value;
        return function() {
            if (evaluated === false) { value = formula(); evaluated = true; }
            return value;
        };
    }

function thunk ( formula ) { var evaluated = false , value ; return function ( ) { if ( evaluated === false ) { value = formula ( ) ; evaluated = true ; } return value ; } ; }

A simple implementation of a thunk
@param formula function used to lazily initialize the thunk
@return {Function}


function checkFormatter(formatter, formatterName) {
        if ($.isFunction(formatter)) return true;
        if (!formatter) return false;
        throw new Error(formatterName +" must be a function or a falsy value");
    }

function
checkFormatter
(
formatter
,
formatterName
)
{
if
(
$
.
isFunction
(
formatter
)
)
return
true
;
if
(
!
formatter
)
return
false
;
throw
new
Error
(
formatterName
+
" must be a function or a falsy value"
)
;
}

Checks if the formatter function should be used.

Throws an error if it is not a function. Returns true if it should be used,
false if no formatting should be performed.

@param formatter

Checks if the formatter function should be used .


function defaultTokenizer(input, selection, selectCallback, opts) {
        var original = input, // store the original so we can compare and know if we need to tell the search to update its text
            dupe = false, // check for whether a token we extracted represents a duplicate selected choice
            token, // token
            index, // position at which the separator was found
            i, l, // looping variables
            separator; // the matched separator

        if (!opts.createSearchChoice || !opts.tokenSeparators || opts.tokenSeparators.length < 1) return undefined;

        while (true) {
            index = -1;

            for (i = 0, l = opts.tokenSeparators.length; i < l; i++) {
                separator = opts.tokenSeparators[i];
                index = input.indexOf(separator);
                if (index >= 0) break;
            }

            if (index < 0) break; // did not find any token separator in the input string, bail

            token = input.substring(0, index);
            input = input.substring(index + separator.length);

            if (token.length > 0) {
                token = opts.createSearchChoice.call(this, token, selection);
                if (token !== undefined && token !== null && opts.id(token) !== undefined && opts.id(token) !== null) {
                    dupe = false;
                    for (i = 0, l = selection.length; i < l; i++) {
                        if (equal(opts.id(token), opts.id(selection[i]))) {
                            dupe = true; break;
                        }
                    }

                    if (!dupe) selectCallback(token);
                }
            }
        }

        if (original!==input) return input;
    }

Default tokenizer. This function uses breaks the input on substring match of any string from the
opts.tokenSeparators array and uses opts.createSearchChoice to create the choice object. Both of those
two options have to be defined in order for the tokenizer to work.

@param input text user has typed so far or pasted into the search field
@param selection currently selected choices
@param selectCallback function(choice) callback tho add the choice to selection
@param opts select2's opts
@return undefined/null to leave the current input unchanged, or a string to change the input to the returned value

Default tokenizer . This function uses breaks the input on substring match of any string from the opts . tokenSeparators array and uses opts . createSearchChoice to create the choice object . Both of those two options have to be defined in order for the tokenizer to work .


function clazz(SuperClass, methods) {
        var constructor = function () {};
        constructor.prototype = new SuperClass;
        constructor.prototype.constructor = constructor;
        constructor.prototype.parent = SuperClass.prototype;
        constructor.prototype = $.extend(constructor.prototype, methods);
        return constructor;
    }

function clazz ( SuperClass , methods ) { var constructor = function ( ) { } ; constructor . prototype = new SuperClass ; constructor . prototype . constructor = constructor ; constructor . prototype . parent = SuperClass . prototype ; constructor . prototype = $ . extend ( constructor . prototype , methods ) ; return constructor ; }

Creates a new class

@param superClass
@param methods


function () {
            var el = this.opts.element, sync;

            el.on("change.select2", this.bind(function (e) {
                if (this.opts.element.data("select2-change-triggered") !== true) {
                    this.initSelection();
                }
            }));

            sync = this.bind(function () {

                var enabled, readonly, self = this;

                // sync enabled state
                var disabled = el.prop("disabled");
                if (disabled === undefined) disabled = false;
                this.enable(!disabled);

                var readonly = el.prop("readonly");
                if (readonly === undefined) readonly = false;
                this.readonly(readonly);

                syncCssClasses(this.container, this.opts.element, this.opts.adaptContainerCssClass);
                this.container.addClass(evaluate(this.opts.containerCssClass));

                syncCssClasses(this.dropdown, this.opts.element, this.opts.adaptDropdownCssClass);
                this.dropdown.addClass(evaluate(this.opts.dropdownCssClass));

            });

            // mozilla and IE
            el.on("propertychange.select2 DOMAttrModified.select2", sync);

            // hold onto a reference of the callback to work around a chromium bug
            if (this.mutationCallback === undefined) {
                this.mutationCallback = function (mutations) {
                    mutations.forEach(sync);
                }
            }

            // safari and chrome
            if (typeof WebKitMutationObserver !== "undefined") {
                if (this.propertyObserver) { delete this.propertyObserver; this.propertyObserver = null; }
                this.propertyObserver = new WebKitMutationObserver(this.mutationCallback);
                this.propertyObserver.observe(el.get(0), { attributes:true, subtree:false });
            }
        }

Monitor the original element for changes and update select2 accordingly
 abstract


function() {
            var cid = this.containerId,
                scroll = "scroll." + cid,
                resize = "resize."+cid,
                orient = "orientationchange."+cid,
                mask, maskCss;

            this.container.addClass("select2-dropdown-open").addClass("select2-container-active");

            this.clearDropdownAlignmentPreference();

            if(this.dropdown[0] !== this.body().children().last()[0]) {
                this.dropdown.detach().appendTo(this.body());
            }

            // create the dropdown mask if doesnt already exist
            mask = $("#select2-drop-mask");
            if (mask.length == 0) {
                mask = $(document.createElement("div"));
                mask.attr("id","select2-drop-mask").attr("class","select2-drop-mask");
                mask.hide();
                mask.appendTo(this.body());
                mask.on("mousedown touchstart click", function (e) {
                    var dropdown = $("#select2-drop"), self;
                    if (dropdown.length > 0) {
                        self=dropdown.data("select2");
                        if (self.opts.selectOnBlur) {
                            self.selectHighlighted({noFocus: true});
                        }
                        self.close();
                        e.preventDefault();
                        e.stopPropagation();
                    }
                });
            }

            // ensure the mask is always right before the dropdown
            if (this.dropdown.prev()[0] !== mask[0]) {
                this.dropdown.before(mask);
            }

            // move the global id to the correct dropdown
            $("#select2-drop").removeAttr("id");
            this.dropdown.attr("id", "select2-drop");

            // show the elements
            maskCss=_makeMaskCss();

            mask.css(maskCss).show();

            this.dropdown.show();
            this.positionDropdown();

            this.dropdown.addClass("select2-drop-active");

            // attach listeners to events that can change the position of the container and thus require
            // the position of the dropdown to be updated as well so it does not come unglued from the container
            var that = this;
            this.container.parents().add(window).each(function () {
                $(this).on(resize+" "+scroll+" "+orient, function (e) {
                    var maskCss=_makeMaskCss();
                    $("#select2-drop-mask").css(maskCss);
                    that.positionDropdown();
                });
            });

            function _makeMaskCss() {
                return {
                    width  : Math.max(document.documentElement.scrollWidth,  $(window).width()),
                    height : Math.max(document.documentElement.scrollHeight, $(window).height())
                }
            }
        }

Performs the opening of the dropdown
 abstract


function SubEmitterSocket() {
  this.sock = new SubSocket;
  this.sock.onmessage = this.onmessage.bind(this);
  this.bind = this.sock.bind.bind(this.sock);
  this.connect = this.sock.connect.bind(this.sock);
  this.close = this.sock.close.bind(this.sock);
  this.listeners = [];
}

function SubEmitterSocket ( ) { this . sock = new SubSocket ; this . sock . onmessage = this . onmessage . bind ( this ) ; this . bind = this . sock . bind . bind ( this . sock ) ; this . connect = this . sock . connect . bind ( this . sock ) ; this . close = this . sock . close . bind ( this . sock ) ; this . listeners = [ ] ; }

Initialzie a new `SubEmitterSocket`.

@api private


function PubEmitterSocket() {
  this.sock = new PubSocket;
  this.emit = this.sock.send.bind(this.sock);
  this.bind = this.sock.bind.bind(this.sock);
  this.connect = this.sock.connect.bind(this.sock);
  this.close = this.sock.close.bind(this.sock);
}

function PubEmitterSocket ( ) { this . sock = new PubSocket ; this . emit = this . sock . send . bind ( this . sock ) ; this . bind = this . sock . bind . bind ( this . sock ) ; this . connect = this . sock . connect . bind ( this . sock ) ; this . close = this . sock . close . bind ( this . sock ) ; }

Initialzie a new `PubEmitterSocket`.

@api private


function toRegExp(str) {
  if (str instanceof RegExp) return str;
  str = escape(str);
  str = str.replace(/\\\*/g, '(.+)');
  return new RegExp('^' + str + '$');
}

function toRegExp ( str ) { if ( str instanceof RegExp ) return str ; str = escape ( str ) ; str = str . replace ( / \\\* / g , '(.+)' ) ; return new RegExp ( '^' + str + '$' ) ; }

Convert `str` to a `RegExp`.

@param {String} str
@return {RegExp}
@api private


function ReqSocket() {
  Socket.call(this);
  this.n = 0;
  this.ids = 0;
  this.callbacks = {};
  this.identity = this.get('identity');
  this.use(queue());
}

function ReqSocket ( ) { Socket . call ( this ) ; this . n = 0 ; this . ids = 0 ; this . callbacks = { } ; this . identity = this . get ( 'identity' ) ; this . use ( queue ( ) ) ; }

Initialize a new `ReqSocket`.

@api private


function Node(kind, docs, location) {
  this.kind = kind;
  if (docs) {
    this.leadingComments = docs;
  }
  if (location) {
    this.loc = location;
  }
}

function Node ( kind , docs , location ) { this . kind = kind ; if ( docs ) { this . leadingComments = docs ; } if ( location ) { this . loc = location ; } }

A generic AST node
@constructor Node
@property {Location|null} loc
@property {Comment[]} leadingComments
@property {Comment[]?} trailingComments
@property {String} kind


function() {
    let location = null;
    const args = Array.prototype.slice.call(arguments);
    args.push(docs);
    if (typeof result.preBuild === "function") {
      result.preBuild(arguments);
    }
    if (self.withPositions || self.withSource) {
      let src = null;
      if (self.withSource) {
        src = parser.lexer._input.substring(start.offset, parser.prev[2]);
      }
      if (self.withPositions) {
        location = new Location(
          src,
          start,
          new Position(parser.prev[0], parser.prev[1], parser.prev[2])
        );
      } else {
        location = new Location(src, null, null);
      }
      // last argument is allways the location
      args.push(location);
    }
    // handle lazy kind definitions
    if (!kind) {
      kind = args.shift();
    }
    // build the object
    const node = self[kind];
    if (typeof node !== "function") {
      throw new Error('Undefined node "' + kind + '"');
    }
    const astNode = Object.create(node.prototype);
    node.apply(astNode, args);
    result.instance = astNode;
    if (result.trailingComments) {
      // buffer of trailingComments
      astNode.trailingComments = result.trailingComments;
    }
    if (typeof result.postBuild === "function") {
      result.postBuild(astNode);
    }
    if (parser.debug) {
      delete AST.stack[result.stackUid];
    }
    return self.resolvePrecedence(astNode, parser);
  }


function() {
    const ch = this._input[this.offset - 1];
    const fn = this.tokenTerminals[ch];
    if (fn) {
      return fn.apply(this, []);
    } else {
      return this.yytext;
    }
  }

function ( ) { const ch = this . _input [ this . offset - 1 ] ; const fn = this . tokenTerminals [ ch ] ; if ( fn ) { return fn . apply ( this , [ ] ) ; } else { return this . yytext ; } }


function(text, doubleQuote) {
    if (!doubleQuote) {
      // single quote fix
      return text.replace(/\\['\\]/g, function(seq) {
        return specialChar[seq];
      });
    }
    return text.replace(/\\[rntvef"'\\$]/g, function(seq) {
      return specialChar[seq];
    });
  }

function
(
text
,
doubleQuote
)
{
if
(
!
doubleQuote
)
{
// single quote fix
return
text
.
replace
(
/
\\['\\]
/
g
,
function
(
seq
)
{
return
specialChar
[
seq
]
;
}
)
;
}
return
text
.
replace
(
/
\\[rntvef"'\\$]
/
g
,
function
(
seq
)
{
return
specialChar
[
seq
]
;
}
)
;
}


function(expr) {
    let result, offset;
    const node = this.node("offsetlookup");
    if (this.token === "[") {
      offset = this.next().read_expr();
      if (this.expect("]")) this.next();
      result = node(expr, offset);
    } else if (this.token === this.tok.T_DOLLAR_OPEN_CURLY_BRACES) {
      offset = this.read_encapsed_string_item(false);
      result = node(expr, offset);
    }
    return result;
  }

function ( expr ) { let result , offset ; const node = this . node ( "offsetlookup" ) ; if ( this . token === "[" ) { offset = this . next ( ) . read_expr ( ) ; if ( this . expect ( "]" ) ) this . next ( ) ; result = node ( expr , offset ) ; } else if ( this . token === this . tok . T_DOLLAR_OPEN_CURLY_BRACES ) { offset = this . read_encapsed_string_item ( false ) ; result = node ( expr , offset ) ; } return result ; }


function(expect, isBinary = false) {
    let node = this.node("encapsed");
    this.next();
    const start = this.lexer.yylloc.prev_offset - (isBinary ? 1 : 0);
    const value = [];
    let type = null;

    if (expect === "`") {
      type = this.ast.encapsed.TYPE_SHELL;
    } else if (expect === '"') {
      type = this.ast.encapsed.TYPE_STRING;
    } else {
      type = this.ast.encapsed.TYPE_HEREDOC;
    }

    // reading encapsed parts
    while (this.token !== expect && this.token !== this.EOF) {
      value.push(this.read_encapsed_string_item(true));
    }

    this.expect(expect) && this.next();
    node = node(
      value,
      this.lexer._input.substring(start - 1, this.lexer.yylloc.first_offset),
      type
    );

    if (expect === this.tok.T_END_HEREDOC) {
      node.label = this.lexer.heredoc_label;
    }
    return node;
  }

function
(
expect
,
isBinary
=
false
)
{
let
node
=
this
.
node
(
"encapsed"
)
;
this
.
next
(
)
;
const
start
=
this
.
lexer
.
yylloc
.
prev_offset
(
isBinary
1
:
0
)
;
const
value
=
[
]
;
let
type
=
;
if
(
expect
===
"`"
)
{
type
=
this
.
ast
.
encapsed
.
TYPE_SHELL
;
}
else
if
(
expect
===
'"'
)
{
type
=
this
.
ast
.
encapsed
.
TYPE_STRING
;
}
else
{
type
=
this
.
ast
.
encapsed
.
TYPE_HEREDOC
;
}
// reading encapsed parts
while
(
this
.
token
!==
expect
&&
this
.
token
!==
this
.
EOF
)
{
value
.
push
(
this
.
read_encapsed_string_item
(
true
)
)
;
}
this
.
expect
(
expect
)
&&
this
.
next
(
)
;
node
=
node
(
value
,
this
.
lexer
.
_input
.
substring
(
start
1
,
this
.
lexer
.
yylloc
.
first_offset
)
,
type
)
;
if
(
expect
===
this
.
tok
.
T_END_HEREDOC
)
{
node
.
label
=
this
.
lexer
.
heredoc_label
;
}
return
node
;
}


function() {
    const revert = this.offset;
    if (
      this._input[this.offset - 1] === "<" &&
      this._input[this.offset] === "<" &&
      this._input[this.offset + 1] === "<"
    ) {
      this.offset += 3;

      // optional tabs / spaces
      if (this.is_TABSPACE()) {
        while (this.offset < this.size) {
          this.offset++;
          if (!this.is_TABSPACE()) {
            break;
          }
        }
      }

      // optional quotes
      let tChar = this._input[this.offset - 1];
      if (tChar === "'" || tChar === '"') {
        this.offset++;
      } else {
        tChar = null;
      }

      // required label
      if (this.is_LABEL_START()) {
        let yyoffset = this.offset - 1;
        while (this.offset < this.size) {
          this.offset++;
          if (!this.is_LABEL()) {
            break;
          }
        }
        const yylabel = this._input.substring(yyoffset, this.offset - 1);
        if (!tChar || tChar === this._input[this.offset - 1]) {
          // required ending quote
          if (tChar) this.offset++;
          // require newline
          if (
            this._input[this.offset - 1] === "\r" ||
            this._input[this.offset - 1] === "\n"
          ) {
            // go go go
            this.heredoc_label = yylabel;
            yyoffset = this.offset - revert;
            this.offset = revert;
            this.consume(yyoffset);
            if (tChar === "'") {
              this.begin("ST_NOWDOC");
            } else {
              this.begin("ST_HEREDOC");
            }
            return this.tok.T_START_HEREDOC;
          }
        }
      }
    }
    this.offset = revert;
    return false;
  }

function
(
)
{
const
revert
=
this
.
offset
;
if
(
this
.
_input
[
this
.
offset
1
]
===
"<"
&&
this
.
_input
[
this
.
offset
]
===
"<"
&&
this
.
_input
[
this
.
offset
+
1
]
===
"<"
)
{
this
.
offset
+=
3
;
// optional tabs / spaces
if
(
this
.
is_TABSPACE
(
)
)
{
while
(
this
.
offset
<
this
.
size
)
{
this
.
offset
++
;
if
(
!
this
.
is_TABSPACE
(
)
)
{
break
;
}
}
}
// optional quotes
let
tChar
=
this
.
_input
[
this
.
offset
1
]
;
if
(
tChar
===
"'"
||
tChar
===
'"'
)
{
this
.
offset
++
;
}
else
{
tChar
=
;
}
// required label
if
(
this
.
is_LABEL_START
(
)
)
{
let
yyoffset
=
this
.
offset
1
;
while
(
this
.
offset
<
this
.
size
)
{
this
.
offset
++
;
if
(
!
this
.
is_LABEL
(
)
)
{
break
;
}
}
const
yylabel
=
this
.
_input
.
substring
(
yyoffset
,
this
.
offset
1
)
;
if
(
!
tChar
||
tChar
===
this
.
_input
[
this
.
offset
1
]
)
{
// required ending quote
if
(
tChar
)
this
.
offset
++
;
// require newline
if
(
this
.
_input
[
this
.
offset
1
]
===
"\r"
||
this
.
_input
[
this
.
offset
1
]
===
"\n"
)
{
// go go go
this
.
heredoc_label
=
yylabel
;
yyoffset
=
this
.
offset
revert
;
this
.
offset
=
revert
;
this
.
consume
(
yyoffset
)
;
if
(
tChar
===
"'"
)
{
this
.
begin
(
"ST_NOWDOC"
)
;
}
else
{
this
.
begin
(
"ST_HEREDOC"
)
;
}
return
this
.
tok
.
T_START_HEREDOC
;
}
}
}
}
this
.
offset
=
revert
;
return
false
;
}


function() {
    // @fixme : check if out of text limits
    if (
      this._input.substring(
        this.offset - 1,
        this.offset - 1 + this.heredoc_label.length
      ) === this.heredoc_label
    ) {
      const ch = this._input[this.offset - 1 + this.heredoc_label.length];
      if (ch === "\n" || ch === "\r" || ch === ";") {
        return true;
      }
    }
    return false;
  }

function
(
)
{
// @fixme : check if out of text limits
if
(
this
.
_input
.
substring
(
this
.
offset
1
,
this
.
offset
1
+
this
.
heredoc_label
.
length
)
===
this
.
heredoc_label
)
{
const
ch
=
this
.
_input
[
this
.
offset
1
+
this
.
heredoc_label
.
length
]
;
if
(
ch
===
"\n"
||
ch
===
"\r"
||
ch
===
";"
)
{
return
true
;
}
}
return
false
;
}


function() {
    const result = this.node("if");
    let body = null;
    let alternate = null;
    let shortForm = false;
    let test = null;
    test = this.next().read_if_expr();

    if (this.token === ":") {
      shortForm = true;
      this.next();
      body = this.node("block");
      const items = [];
      while (this.token !== this.EOF && this.token !== this.tok.T_ENDIF) {
        if (this.token === this.tok.T_ELSEIF) {
          alternate = this.read_elseif_short();
          break;
        } else if (this.token === this.tok.T_ELSE) {
          alternate = this.read_else_short();
          break;
        }
        items.push(this.read_inner_statement());
      }
      body = body(null, items);
      this.expect(this.tok.T_ENDIF) && this.next();
      this.expectEndOfStatement();
    } else {
      body = this.read_statement();
      if (this.token === this.tok.T_ELSEIF) {
        alternate = this.read_if();
      } else if (this.token === this.tok.T_ELSE) {
        alternate = this.next().read_statement();
      }
    }
    return result(test, body, alternate, shortForm);
  }

function ( ) { const result = this . node ( "if" ) ; let body = null ; let alternate = null ; let shortForm = false ; let test = null ; test = this . next ( ) . read_if_expr ( ) ; if ( this . token === ":" ) { shortForm = true ; this . next ( ) ; body = this . node ( "block" ) ; const items = [ ] ; while ( this . token !== this . EOF && this . token !== this . tok . T_ENDIF ) { if ( this . token === this . tok . T_ELSEIF ) { alternate = this . read_elseif_short ( ) ; break ; } else if ( this . token === this . tok . T_ELSE ) { alternate = this . read_else_short ( ) ; break ; } items . push ( this . read_inner_statement ( ) ) ; } body = body ( null , items ) ; this . expect ( this . tok . T_ENDIF ) && this . next ( ) ; this . expectEndOfStatement ( ) ; } else { body = this . read_statement ( ) ; if ( this . token === this . tok . T_ELSEIF ) { alternate = this . read_if ( ) ; } else if ( this . token === this . tok . T_ELSE ) { alternate = this . next ( ) . read_statement ( ) ; } } return result ( test , body , alternate , shortForm ) ; }

Reads an IF statement

```ebnf
if ::= T_IF '(' expr ')' ':' ...
```


function read_constant_declaration() {
        const result = this.node("constant");
        let constName = null;
        let value = null;
        if (
          this.token === this.tok.T_STRING ||
          (this.php7 && this.is("IDENTIFIER"))
        ) {
          constName = this.node("identifier");
          const name = this.text();
          this.next();
          constName = constName(name);
        } else {
          this.expect("IDENTIFIER");
        }
        if (this.expect("=")) {
          value = this.next().read_expr();
        }
        return result(constName, value);
      }

function read_constant_declaration ( ) { const result = this . node ( "constant" ) ; let constName = null ; let value = null ; if ( this . token === this . tok . T_STRING || ( this . php7 && this . is ( "IDENTIFIER" ) ) ) { constName = this . node ( "identifier" ) ; const name = this . text ( ) ; this . next ( ) ; constName = constName ( name ) ; } else { this . expect ( "IDENTIFIER" ) ; } if ( this . expect ( "=" ) ) { value = this . next ( ) . read_expr ( ) ; } return result ( constName , value ) ; }

Reads a constant declaration

```ebnf
constant_declaration ::= (T_STRING | IDENTIFIER) '=' expr
```
@return {Constant} [:link:](AST.md#constant)


function(asInterface) {
    const result = [-1, -1, -1];
    if (this.is("T_MEMBER_FLAGS")) {
      let idx = 0,
        val = 0;
      do {
        switch (this.token) {
          case this.tok.T_PUBLIC:
            idx = 0;
            val = 0;
            break;
          case this.tok.T_PROTECTED:
            idx = 0;
            val = 1;
            break;
          case this.tok.T_PRIVATE:
            idx = 0;
            val = 2;
            break;
          case this.tok.T_STATIC:
            idx = 1;
            val = 1;
            break;
          case this.tok.T_ABSTRACT:
            idx = 2;
            val = 1;
            break;
          case this.tok.T_FINAL:
            idx = 2;
            val = 2;
            break;
        }
        if (asInterface) {
          if (idx == 0 && val == 2) {
            // an interface can't be private
            this.expect([this.tok.T_PUBLIC, this.tok.T_PROTECTED]);
            val = -1;
          } else if (idx == 2 && val == 1) {
            // an interface cant be abstract
            this.error();
            val = -1;
          }
        }
        if (result[idx] !== -1) {
          // already defined flag
          this.error();
        } else if (val !== -1) {
          result[idx] = val;
        }
      } while (this.next().is("T_MEMBER_FLAGS"));
    }

    if (result[1] == -1) result[1] = 0;
    if (result[2] == -1) result[2] = 0;
    return result;
  }

function
(
asInterface
)
{
const
result
=
[
1
,
1
,
1
]
;
if
(
this
.
is
(
"T_MEMBER_FLAGS"
)
)
{
let
idx
=
0
,
val
=
0
;
do
{
switch
(
this
.
token
)
{
case
this
.
tok
.
T_PUBLIC
:
idx
=
0
;
val
=
0
;
break
;
case
this
.
tok
.
T_PROTECTED
:
idx
=
0
;
val
=
1
;
break
;
case
this
.
tok
.
T_PRIVATE
:
idx
=
0
;
val
=
2
;
break
;
case
this
.
tok
.
T_STATIC
:
idx
=
1
;
val
=
1
;
break
;
case
this
.
tok
.
T_ABSTRACT
:
idx
=
2
;
val
=
1
;
break
;
case
this
.
tok
.
T_FINAL
:
idx
=
2
;
val
=
2
;
break
;
}
if
(
asInterface
)
{
if
(
idx
==
0
&&
val
==
2
)
{
// an interface can't be private
this
.
expect
(
[
this
.
tok
.
T_PUBLIC
,
this
.
tok
.
T_PROTECTED
]
)
;
val
=
1
;
}
else
if
(
idx
==
2
&&
val
==
1
)
{
// an interface cant be abstract
this
.
error
(
)
;
val
=
1
;
}
}
if
(
result
[
idx
]
!==
1
)
{
// already defined flag
this
.
error
(
)
;
}
else
if
(
val
!==
1
)
{
result
[
idx
]
=
val
;
}
}
while
(
this
.
next
(
)
.
is
(
"T_MEMBER_FLAGS"
)
)
;
}
if
(
result
[
1
]
==
1
)
result
[
1
]
=
0
;
if
(
result
[
2
]
==
1
)
result
[
2
]
=
0
;
return
result
;
}

Read member flags
@return array
1st index : 0 => public, 1 => protected, 2 => private
2nd index : 0 => instance member, 1 => static member
3rd index : 0 => normal, 1 => abstract member, 2 => final member


function(read_only, encapsed, byref) {
    let result;

    // check the byref flag
    if (!byref && this.token === "&") {
      byref = true;
      this.next();
    }

    // reads the entry point
    if (this.is([this.tok.T_VARIABLE, "$"])) {
      result = this.read_reference_variable(encapsed, byref);
    } else if (
      this.is([
        this.tok.T_NS_SEPARATOR,
        this.tok.T_STRING,
        this.tok.T_NAMESPACE
      ])
    ) {
      result = this.node();
      const name = this.read_namespace_name();
      if (
        this.token != this.tok.T_DOUBLE_COLON &&
        this.token != "(" &&
        ["parentreference", "selfreference"].indexOf(name.kind) === -1
      ) {
        // @see parser.js line 130 : resolves a conflict with scalar
        const literal = name.name.toLowerCase();
        if (literal === "true") {
          result = name.destroy(result("boolean", true, name.name));
        } else if (literal === "false") {
          result = name.destroy(result("boolean", false, name.name));
        } else {
          // @todo null keyword ?
          result = result("identifier", name);
        }
      } else {
        // @fixme possible #193 bug
        result.destroy(name);
        result = name;
      }
    } else if (this.token === this.tok.T_STATIC) {
      result = this.node("staticreference");
      const raw = this.text();
      this.next();
      result = result(raw);
    } else {
      this.expect("VARIABLE");
    }

    // static mode
    if (this.token === this.tok.T_DOUBLE_COLON) {
      result = this.read_static_getter(result, encapsed);
    }

    return this.recursive_variable_chain_scan(result, read_only, encapsed);
  }

Reads a variable

```ebnf
variable ::= &? ...complex @todo
```

Some samples of parsed code :
```php
&$var                      // simple var
$var                      // simple var
classname::CONST_NAME     // dynamic class name with const retrieval
foo()                     // function call
$var->func()->property    // chained calls
```


function(what, encapsed) {
    const result = this.node("staticlookup");
    let offset, name;
    if (this.next().is([this.tok.T_VARIABLE, "$"])) {
      offset = this.read_reference_variable(encapsed, false);
    } else if (
      this.token === this.tok.T_STRING ||
      this.token === this.tok.T_CLASS ||
      (this.php7 && this.is("IDENTIFIER"))
    ) {
      offset = this.node("identifier");
      name = this.text();
      this.next();
      offset = offset(name);
    } else if (this.token === "{") {
      offset = this.node("literal");
      name = this.next().read_expr();
      this.expect("}") && this.next();
      offset = offset("literal", name, null);
      this.expect("(");
    } else {
      this.error([this.tok.T_VARIABLE, this.tok.T_STRING]);
      // graceful mode : set getter as error node and continue
      offset = this.node("identifier");
      name = this.text();
      this.next();
      offset = offset(name);
    }
    return result(what, offset);
  }


function(options) {
  if (typeof this === "function") {
    return new this(options);
  }
  this.tokens = tokens;
  this.lexer = new lexer(this);
  this.ast = new AST();
  this.parser = new parser(this.lexer, this.ast);
  if (options && typeof options === "object") {
    // disable php7 from lexer if already disabled from parser
    if (options.parser && options.parser.php7 === false) {
      if (!options.lexer) {
        options.lexer = {};
      }
      options.lexer.php7 = false;
    }
    combine(options, this);
  }
}

Initialise a new parser instance with the specified options

@class
@tutorial Engine
@example
var parser = require('php-parser');
var instance = new parser({
parser: {
extractDoc: true,
suppressErrors: true,
php7: true
},
ast: {
withPositions: true
},
lexer: {
short_tags: true,
asp_tags: true
}
});

var evalAST = instance.parseEval('some php code');
var codeAST = instance.parseCode('<?php some php code', 'foo.php');
var tokens = instance.tokenGetAll('<?php some php code');

@param {Object} options - List of options
@property {Lexer} lexer
@property {Parser} parser
@property {AST} ast
@property {Object} tokens


function() {
    while (this.offset < this.size) {
      const ch = this.input();
      if (ch === "\n" || ch === "\r") {
        return this.tok.T_COMMENT;
      } else if (
        ch === "?" &&
        !this.aspTagMode &&
        this._input[this.offset] === ">"
      ) {
        this.unput(1);
        return this.tok.T_COMMENT;
      } else if (
        ch === "%" &&
        this.aspTagMode &&
        this._input[this.offset] === ">"
      ) {
        this.unput(1);
        return this.tok.T_COMMENT;
      }
    }
    return this.tok.T_COMMENT;
  }

function ( ) { while ( this . offset < this . size ) { const ch = this . input ( ) ; if ( ch === "\n" || ch === "\r" ) { return this . tok . T_COMMENT ; } else if ( ch === "?" && ! this . aspTagMode && this . _input [ this . offset ] === ">" ) { this . unput ( 1 ) ; return this . tok . T_COMMENT ; } else if ( ch === "%" && this . aspTagMode && this . _input [ this . offset ] === ">" ) { this . unput ( 1 ) ; return this . tok . T_COMMENT ; } } return this . tok . T_COMMENT ; }


function(token) {
    const body = this.node("block");
    const items = [];
    if (this.expect(":")) this.next();
    while (this.token != this.EOF && this.token !== token) {
      items.push(this.read_inner_statement());
    }
    if (this.expect(token)) this.next();
    this.expectEndOfStatement();
    return body(null, items);
  }

function ( token ) { const body = this . node ( "block" ) ; const items = [ ] ; if ( this . expect ( ":" ) ) this . next ( ) ; while ( this . token != this . EOF && this . token !== token ) { items . push ( this . read_inner_statement ( ) ) ; } if ( this . expect ( token ) ) this . next ( ) ; this . expectEndOfStatement ( ) ; return body ( null , items ) ; }

Reads a short form of tokens
@param {Number} token - The ending token
@return {Block}


function() {
    return this.read_list(function() {
      const node = this.node("staticvariable");
      let variable = this.node("variable");
      // plain variable name
      if (this.expect(this.tok.T_VARIABLE)) {
        const name = this.text().substring(1);
        this.next();
        variable = variable(name, false, false);
      } else {
        variable = variable("#ERR", false, false);
      }
      if (this.token === "=") {
        return node(variable, this.next().read_expr());
      } else {
        return variable;
      }
    }, ",");
  }

function
(
)
{
return
this
.
read_list
(
function
(
)
{
const
node
=
this
.
node
(
"staticvariable"
)
;
let
variable
=
this
.
node
(
"variable"
)
;
// plain variable name
if
(
this
.
expect
(
this
.
tok
.
T_VARIABLE
)
)
{
const
name
=
this
.
text
(
)
.
substring
(
1
)
;
this
.
next
(
)
;
variable
=
variable
(
name
,
false
,
false
)
;
}
else
{
variable
=
variable
(
"#ERR"
,
false
,
false
)
;
}
if
(
this
.
token
===
"="
)
{
return
node
(
variable
,
this
.
next
(
)
.
read_expr
(
)
)
;
}
else
{
return
variable
;
}
}
,
","
)
;
}

Reads a list of variables declarations

```ebnf
variable_declaration ::= T_VARIABLE ('=' expr)?*
variable_declarations ::= variable_declaration (',' variable_declaration)*
```

Sample code :
```php
<?php static $a = 'hello', $b = 'world';
```
@return {StaticVariable[]} Returns an array composed by a list of variables, or
assign values


function findChunkFile(chunk, chunkId, outputFilePath) {
  for (let i = 0; i < chunk.files.length; i++) {
    const chunkFile = chunk.files[i];
    let normalizedOutputFilePath = outputFilePath.replace(/^\.\//, '');
    if (!/\.js$/.test(chunkFile)) {
      normalizedOutputFilePath = normalizedOutputFilePath.substr(
        0,
        normalizedOutputFilePath.length - 3
      );
    }

    if (normalizedOutputFilePath === chunkFile) {
      return chunkFile;
    }
  }
  if (chunk.id === chunkId) {
    return chunk.files[0];
  }
  return undefined; // eslint-disable-line no-undefined
}

function
findChunkFile
(
chunk
,
chunkId
,
outputFilePath
)
{
for
(
let
i
=
0
;
i
<
chunk
.
files
.
length
;
i
++
)
{
const
chunkFile
=
chunk
.
files
[
i
]
;
let
normalizedOutputFilePath
=
outputFilePath
.
replace
(
/
^\.\/
/
,
''
)
;
if
(
!
/
\.js$
/
.
test
(
chunkFile
)
)
{
normalizedOutputFilePath
=
normalizedOutputFilePath
.
substr
(
0
,
normalizedOutputFilePath
.
length
3
)
;
}
if
(
normalizedOutputFilePath
===
chunkFile
)
{
return
chunkFile
;
}
}
if
(
chunk
.
id
===
chunkId
)
{
return
chunk
.
files
[
0
]
;
}
return
undefined
;
// eslint-disable-line no-undefined
}

Find the filename of a chunk which matches either the id or path provided.

@param {!Chunk} chunk
@param {number} chunkId
@param {string} outputFilePath
@return {string|undefined}

Find the filename of a chunk which matches either the id or path provided .


function findAncestorDistance(src, target, currentDistance) {
  if (target === src) {
    return currentDistance;
  }

  const distances = [];
  src.getParents().forEach((srcParentChunkGroup) => {
    const distance = findAncestorDistance(
      srcParentChunkGroup,
      target,
      currentDistance + 1
    );
    if (distance >= 0) {
      distances.push(distance);
    }
  });
  if (distances.length === 0) {
    return -1;
  }
  return Math.min(...distances);
}

function findAncestorDistance ( src , target , currentDistance ) { if ( target === src ) { return currentDistance ; } const distances = [ ] ; src . getParents ( ) . forEach ( ( srcParentChunkGroup ) => { const distance = findAncestorDistance ( srcParentChunkGroup , target , currentDistance + 1 ) ; if ( distance >= 0 ) { distances . push ( distance ) ; } } ) ; if ( distances . length === 0 ) { return - 1 ; } return Math . min ( ... distances ) ; }

Find an ancestor of a chunk. Return the distance from the target or -1 if not found.

@param {string} src
@param {string} target
@param {number} currentDistance
@return {number} distance from target of parent or -1 when not found

Find an ancestor of a chunk . Return the distance from the target or - 1 if not found .


function findNearestCommonParentChunk(chunkGroups, currentDistance = 0) {
  // Map of chunk name to distance from target
  const distances = new Map();
  for (let i = 1; i < chunkGroups.length; i++) {
    const distance = findAncestorDistance(
      chunkGroups[i],
      chunkGroups[0],
      currentDistance
    );
    if (distance < 0) {
      distances.delete(chunkGroups[0]);
    } else if (
      !distances.has(chunkGroups[0]) ||
      distance < distances.get(chunkGroups[0])
    ) {
      distances.set(chunkGroups[0], distance);
    }
  }
  if (distances.size === 0) {
    // chunkGroup[0] was not a parent for the other chunk groups.
    // So move up the graph one level and check again.
    chunkGroups[0].getParents().forEach((chunkGroupParent) => {
      const distanceRecord = findNearestCommonParentChunk(
        [chunkGroupParent].concat(chunkGroups.slice(1)),
        currentDistance + 1
      );
      if (
        distanceRecord.distance >= 0 &&
        (!distances.has(distanceRecord.chunkGroup) ||
          distances.get(distanceRecord.chunkGroup) < distanceRecord.distance)
      ) {
        distances.set(distanceRecord.chunkGroup, distanceRecord.distance);
      }
    });
  }

  const nearestCommonParent = {
    chunkGroup: undefined,
    distance: -1,
  };
  distances.forEach((distance, chunkGroup) => {
    if (
      nearestCommonParent.distance < 0 ||
      distance < nearestCommonParent.distance
    ) {
      nearestCommonParent.chunkGroup = chunkGroup;
      nearestCommonParent.distance = distance;
    }
  });
  return nearestCommonParent;
}

Find the closest common parent chunk from a list.
Since closure-compiler requires a chunk tree to have a single root,
there will always be a common parent.

@param {!Array<string>} chunkGroups
@param {number} currentDistance
@return {{chunkGroup: (!ChunkGroup|undefined), distance: number}}

Find the closest common parent chunk from a list . Since closure - compiler requires a chunk tree to have a single root there will always be a common parent .


function(page, data) {
			if (page.flagAniBind == true) return;
			// do callback when animation start/end
			["animationstart", "animationend"].forEach(function(animationkey, index) {
				var animition = paramsIn[animationkey], webkitkey = "webkit" + animationkey.replace(/^a|s|e/g, function(matchs) {
					return matchs.toUpperCase();
				});
				var animateEventName = isWebkit? webkitkey: animationkey;
				// if it's the out element, hide it when 'animationend'
				if (index) {
					page.addEventListener(animateEventName, function() {
						if (this.classList.contains("in") == false) {
							this.style.display = "none";
							// add on v2.5.5
							// move here on v2.5.8
							// main for remove page is just current page
							// remove on v2.7.0
							// if (this.removeSelf == true) {
							// 	this.parentElement.removeChild(this);
							// 	this.removeSelf = null;
							// }
						}
						this.classList.remove(params(this).form);
					});
				}
				// bind animation events
				if (typeof animition == "string" && paramsIn.root[animition]) {
					page.addEventListener(animateEventName, function() {
						data.root[animition].call(data.root, this, this.classList.contains("in")? "into": "out", options);
					});
				} else if (typeof animition == "function") {
					page.addEventListener(animateEventName, function() {
						animition.call(data.root, this, this.classList.contains("in")? "into": "out", options);
					});
				}
				// set a flag
				page.flagAniBind = true;
			});
		}


function updateProps (domNode, oldVirtualNode, oldProps, newVirtualNode, newProps) {
  if (oldProps) {
    for (var name in oldProps) {
      if (name === 'ref' || name === 'on') continue
      if (name in EVENT_LISTENER_PROPS) continue
      if (!newProps || !(name in newProps)) {
        if (name === 'dataset') {
          updateProps(domNode.dataset, null, oldProps && oldProps.dataset, null, null)
        } else if (name !== 'innerHTML' && oldVirtualNode && SVG_TAGS.has(oldVirtualNode.tag)) {
          domNode.removeAttribute(SVG_ATTRIBUTE_TRANSLATIONS.get(name) || name)
        } else {
          // Clear property for objects that don't support deletion (e.g. style
          // or className). If we used null instead of an empty string, the DOM
          // could sometimes stringify the value and mistakenly assign 'null'.
          domNode[name] = EMPTY
          delete domNode[name]
        }
      }
    }
  }

  if (newProps) {
    for (var name in newProps) {
      if (name === 'ref' || name === 'on') continue
      if (name in EVENT_LISTENER_PROPS) continue
      var oldValue = oldProps && oldProps[name]
      var newValue = newProps[name]
      if (name === 'dataset') {
        updateNestedProps(domNode.dataset, oldValue, newValue, false)
      } else if (name === 'style' && typeof newValue !== 'string') {
        if (typeof oldValue === 'string') {
          domNode.style = ''
          oldValue = null
        }
        updateNestedProps(domNode.style, oldValue, newValue, true)
      } else if (name === 'attributes') {
        updateAttributes(domNode, oldValue, newValue)
      } else {
        if (newValue !== oldValue) {
          if (name !== 'innerHTML' && newVirtualNode && SVG_TAGS.has(newVirtualNode.tag)) {
            domNode.setAttribute(SVG_ATTRIBUTE_TRANSLATIONS.get(name) || name, newValue)
          } else if (newVirtualNode && newVirtualNode.tag === 'input'
            && name === 'value' && domNode[name] === newValue) {
            // Do not update `value` of an `input` unless it differs.
            // Every change will reset the cursor position.
          } else {
            domNode[name] = newValue
          }
        }
      }
    }
  }
}

Using var to avoid "Unsupported phi use of variable" deoptimization in Chrome 56

Using var to avoid Unsupported phi use of variable deoptimization in Chrome 56


function initialize(component) {
  if (typeof component.update !== 'function') {
    throw new Error('Etch components must implement `update(props, children)`.')
  }

  let virtualNode = component.render()
  if (!isValidVirtualNode(virtualNode)) {
    let namePart = component.constructor && component.constructor.name ? ' in ' + component.constructor.name : ''
    throw new Error('invalid falsy value ' + virtualNode + ' returned from render()' + namePart)
  }

  applyContext(component, virtualNode)

  component.refs = {}
  component.virtualNode = virtualNode
  component.element = render(component.virtualNode, {
    refs: component.refs, listenerContext: component
  })
}

This function associates a component object with a DOM element by calling the components `render` method, assigning an `.element` property on the object and also returning the element.  It also assigns a `virtualNode` property based on the return value of the `render` method. This will be used later by `performElementUpdate` to diff the new results of `render` with the previous results when updating the component's element.  Finally, this function also associates the component with a `refs` object, which is populated with references to elements based on `ref` properties on nodes of the `virtual-dom` tree. Before calling into `virtual-dom` to create the DOM tree, it pushes this `refs` object to a shared stack so it can be accessed by hooks during the creation of individual elements.

This function associates a component object with a DOM element by calling the components render method assigning an . element property on the object and also returning the element . It also assigns a virtualNode property based on the return value of the render method . This will be used later by performElementUpdate to diff the new results of render with the previous results when updating the component s element . Finally this function also associates the component with a refs object which is populated with references to elements based on ref properties on nodes of the virtual - dom tree . Before calling into virtual - dom to create the DOM tree it pushes this refs object to a shared stack so it can be accessed by hooks during the creation of individual elements .


function updateSync (component, replaceNode=true) {
  if (!isValidVirtualNode(component.virtualNode)) {
    throw new Error(`${component.constructor ? component.constructor.name + ' instance' : component} is not associated with a valid virtualNode. Perhaps this component was never initialized?`)
  }

  if (component.element == null) {
    throw new Error(`${component.constructor ? component.constructor.name + ' instance' : component} is not associated with a DOM element. Perhaps this component was never initialized?`)
  }

  let newVirtualNode = component.render()
  if (!isValidVirtualNode(newVirtualNode)) {
    const namePart = component.constructor && component.constructor.name ? ' in ' + component.constructor.name : ''
    throw new Error('invalid falsy value ' + newVirtualNode + ' returned from render()' + namePart)
  }

  applyContext(component, newVirtualNode)

  syncUpdatesInProgressCounter++
  let oldVirtualNode = component.virtualNode
  let oldDomNode = component.element
  let newDomNode = patch(oldVirtualNode, newVirtualNode, {
    refs: component.refs,
    listenerContext: component
  })
  component.virtualNode = newVirtualNode
  if (newDomNode !== oldDomNode && !replaceNode) {
    throw new Error('The root node type changed on update, but the update was performed with the replaceNode option set to false')
  } else {
    component.element = newDomNode
  }

  // We can safely perform additional writes after a DOM update synchronously,
  // but any reads need to be deferred until all writes are completed to avoid
  // DOM thrashing. Requested reads occur at the end of the the current frame
  // if this method was invoked via the scheduler. Otherwise, if `updateSync`
  // was invoked outside of the scheduler, the default scheduler will defer
  // reads until the next animation frame.
  if (typeof component.writeAfterUpdate === 'function') {
    component.writeAfterUpdate()
  }
  if (typeof component.readAfterUpdate === 'function') {
    getScheduler().readDocument(function () {
      component.readAfterUpdate()
    })
  }

  syncUpdatesInProgressCounter--
}

Synchronsly updates the DOM element associated with a component object. . This method assumes the presence of `.element` and `.virtualNode` properties on the component, which are assigned in the `initialize` function.  It calls `render` on the component to obtain the desired state of the DOM, then `diff`s it with the previous state and `patch`es the element based on the resulting diff. During the patch operation, it pushes the component's `refs` object to a shared stack so that references to DOM elements can be updated.  If `update` is called during the invocation of `updateSync`, the requests are processed synchronously as well. We track whether this is the case by incrementing and decrementing `syncUpdatesInProgressCounter` around the call.  For now, etch does not allow the root tag of the `render` method to change between invocations, because we want to preserve a one-to-one relationship between component objects and DOM elements for simplicity.

Synchronsly updates the DOM element associated with a component object . . This method assumes the presence of . element and . virtualNode properties on the component which are assigned in the initialize function . It calls render on the component to obtain the desired state of the DOM then diff s it with the previous state and patch es the element based on the resulting diff . During the patch operation it pushes the component s refs object to a shared stack so that references to DOM elements can be updated . If update is called during the invocation of updateSync the requests are processed synchronously as well . We track whether this is the case by incrementing and decrementing syncUpdatesInProgressCounter around the call . For now etch does not allow the root tag of the render method to change between invocations because we want to preserve a one - to - one relationship between component objects and DOM elements for simplicity .


function destroy (component, removeNode=true) {
  if (syncUpdatesInProgressCounter > 0 || syncDestructionsInProgressCounter > 0) {
    destroySync(component, removeNode)
    return Promise.resolve()
  }

  let scheduler = getScheduler()
  scheduler.updateDocument(function () {
    destroySync(component, removeNode)
  })
  return scheduler.getNextUpdatePromise()
}

function destroy ( component , removeNode = true ) { if ( syncUpdatesInProgressCounter > 0 || syncDestructionsInProgressCounter > 0 ) { destroySync ( component , removeNode ) return Promise . resolve ( ) } let scheduler = getScheduler ( ) scheduler . updateDocument ( function ( ) { destroySync ( component , removeNode ) } ) return scheduler . getNextUpdatePromise ( ) }

Removes the component's associated element and calls `destroy` on any child components. Normally, this function is asynchronous and will perform the destruction on the next animation frame. If called as the result of another update or destruction, it calls `destroy` on child components synchronously. If called as the result of destroying a component higher in the DOM, the element is not removed to avoid redundant DOM manipulation. Returns a promise that resolves when the destruction is completed.

Removes the component s associated element and calls destroy on any child components . Normally this function is asynchronous and will perform the destruction on the next animation frame . If called as the result of another update or destruction it calls destroy on child components synchronously . If called as the result of destroying a component higher in the DOM the element is not removed to avoid redundant DOM manipulation . Returns a promise that resolves when the destruction is completed .


function destroySync (component, removeNode=true) {
  syncDestructionsInProgressCounter++
  destroyChildComponents(component.virtualNode)
  if (syncDestructionsInProgressCounter === 1 && removeNode) component.element.remove()
  syncDestructionsInProgressCounter--
}

function destroySync ( component , removeNode = true ) { syncDestructionsInProgressCounter ++ destroyChildComponents ( component . virtualNode ) if ( syncDestructionsInProgressCounter === 1 && removeNode ) component . element . remove ( ) syncDestructionsInProgressCounter -- }

A synchronous version of `destroy`.  Note that we track whether `destroy` calls are in progress and only remove the element if we are not a nested call.

A synchronous version of destroy . Note that we track whether destroy calls are in progress and only remove the element if we are not a nested call .


function enlargeUUID(shortId, translator) {
    var uu1 = translator(shortId);
    var leftPad = "";
    var m;

    // Pad out UUIDs beginning with zeros (any number shorter than 32 characters of hex)
    for (var i = 0, len = 32-uu1.length; i < len; ++i) {
        leftPad += "0";
    }

    // Join the zero padding and the UUID and then slice it up with match
    m = (leftPad + uu1).match(/(\w{8})(\w{4})(\w{4})(\w{4})(\w{12})/);

    // Accumulate the matches and join them.
    return [m[1], m[2], m[3], m[4], m[5]].join('-');
}

Translate back to hex and turn back into UUID format, with dashes
@param {string} shortId
@param {function(string)} translator
@returns {string}

Translate back to hex and turn back into UUID format with dashes


function cleanFilter() {
        sbSearch.reset();
        if (!templateOpts.sidebar.enabled || !$sidebarNodes) return;

        setFilterBtnStates();

        if ($txtSearch) $txtSearch.val('');
        $sidebarNodes.removeClass('hidden');
        if ($btnClean) $btnClean.hide();
        $('.toolbar-buttons > span').css('color', '#fff');
        // show back the chevrons within the sidebar symbols.
        $('.chevron').show();
        // reset outline back to initial value
        setTimeout(function () {
            setSidebarNodesOutline(templateOpts.sidebar.outline);
            if ($txtSearch) $txtSearch.focus();
        }, 100); // with a little delay
        isFilterActive = false;
    }


function filterSidebarNodes(strSearch) {
        if (!templateOpts.sidebar.enabled) return;

        strSearch = (strSearch || '').trim().toLowerCase();
        if (!strSearch) {
            cleanFilter();
            return;
        }
        if ($btnClean) $btnClean.show();

        // expand all sub-trees, so any found item is visible
        toggleAllSubTrees(false);
        $('.chevron').hide();
        // set unfold state
        setFoldState(false);

        isFilterActive = true;

        // We set outline to "flat" bec. if outline is "tree", and some symbol
        // parent does not match the search/filter, the indents and tree lines
        // look weird.
        setSidebarNodesOutline('flat');

        debounceApplySearch(strSearch);

        $('.toolbar-buttons > span').css('color', '#3f4450'); // '#7b8395'
    }

Filters the symbol nodes in the API sidebar by the given search string.

Prefix `kind:` will filter by symbol kind rather than searching for the
given text. e.g. `kind:method` or `kind:method,class`.

Additionally, prefix `scope:` will filter by symbol scope rather than
searching for the given text. e.g. `scope:inner` or `scope:static,inner`.
@private

@param {*} strSearch - String to be searched for.

Filters the symbol nodes in the API sidebar by the given search string .


function toggleHamMenu(show) {
        if (!$nbmBtn) return;
        var fn = show ? 'addClass' : 'removeClass';
        $nbmBtn[fn]('toggled');
        $navOverlay[fn]('toggled'); // toggle overlay / backdrop
        $navbarMenu[fn]('toggled');
        // disable body scroll if menu is open
        helper.toggleBodyScroll(!show);

        if (show) {
            // scroll the contents of the responsive collapsed navbar menu to
            // top.
            $navbarMenu.scrollTop(0);
            // if showing responsive collapsed navbar menu, we'll close the
            // sidebar.
            if ($sidebarWrapper && $sidebarWrapper.length) {
                $wrapper.removeClass('toggled');
                $sidebarToggle.removeClass('toggled');
                // also hide the sidebar toggler, so user cannot re-open it
                // while navbar menu is shown. we use opacity instead of
                // display:none bec, it's used by a media query in sidebar.less
                // (the toggler is already hidden in small screens).
                $sidebarToggle.css('opacity', 0);
            }
        } else {
            // show sidebar toggler if responsive collapsed navbar menu is
            // closed.
            $sidebarToggle.css('opacity', 1);
        }
    }

Toggles the hamburger menu for the navbar list.
@private
@param {Boolean} show -

Toggles the hamburger menu for the navbar list .