<commit_before>/**
 *  Copyright (c) 2015, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 */

import {
  GraphQLBoolean,
  GraphQLFloat,
  GraphQLID,
  GraphQLInt,
  GraphQLList,
  GraphQLNonNull,
  GraphQLObjectType,
  GraphQLSchema,
  GraphQLString,
} from 'graphql'

import {
  connectionArgs,
  connectionDefinitions,
  connectionFromArray,
  fromGlobalId,
  globalIdField,
  mutationWithClientMutationId,
  nodeDefinitions,
} from 'graphql-relay'

import {
  // Import methods that your schema can use to interact with your database
  User,
  Widget,
  getUser,
  getViewer,
  getWidget,
  getWidgets,
} from './database';

/**
 * We get the node interface and field from the Relay library.
 *
 * The first method defines the way we resolve an ID to its object.
 * The second defines the way we resolve an object to its GraphQL type.
 */
var {nodeInterface, nodeField} = nodeDefinitions(
  (globalId) => {
    var {type, id} = fromGlobalId(globalId);
    if (type === 'User') {
      return getUser(id);
    } else if (type === 'Widget') {
      return getWidget(id);
    } else {
      return null;
    }
  },
  (obj) => {
    if (obj instanceof User) {
      return userType;
    } else if (obj instanceof Widget)  {
      return widgetType;
    } else {
      return null;
    }
  }
);

/**
 * Define your own types here
 */

var userType = new GraphQLObjectType({
  name: 'User',
  description: 'A person who uses our app',
  fields: () => ({
    id: globalIdField('User'),
    widgets: {
      type: widgetConnection,
      description: 'A person\'s collection of widgets',
      args: connectionArgs,
      resolve: (_, args) => connectionFromArray(getWidgets(), args),
    },
  }),
  interfaces: [nodeInterface],
});

var widgetType = new GraphQLObjectType({
  name: 'Widget',
  description: 'A shiny widget',
  fields: () => ({
    id: globalIdField('Widget'),
    name: {
      type: GraphQLString,
      description: 'The name of the widget',
    },
  }),
  interfaces: [nodeInterface],
});

/**
 * Define your own connection types here
 */
var {connectionType: widgetConnection} =
  connectionDefinitions({name: 'Widget', nodeType: widgetType});

/**
 * This is the type that will be the root of our query,
 * and the entry point into our schema.
 */
var queryType = new GraphQLObjectType({
  name: 'Query',
  fields: () => ({
    node: nodeField,
    // Add your own root fields here
    viewer: {
      type: userType,
      resolve: () => getViewer(),
    },
  }),
});

/**
 * This is the type that will be the root of our mutations,
 * and the entry point into performing writes in our schema.
 */
var mutationType = new GraphQLObjectType({
  name: 'Mutation',
  fields: () => ({
    // Add your own mutations here
  })
});

/**
 * Finally, we construct our schema (whose starting query type is the query
 * type we defined above) and export it.
 */
export var Schema = new GraphQLSchema({
  query: queryType,
  // Uncomment the following after adding some mutation fields:
  // mutation: mutationType
});
<commit_msg>add schema<commit_after>import {
  GraphQLObjectType as ObjectType,
  GraphQLString as String,
  GraphQLSchema as Schema
} from 'graphql'

const GREETINGS = { hello: 'Hello world' }

const GreetingsType = new ObjectType({
  name: 'Greetings',
  fields: () => ({
    hello: { type: String }
  })
})

export default new Schema({
  query: new ObjectType({
    name: 'Query',
    fields: () => ({
      greetings: {
        type: GreetingsType,
        resolve: () => GREETINGS
      }
    })
  })
})

// /**
//  *  Copyright (c) 2015, Facebook, Inc.
//  *  All rights reserved.
//  *
//  *  This source code is licensed under the BSD-style license found in the
//  *  LICENSE file in the root directory of this source tree. An additional grant
//  *  of patent rights can be found in the PATENTS file in the same directory.
//  */
//
// import {
//   GraphQLBoolean,
//   GraphQLFloat,
//   GraphQLID,
//   GraphQLInt,
//   GraphQLList,
//   GraphQLNonNull,
//   GraphQLObjectType,
//   GraphQLSchema,
//   GraphQLString,
// } from 'graphql'
//
// import {
//   connectionArgs,
//   connectionDefinitions,
//   connectionFromArray,
//   fromGlobalId,
//   globalIdField,
//   mutationWithClientMutationId,
//   nodeDefinitions,
// } from 'graphql-relay'
//
// import {
//   // Import methods that your schema can use to interact with your database
//   User,
//   Widget,
//   getUser,
//   getViewer,
//   getWidget,
//   getWidgets,
// } from './database';
//
// /**
//  * We get the node interface and field from the Relay library.
//  *
//  * The first method defines the way we resolve an ID to its object.
//  * The second defines the way we resolve an object to its GraphQL type.
//  */
// var {nodeInterface, nodeField} = nodeDefinitions(
//   (globalId) => {
//     var {type, id} = fromGlobalId(globalId);
//     if (type === 'User') {
//       return getUser(id);
//     } else if (type === 'Widget') {
//       return getWidget(id);
//     } else {
//       return null;
//     }
//   },
//   (obj) => {
//     if (obj instanceof User) {
//       return userType;
//     } else if (obj instanceof Widget)  {
//       return widgetType;
//     } else {
//       return null;
//     }
//   }
// );
//
// /**
//  * Define your own types here
//  */
//
// var userType = new GraphQLObjectType({
//   name: 'User',
//   description: 'A person who uses our app',
//   fields: () => ({
//     id: globalIdField('User'),
//     widgets: {
//       type: widgetConnection,
//       description: 'A person\'s collection of widgets',
//       args: connectionArgs,
//       resolve: (_, args) => connectionFromArray(getWidgets(), args),
//     },
//   }),
//   interfaces: [nodeInterface],
// });
//
// var widgetType = new GraphQLObjectType({
//   name: 'Widget',
//   description: 'A shiny widget',
//   fields: () => ({
//     id: globalIdField('Widget'),
//     name: {
//       type: GraphQLString,
//       description: 'The name of the widget',
//     },
//   }),
//   interfaces: [nodeInterface],
// });
//
// /**
//  * Define your own connection types here
//  */
// var {connectionType: widgetConnection} =
//   connectionDefinitions({name: 'Widget', nodeType: widgetType});
//
// /**
//  * This is the type that will be the root of our query,
//  * and the entry point into our schema.
//  */
// var queryType = new GraphQLObjectType({
//   name: 'Query',
//   fields: () => ({
//     node: nodeField,
//     // Add your own root fields here
//     viewer: {
//       type: userType,
//       resolve: () => getViewer(),
//     },
//   }),
// });
//
// /**
//  * This is the type that will be the root of our mutations,
//  * and the entry point into performing writes in our schema.
//  */
// var mutationType = new GraphQLObjectType({
//   name: 'Mutation',
//   fields: () => ({
//     // Add your own mutations here
//   })
// });
//
// /**
//  * Finally, we construct our schema (whose starting query type is the query
//  * type we defined above) and export it.
//  */
// export var Schema = new GraphQLSchema({
//   query: queryType,
//   // Uncomment the following after adding some mutation fields:
//   // mutation: mutationType
// });
<|endoftext|>


<commit_before>var _ = require('../util')
var config = require('../config')
var textParser = require('../parsers/text')
var dirParser = require('../parsers/directive')
var templateParser = require('../parsers/template')

/**
 * Compile a template and return a reusable composite link
 * function, which recursively contains more link functions
 * inside. This top level compile function should only be
 * called on instance root nodes.
 *
 * When the `asParent` flag is true, this means we are doing
 * a partial compile for a component's parent scope markup
 * (See #502). This could **only** be triggered during
 * compilation of `v-component`, and we need to skip v-with,
 * v-ref & v-component in this situation.
 *
 * @param {Element|DocumentFragment} el
 * @param {Object} options
 * @param {Boolean} partial
 * @param {Boolean} asParent - compiling a component
 *                             container as its parent.
 * @return {Function}
 */

module.exports = function compile (el, options, partial, asParent) {
  var isBlock = el.nodeType === 11
  var params = !partial && options.paramAttributes
  // if el is a fragment, this is a block instance
  // and paramAttributes will be stored on the first
  // element in the template. (excluding the _blockStart
  // comment node)
  var paramsEl = isBlock ? el.childNodes[1] : el
  var paramsLinkFn = params
    ? compileParamAttributes(paramsEl, params, options)
    : null
  var nodeLinkFn = isBlock
    ? null
    : compileNode(el, options, asParent)
  var childLinkFn =
    !(nodeLinkFn && nodeLinkFn.terminal) &&
    el.tagName !== 'SCRIPT' &&
    el.hasChildNodes()
      ? compileNodeList(el.childNodes, options)
      : null

  /**
   * A linker function to be called on a already compiled
   * piece of DOM, which instantiates all directive
   * instances.
   *
   * @param {Vue} vm
   * @param {Element|DocumentFragment} el
   * @return {Function|undefined}
   */

  return function link (vm, el) {
    var originalDirCount = vm._directives.length
    if (paramsLinkFn) {
      var paramsEl = isBlock ? el.childNodes[1] : el
      paramsLinkFn(vm, paramsEl)
    }
    // cache childNodes before linking parent, fix #657
    var childNodes = _.toArray(el.childNodes)
    if (nodeLinkFn) nodeLinkFn(vm, el)
    if (childLinkFn) childLinkFn(vm, childNodes)

    /**
     * If this is a partial compile, the linker function
     * returns an unlink function that tearsdown all
     * directives instances generated during the partial
     * linking.
     */

    if (partial) {
      var dirs = vm._directives.slice(originalDirCount)
      return function unlink () {
        var i = dirs.length
        while (i--) {
          dirs[i]._teardown()
        }
        i = vm._directives.indexOf(dirs[0])
        vm._directives.splice(i, dirs.length)
      }
    }
  }
}

/**
 * Compile a node and return a nodeLinkFn based on the
 * node type.
 *
 * @param {Node} node
 * @param {Object} options
 * @param {Boolean} asParent
 * @return {Function|undefined}
 */

function compileNode (node, options, asParent) {
  var type = node.nodeType
  if (type === 1 && node.tagName !== 'SCRIPT') {
    return compileElement(node, options, asParent)
  } else if (type === 3 && config.interpolate) {
    return compileTextNode(node, options)
  }
}

/**
 * Compile an element and return a nodeLinkFn.
 *
 * @param {Element} el
 * @param {Object} options
 * @param {Boolean} asParent
 * @return {Function|null}
 */

function compileElement (el, options, asParent) {
  var linkFn, tag, component
  // check custom element component, but only on non-root
  if (!asParent && !el.__vue__) {
    tag = el.tagName.toLowerCase()
    component =
      tag.indexOf('-') > 0 &&
      options.components[tag]
    if (component) {
      el.setAttribute(config.prefix + 'component', tag)
    }
  }
  if (component || el.hasAttributes()) {
    // check terminal direcitves
    if (!asParent) {
      linkFn = checkTerminalDirectives(el, options)
    }
    // if not terminal, build normal link function
    if (!linkFn) {
      var dirs = collectDirectives(el, options, asParent)
      linkFn = dirs.length
        ? makeDirectivesLinkFn(dirs)
        : null
    }
  }
  // if the element is a textarea, we need to interpolate
  // its content on initial render.
  if (el.tagName === 'TEXTAREA') {
    var realLinkFn = linkFn
    linkFn = function (vm, el) {
      el.value = vm.$interpolate(el.value)
      if (realLinkFn) realLinkFn(vm, el)
    }
    linkFn.terminal = true
  }
  return linkFn
}

/**
 * Build a multi-directive link function.
 *
 * @param {Array} directives
 * @return {Function} directivesLinkFn
 */

function makeDirectivesLinkFn (directives) {
  return function directivesLinkFn (vm, el) {
    // reverse apply because it's sorted low to high
    var i = directives.length
    var dir, j, k
    while (i--) {
      dir = directives[i]
      if (dir._link) {
        // custom link fn
        dir._link(vm, el)
      } else {
        k = dir.descriptors.length
        for (j = 0; j < k; j++) {
          vm._bindDir(dir.name, el,
                      dir.descriptors[j], dir.def)
        }
      }
    }
  }
}

/**
 * Compile a textNode and return a nodeLinkFn.
 *
 * @param {TextNode} node
 * @param {Object} options
 * @return {Function|null} textNodeLinkFn
 */

function compileTextNode (node, options) {
  var tokens = textParser.parse(node.nodeValue)
  if (!tokens) {
    return null
  }
  var frag = document.createDocumentFragment()
  var el, token
  for (var i = 0, l = tokens.length; i < l; i++) {
    token = tokens[i]
    el = token.tag
      ? processTextToken(token, options)
      : document.createTextNode(token.value)
    frag.appendChild(el)
  }
  return makeTextNodeLinkFn(tokens, frag, options)
}

/**
 * Process a single text token.
 *
 * @param {Object} token
 * @param {Object} options
 * @return {Node}
 */

function processTextToken (token, options) {
  var el
  if (token.oneTime) {
    el = document.createTextNode(token.value)
  } else {
    if (token.html) {
      el = document.createComment('v-html')
      setTokenType('html')
    } else if (token.partial) {
      el = document.createComment('v-partial')
      setTokenType('partial')
    } else {
      // IE will clean up empty textNodes during
      // frag.cloneNode(true), so we have to give it
      // something here...
      el = document.createTextNode(' ')
      setTokenType('text')
    }
  }
  function setTokenType (type) {
    token.type = type
    token.def = options.directives[type]
    token.descriptor = dirParser.parse(token.value)[0]
  }
  return el
}

/**
 * Build a function that processes a textNode.
 *
 * @param {Array<Object>} tokens
 * @param {DocumentFragment} frag
 */

function makeTextNodeLinkFn (tokens, frag) {
  return function textNodeLinkFn (vm, el) {
    var fragClone = frag.cloneNode(true)
    var childNodes = _.toArray(fragClone.childNodes)
    var token, value, node
    for (var i = 0, l = tokens.length; i < l; i++) {
      token = tokens[i]
      value = token.value
      if (token.tag) {
        node = childNodes[i]
        if (token.oneTime) {
          value = vm.$eval(value)
          if (token.html) {
            _.replace(node, templateParser.parse(value, true))
          } else {
            node.nodeValue = value
          }
        } else {
          vm._bindDir(token.type, node,
                      token.descriptor, token.def)
        }
      }
    }
    _.replace(el, fragClone)
  }
}

/**
 * Compile a node list and return a childLinkFn.
 *
 * @param {NodeList} nodeList
 * @param {Object} options
 * @return {Function|undefined}
 */

function compileNodeList (nodeList, options) {
  var linkFns = []
  var nodeLinkFn, childLinkFn, node
  for (var i = 0, l = nodeList.length; i < l; i++) {
    node = nodeList[i]
    nodeLinkFn = compileNode(node, options)
    childLinkFn =
      !(nodeLinkFn && nodeLinkFn.terminal) &&
      node.tagName !== 'SCRIPT' &&
      node.hasChildNodes()
        ? compileNodeList(node.childNodes, options)
        : null
    linkFns.push(nodeLinkFn, childLinkFn)
  }
  return linkFns.length
    ? makeChildLinkFn(linkFns)
    : null
}

/**
 * Make a child link function for a node's childNodes.
 *
 * @param {Array<Function>} linkFns
 * @return {Function} childLinkFn
 */

function makeChildLinkFn (linkFns) {
  return function childLinkFn (vm, nodes) {
    var node, nodeLinkFn, childrenLinkFn
    for (var i = 0, n = 0, l = linkFns.length; i < l; n++) {
      node = nodes[n]
      nodeLinkFn = linkFns[i++]
      childrenLinkFn = linkFns[i++]
      // cache childNodes before linking parent, fix #657
      var childNodes = _.toArray(node.childNodes)
      if (nodeLinkFn) {
        nodeLinkFn(vm, node)
      }
      if (childrenLinkFn) {
        childrenLinkFn(vm, childNodes)
      }
    }
  }
}

/**
 * Compile param attributes on a root element and return
 * a paramAttributes link function.
 *
 * @param {Element} el
 * @param {Array} attrs
 * @param {Object} options
 * @return {Function} paramsLinkFn
 */

function compileParamAttributes (el, attrs, options) {
  var params = []
  var i = attrs.length
  var name, value, param
  while (i--) {
    name = attrs[i]
    if (/[A-Z]/.test(name)) {
      _.warn(
        'You seem to be using camelCase for a paramAttribute, ' +
        'but HTML doesn\'t differentiate between upper and ' +
        'lower case. You should use hyphen-delimited ' +
        'attribute names. For more info see ' +
        'http://vuejs.org/api/options.html#paramAttributes'
      )
    }
    value = el.getAttribute(name)
    if (value !== null) {
      param = {
        name: name,
        value: value
      }
      var tokens = textParser.parse(value)
      if (tokens) {
        el.removeAttribute(name)
        if (tokens.length > 1) {
          _.warn(
            'Invalid param attribute binding: "' +
            name + '="' + value + '"' +
            '\nDon\'t mix binding tags with plain text ' +
            'in param attribute bindings.'
          )
          continue
        } else {
          param.dynamic = true
          param.value = tokens[0].value
        }
      }
      params.push(param)
    }
  }
  return makeParamsLinkFn(params, options)
}

/**
 * Build a function that applies param attributes to a vm.
 *
 * @param {Array} params
 * @param {Object} options
 * @return {Function} paramsLinkFn
 */

var dataAttrRE = /^data-/

function makeParamsLinkFn (params, options) {
  var def = options.directives['with']
  return function paramsLinkFn (vm, el) {
    var i = params.length
    var param, path
    while (i--) {
      param = params[i]
      // params could contain dashes, which will be
      // interpreted as minus calculations by the parser
      // so we need to wrap the path here
      path = _.camelize(param.name.replace(dataAttrRE, ''))
      if (param.dynamic) {
        // dynamic param attribtues are bound as v-with.
        // we can directly duck the descriptor here beacuse
        // param attributes cannot use expressions or
        // filters.
        vm._bindDir('with', el, {
          arg: path,
          expression: param.value
        }, def)
      } else {
        // just set once
        vm.$set(path, param.value)
      }
    }
  }
}

/**
 * Check an element for terminal directives in fixed order.
 * If it finds one, return a terminal link function.
 *
 * @param {Element} el
 * @param {Object} options
 * @return {Function} terminalLinkFn
 */

var terminalDirectives = [
  'repeat',
  'if',
  'component'
]

function skip () {}
skip.terminal = true

function checkTerminalDirectives (el, options) {
  if (_.attr(el, 'pre') !== null) {
    return skip
  }
  var value, dirName
  /* jshint boss: true */
  for (var i = 0; i < 3; i++) {
    dirName = terminalDirectives[i]
    if (value = _.attr(el, dirName)) {
      return makeTeriminalLinkFn(el, dirName, value, options)
    }
  }
}

/**
 * Build a link function for a terminal directive.
 *
 * @param {Element} el
 * @param {String} dirName
 * @param {String} value
 * @param {Object} options
 * @return {Function} terminalLinkFn
 */

function makeTeriminalLinkFn (el, dirName, value, options) {
  var descriptor = dirParser.parse(value)[0]
  var def = options.directives[dirName]
  var terminalLinkFn = function (vm, el) {
    vm._bindDir(dirName, el, descriptor, def)
  }
  terminalLinkFn.terminal = true
  return terminalLinkFn
}

/**
 * Collect the directives on an element.
 *
 * @param {Element} el
 * @param {Object} options
 * @param {Boolean} asParent
 * @return {Array}
 */

function collectDirectives (el, options, asParent) {
  var attrs = _.toArray(el.attributes)
  var i = attrs.length
  var dirs = []
  var attr, attrName, dir, dirName, dirDef
  while (i--) {
    attr = attrs[i]
    attrName = attr.name
    if (attrName.indexOf(config.prefix) === 0) {
      dirName = attrName.slice(config.prefix.length)
      if (asParent &&
          (dirName === 'with' ||
           dirName === 'component')) {
        continue
      }
      dirDef = options.directives[dirName]
      _.assertAsset(dirDef, 'directive', dirName)
      if (dirDef) {
        dirs.push({
          name: dirName,
          descriptors: dirParser.parse(attr.value),
          def: dirDef
        })
      }
    } else if (config.interpolate) {
      dir = collectAttrDirective(el, attrName, attr.value,
                                 options)
      if (dir) {
        dirs.push(dir)
      }
    }
  }
  // sort by priority, LOW to HIGH
  dirs.sort(directiveComparator)
  return dirs
}

/**
 * Check an attribute for potential dynamic bindings,
 * and return a directive object.
 *
 * @param {Element} el
 * @param {String} name
 * @param {String} value
 * @param {Object} options
 * @return {Object}
 */

function collectAttrDirective (el, name, value, options) {
  if (options._skipAttrs &&
      options._skipAttrs.indexOf(name) > -1) {
    return
  }
  var tokens = textParser.parse(value)
  if (tokens) {
    var def = options.directives.attr
    var i = tokens.length
    var allOneTime = true
    while (i--) {
      var token = tokens[i]
      if (token.tag && !token.oneTime) {
        allOneTime = false
      }
    }
    return {
      def: def,
      _link: allOneTime
        ? function (vm, el) {
            el.setAttribute(name, vm.$interpolate(value))
          }
        : function (vm, el) {
            var value = textParser.tokensToExp(tokens, vm)
            var desc = dirParser.parse(name + ':' + value)[0]
            vm._bindDir('attr', el, desc, def)
          }
    }
  }
}

/**
 * Directive priority sort comparator
 *
 * @param {Object} a
 * @param {Object} b
 */

function directiveComparator (a, b) {
  a = a.def.priority || 0
  b = b.def.priority || 0
  return a > b ? 1 : -1
}<commit_msg>skip empty TextNode early in compilation<commit_after>var _ = require('../util')
var config = require('../config')
var textParser = require('../parsers/text')
var dirParser = require('../parsers/directive')
var templateParser = require('../parsers/template')

/**
 * Compile a template and return a reusable composite link
 * function, which recursively contains more link functions
 * inside. This top level compile function should only be
 * called on instance root nodes.
 *
 * When the `asParent` flag is true, this means we are doing
 * a partial compile for a component's parent scope markup
 * (See #502). This could **only** be triggered during
 * compilation of `v-component`, and we need to skip v-with,
 * v-ref & v-component in this situation.
 *
 * @param {Element|DocumentFragment} el
 * @param {Object} options
 * @param {Boolean} partial
 * @param {Boolean} asParent - compiling a component
 *                             container as its parent.
 * @return {Function}
 */

module.exports = function compile (el, options, partial, asParent) {
  var isBlock = el.nodeType === 11
  var params = !partial && options.paramAttributes
  // if el is a fragment, this is a block instance
  // and paramAttributes will be stored on the first
  // element in the template. (excluding the _blockStart
  // comment node)
  var paramsEl = isBlock ? el.childNodes[1] : el
  var paramsLinkFn = params
    ? compileParamAttributes(paramsEl, params, options)
    : null
  var nodeLinkFn = isBlock
    ? null
    : compileNode(el, options, asParent)
  var childLinkFn =
    !(nodeLinkFn && nodeLinkFn.terminal) &&
    el.tagName !== 'SCRIPT' &&
    el.hasChildNodes()
      ? compileNodeList(el.childNodes, options)
      : null

  /**
   * A linker function to be called on a already compiled
   * piece of DOM, which instantiates all directive
   * instances.
   *
   * @param {Vue} vm
   * @param {Element|DocumentFragment} el
   * @return {Function|undefined}
   */

  return function link (vm, el) {
    var originalDirCount = vm._directives.length
    if (paramsLinkFn) {
      var paramsEl = isBlock ? el.childNodes[1] : el
      paramsLinkFn(vm, paramsEl)
    }
    // cache childNodes before linking parent, fix #657
    var childNodes = _.toArray(el.childNodes)
    if (nodeLinkFn) nodeLinkFn(vm, el)
    if (childLinkFn) childLinkFn(vm, childNodes)

    /**
     * If this is a partial compile, the linker function
     * returns an unlink function that tearsdown all
     * directives instances generated during the partial
     * linking.
     */

    if (partial) {
      var dirs = vm._directives.slice(originalDirCount)
      return function unlink () {
        var i = dirs.length
        while (i--) {
          dirs[i]._teardown()
        }
        i = vm._directives.indexOf(dirs[0])
        vm._directives.splice(i, dirs.length)
      }
    }
  }
}

/**
 * Compile a node and return a nodeLinkFn based on the
 * node type.
 *
 * @param {Node} node
 * @param {Object} options
 * @param {Boolean} asParent
 * @return {Function|null}
 */

function compileNode (node, options, asParent) {
  var type = node.nodeType
  if (type === 1 && node.tagName !== 'SCRIPT') {
    return compileElement(node, options, asParent)
  } else if (type === 3 && config.interpolate && node.data.trim()) {
    return compileTextNode(node, options)
  } else {
    return null
  }
}

/**
 * Compile an element and return a nodeLinkFn.
 *
 * @param {Element} el
 * @param {Object} options
 * @param {Boolean} asParent
 * @return {Function|null}
 */

function compileElement (el, options, asParent) {
  var linkFn, tag, component
  // check custom element component, but only on non-root
  if (!asParent && !el.__vue__) {
    tag = el.tagName.toLowerCase()
    component =
      tag.indexOf('-') > 0 &&
      options.components[tag]
    if (component) {
      el.setAttribute(config.prefix + 'component', tag)
    }
  }
  if (component || el.hasAttributes()) {
    // check terminal direcitves
    if (!asParent) {
      linkFn = checkTerminalDirectives(el, options)
    }
    // if not terminal, build normal link function
    if (!linkFn) {
      var dirs = collectDirectives(el, options, asParent)
      linkFn = dirs.length
        ? makeDirectivesLinkFn(dirs)
        : null
    }
  }
  // if the element is a textarea, we need to interpolate
  // its content on initial render.
  if (el.tagName === 'TEXTAREA') {
    var realLinkFn = linkFn
    linkFn = function (vm, el) {
      el.value = vm.$interpolate(el.value)
      if (realLinkFn) realLinkFn(vm, el)
    }
    linkFn.terminal = true
  }
  return linkFn
}

/**
 * Build a multi-directive link function.
 *
 * @param {Array} directives
 * @return {Function} directivesLinkFn
 */

function makeDirectivesLinkFn (directives) {
  return function directivesLinkFn (vm, el) {
    // reverse apply because it's sorted low to high
    var i = directives.length
    var dir, j, k
    while (i--) {
      dir = directives[i]
      if (dir._link) {
        // custom link fn
        dir._link(vm, el)
      } else {
        k = dir.descriptors.length
        for (j = 0; j < k; j++) {
          vm._bindDir(dir.name, el,
                      dir.descriptors[j], dir.def)
        }
      }
    }
  }
}

/**
 * Compile a textNode and return a nodeLinkFn.
 *
 * @param {TextNode} node
 * @param {Object} options
 * @return {Function|null} textNodeLinkFn
 */

function compileTextNode (node, options) {
  var tokens = textParser.parse(node.data)
  if (!tokens) {
    return null
  }
  var frag = document.createDocumentFragment()
  var el, token
  for (var i = 0, l = tokens.length; i < l; i++) {
    token = tokens[i]
    el = token.tag
      ? processTextToken(token, options)
      : document.createTextNode(token.value)
    frag.appendChild(el)
  }
  return makeTextNodeLinkFn(tokens, frag, options)
}

/**
 * Process a single text token.
 *
 * @param {Object} token
 * @param {Object} options
 * @return {Node}
 */

function processTextToken (token, options) {
  var el
  if (token.oneTime) {
    el = document.createTextNode(token.value)
  } else {
    if (token.html) {
      el = document.createComment('v-html')
      setTokenType('html')
    } else if (token.partial) {
      el = document.createComment('v-partial')
      setTokenType('partial')
    } else {
      // IE will clean up empty textNodes during
      // frag.cloneNode(true), so we have to give it
      // something here...
      el = document.createTextNode(' ')
      setTokenType('text')
    }
  }
  function setTokenType (type) {
    token.type = type
    token.def = options.directives[type]
    token.descriptor = dirParser.parse(token.value)[0]
  }
  return el
}

/**
 * Build a function that processes a textNode.
 *
 * @param {Array<Object>} tokens
 * @param {DocumentFragment} frag
 */

function makeTextNodeLinkFn (tokens, frag) {
  return function textNodeLinkFn (vm, el) {
    var fragClone = frag.cloneNode(true)
    var childNodes = _.toArray(fragClone.childNodes)
    var token, value, node
    for (var i = 0, l = tokens.length; i < l; i++) {
      token = tokens[i]
      value = token.value
      if (token.tag) {
        node = childNodes[i]
        if (token.oneTime) {
          value = vm.$eval(value)
          if (token.html) {
            _.replace(node, templateParser.parse(value, true))
          } else {
            node.data = value
          }
        } else {
          vm._bindDir(token.type, node,
                      token.descriptor, token.def)
        }
      }
    }
    _.replace(el, fragClone)
  }
}

/**
 * Compile a node list and return a childLinkFn.
 *
 * @param {NodeList} nodeList
 * @param {Object} options
 * @return {Function|undefined}
 */

function compileNodeList (nodeList, options) {
  var linkFns = []
  var nodeLinkFn, childLinkFn, node
  for (var i = 0, l = nodeList.length; i < l; i++) {
    node = nodeList[i]
    nodeLinkFn = compileNode(node, options)
    childLinkFn =
      !(nodeLinkFn && nodeLinkFn.terminal) &&
      node.tagName !== 'SCRIPT' &&
      node.hasChildNodes()
        ? compileNodeList(node.childNodes, options)
        : null
    linkFns.push(nodeLinkFn, childLinkFn)
  }
  return linkFns.length
    ? makeChildLinkFn(linkFns)
    : null
}

/**
 * Make a child link function for a node's childNodes.
 *
 * @param {Array<Function>} linkFns
 * @return {Function} childLinkFn
 */

function makeChildLinkFn (linkFns) {
  return function childLinkFn (vm, nodes) {
    var node, nodeLinkFn, childrenLinkFn
    for (var i = 0, n = 0, l = linkFns.length; i < l; n++) {
      node = nodes[n]
      nodeLinkFn = linkFns[i++]
      childrenLinkFn = linkFns[i++]
      // cache childNodes before linking parent, fix #657
      var childNodes = _.toArray(node.childNodes)
      if (nodeLinkFn) {
        nodeLinkFn(vm, node)
      }
      if (childrenLinkFn) {
        childrenLinkFn(vm, childNodes)
      }
    }
  }
}

/**
 * Compile param attributes on a root element and return
 * a paramAttributes link function.
 *
 * @param {Element} el
 * @param {Array} attrs
 * @param {Object} options
 * @return {Function} paramsLinkFn
 */

function compileParamAttributes (el, attrs, options) {
  var params = []
  var i = attrs.length
  var name, value, param
  while (i--) {
    name = attrs[i]
    if (/[A-Z]/.test(name)) {
      _.warn(
        'You seem to be using camelCase for a paramAttribute, ' +
        'but HTML doesn\'t differentiate between upper and ' +
        'lower case. You should use hyphen-delimited ' +
        'attribute names. For more info see ' +
        'http://vuejs.org/api/options.html#paramAttributes'
      )
    }
    value = el.getAttribute(name)
    if (value !== null) {
      param = {
        name: name,
        value: value
      }
      var tokens = textParser.parse(value)
      if (tokens) {
        el.removeAttribute(name)
        if (tokens.length > 1) {
          _.warn(
            'Invalid param attribute binding: "' +
            name + '="' + value + '"' +
            '\nDon\'t mix binding tags with plain text ' +
            'in param attribute bindings.'
          )
          continue
        } else {
          param.dynamic = true
          param.value = tokens[0].value
        }
      }
      params.push(param)
    }
  }
  return makeParamsLinkFn(params, options)
}

/**
 * Build a function that applies param attributes to a vm.
 *
 * @param {Array} params
 * @param {Object} options
 * @return {Function} paramsLinkFn
 */

var dataAttrRE = /^data-/

function makeParamsLinkFn (params, options) {
  var def = options.directives['with']
  return function paramsLinkFn (vm, el) {
    var i = params.length
    var param, path
    while (i--) {
      param = params[i]
      // params could contain dashes, which will be
      // interpreted as minus calculations by the parser
      // so we need to wrap the path here
      path = _.camelize(param.name.replace(dataAttrRE, ''))
      if (param.dynamic) {
        // dynamic param attribtues are bound as v-with.
        // we can directly duck the descriptor here beacuse
        // param attributes cannot use expressions or
        // filters.
        vm._bindDir('with', el, {
          arg: path,
          expression: param.value
        }, def)
      } else {
        // just set once
        vm.$set(path, param.value)
      }
    }
  }
}

/**
 * Check an element for terminal directives in fixed order.
 * If it finds one, return a terminal link function.
 *
 * @param {Element} el
 * @param {Object} options
 * @return {Function} terminalLinkFn
 */

var terminalDirectives = [
  'repeat',
  'if',
  'component'
]

function skip () {}
skip.terminal = true

function checkTerminalDirectives (el, options) {
  if (_.attr(el, 'pre') !== null) {
    return skip
  }
  var value, dirName
  /* jshint boss: true */
  for (var i = 0; i < 3; i++) {
    dirName = terminalDirectives[i]
    if (value = _.attr(el, dirName)) {
      return makeTeriminalLinkFn(el, dirName, value, options)
    }
  }
}

/**
 * Build a link function for a terminal directive.
 *
 * @param {Element} el
 * @param {String} dirName
 * @param {String} value
 * @param {Object} options
 * @return {Function} terminalLinkFn
 */

function makeTeriminalLinkFn (el, dirName, value, options) {
  var descriptor = dirParser.parse(value)[0]
  var def = options.directives[dirName]
  var terminalLinkFn = function (vm, el) {
    vm._bindDir(dirName, el, descriptor, def)
  }
  terminalLinkFn.terminal = true
  return terminalLinkFn
}

/**
 * Collect the directives on an element.
 *
 * @param {Element} el
 * @param {Object} options
 * @param {Boolean} asParent
 * @return {Array}
 */

function collectDirectives (el, options, asParent) {
  var attrs = _.toArray(el.attributes)
  var i = attrs.length
  var dirs = []
  var attr, attrName, dir, dirName, dirDef
  while (i--) {
    attr = attrs[i]
    attrName = attr.name
    if (attrName.indexOf(config.prefix) === 0) {
      dirName = attrName.slice(config.prefix.length)
      if (asParent &&
          (dirName === 'with' ||
           dirName === 'component')) {
        continue
      }
      dirDef = options.directives[dirName]
      _.assertAsset(dirDef, 'directive', dirName)
      if (dirDef) {
        dirs.push({
          name: dirName,
          descriptors: dirParser.parse(attr.value),
          def: dirDef
        })
      }
    } else if (config.interpolate) {
      dir = collectAttrDirective(el, attrName, attr.value,
                                 options)
      if (dir) {
        dirs.push(dir)
      }
    }
  }
  // sort by priority, LOW to HIGH
  dirs.sort(directiveComparator)
  return dirs
}

/**
 * Check an attribute for potential dynamic bindings,
 * and return a directive object.
 *
 * @param {Element} el
 * @param {String} name
 * @param {String} value
 * @param {Object} options
 * @return {Object}
 */

function collectAttrDirective (el, name, value, options) {
  if (options._skipAttrs &&
      options._skipAttrs.indexOf(name) > -1) {
    return
  }
  var tokens = textParser.parse(value)
  if (tokens) {
    var def = options.directives.attr
    var i = tokens.length
    var allOneTime = true
    while (i--) {
      var token = tokens[i]
      if (token.tag && !token.oneTime) {
        allOneTime = false
      }
    }
    return {
      def: def,
      _link: allOneTime
        ? function (vm, el) {
            el.setAttribute(name, vm.$interpolate(value))
          }
        : function (vm, el) {
            var value = textParser.tokensToExp(tokens, vm)
            var desc = dirParser.parse(name + ':' + value)[0]
            vm._bindDir('attr', el, desc, def)
          }
    }
  }
}

/**
 * Directive priority sort comparator
 *
 * @param {Object} a
 * @param {Object} b
 */

function directiveComparator (a, b) {
  a = a.def.priority || 0
  b = b.def.priority || 0
  return a > b ? 1 : -1
}<|endoftext|>


<commit_before>/** *
 * Jobs of this module
 * - Maintain the list of components in the Redux store. So monitor new components
 *   and add/remove components.
 * - Watch components for query changes and extract these and update the store.
 * - Ensure all page queries are run as part of bootstrap and report back when
 *   this is done
 * - Whenever a query changes, re-run all pages that rely on this query.
 ***/

const _ = require(`lodash`)
const chokidar = require(`chokidar`)

const path = require(`path`)
const { slash } = require(`gatsby-core-utils`)

const { store, emitter } = require(`../redux/`)
const { boundActionCreators } = require(`../redux/actions`)
const queryCompiler = require(`./query-compiler`).default
const report = require(`gatsby-cli/lib/reporter`)
const queryUtil = require(`./index`)
const debug = require(`debug`)(`gatsby:query-watcher`)
const getGatsbyDependents = require(`../utils/gatsby-dependents`)

const getQueriesSnapshot = () => {
  const state = store.getState()

  const snapshot = {
    components: new Map(state.components),
    staticQueryComponents: new Map(state.staticQueryComponents),
  }

  return snapshot
}

const handleComponentsWithRemovedQueries = (
  { components, staticQueryComponents },
  queries
) => {
  // If a component had static query and it doesn't have it
  // anymore - update the store
  staticQueryComponents.forEach(c => {
    if (c.query !== `` && !queries.has(c.componentPath)) {
      debug(`Static query was removed from ${c.componentPath}`)
      store.dispatch({
        type: `REMOVE_STATIC_QUERY`,
        payload: c.id,
      })
      boundActionCreators.deleteComponentsDependencies([c.id])
    }
  })
}

const handleQuery = (
  { components, staticQueryComponents },
  query,
  component
) => {
  // If this is a static query
  // Add action / reducer + watch staticquery files
  if (query.isStaticQuery) {
    const oldQuery = staticQueryComponents.get(query.id)
    const isNewQuery = !oldQuery

    // Compare query text because text is compiled query with any attached
    // fragments and we want to rerun queries if fragments are edited.
    // Compare hash because hash is used for identyfing query and
    // passing data to component in development. Hash can change if user will
    // format query text, but it doesn't mean that compiled text will change.
    if (
      isNewQuery ||
      oldQuery.hash !== query.hash ||
      oldQuery.text !== query.text
    ) {
      boundActionCreators.replaceStaticQuery({
        name: query.name,
        componentPath: query.path,
        id: query.id,
        query: query.text,
        hash: query.hash,
      })

      debug(
        `Static query in ${component} ${
          isNewQuery ? `was added` : `has changed`
        }.`
      )

      boundActionCreators.deleteComponentsDependencies([query.id])
      queryUtil.enqueueExtractedQueryId(query.id)
    }
    return true
  }

  return false
}

const updateStateAndRunQueries = (isFirstRun, { parentSpan } = {}) => {
  const snapshot = getQueriesSnapshot()
  return queryCompiler({ parentSpan }).then(queries => {
    // If there's an error while extracting queries, the queryCompiler returns false
    // or zero results.
    // Yeah, should probably be an error but don't feel like threading the error
    // all the way here.
    if (!queries || queries.size === 0) {
      return null
    }
    handleComponentsWithRemovedQueries(snapshot, queries)

    // Run action for each component
    const { components } = snapshot
    components.forEach(c =>
      boundActionCreators.queryExtracted({
        componentPath: c.componentPath,
        query: queries.get(c.componentPath)?.text || ``,
      })
    )

    let queriesWillNotRun = false
    queries.forEach((query, component) => {
      const queryWillRun = handleQuery(snapshot, query, component)

      if (queryWillRun) {
        watchComponent(component)
        // Check if this is a page component.
        // If it is and this is our first run during bootstrap,
        // show a warning about having a query in a non-page component.
      } else if (isFirstRun && !snapshot.components.has(component)) {
        report.warn(
          `The GraphQL query in the non-page component "${component}" will not be run.`
        )
        queriesWillNotRun = true
      }
    })

    if (queriesWillNotRun) {
      report.log(report.stripIndent`

        Exported queries are only executed for Page components. It's possible you're
        trying to create pages in your gatsby-node.js and that's failing for some
        reason.

        If the failing component(s) is a regular component and not intended to be a page
        component, you generally want to use a <StaticQuery> (https://gatsbyjs.org/docs/static-query)
        instead of exporting a page query.

        If you're more experienced with GraphQL, you can also export GraphQL
        fragments from components and compose the fragments in the Page component
        query and pass data down into the child component — http://graphql.org/learn/queries/#fragments

      `)
    }

    queryUtil.runQueuedQueries()

    return null
  })
}

/**
 * Removes components templates that aren't used by any page from redux store.
 */
const clearInactiveComponents = () => {
  const { components, pages } = store.getState()

  const activeTemplates = new Set()
  pages.forEach(page => {
    // Set will guarantee uniqeness of entires
    activeTemplates.add(slash(page.component))
  })

  components.forEach(component => {
    if (!activeTemplates.has(component.componentPath)) {
      debug(
        `${component.componentPath} component was removed because it isn't used by any page`
      )
      store.dispatch({
        type: `REMOVE_TEMPLATE_COMPONENT`,
        payload: component,
      })
    }
  })
}

exports.extractQueries = ({ parentSpan } = {}) => {
  // Remove template components that point to not existing page templates.
  // We need to do this, because components data is cached and there might
  // be changes applied when development server isn't running. This is needed
  // only in initial run, because during development state will be adjusted.
  clearInactiveComponents()

  return updateStateAndRunQueries(true, { parentSpan }).then(() => {
    // During development start watching files to recompile & run
    // queries on the fly.
    if (process.env.NODE_ENV !== `production`) {
      watch(store.getState().program.directory)
    }
  })
}

const filesToWatch = new Set()
let watcher
const watchComponent = componentPath => {
  // We don't start watching until mid-way through the bootstrap so ignore
  // new components being added until then. This doesn't affect anything as
  // when extractQueries is called from bootstrap, we make sure that all
  // components are being watched.
  if (
    process.env.NODE_ENV !== `production` &&
    !filesToWatch.has(componentPath)
  ) {
    filesToWatch.add(componentPath)
    if (watcher) {
      watcher.add(componentPath)
    }
  }
}

const debounceCompile = _.debounce(() => {
  updateStateAndRunQueries()
}, 100)

const watch = async rootDir => {
  if (watcher) return

  const modulesThatUseGatsby = await getGatsbyDependents()

  const packagePaths = modulesThatUseGatsby.map(module => {
    const filesRegex = `*.+(t|j)s?(x)`
    const pathRegex = `/{${filesRegex},!(node_modules)/**/${filesRegex}}`
    return slash(path.join(module.path, pathRegex))
  })

  watcher = chokidar
    .watch([
      slash(path.join(rootDir, `/src/**/*.{js,jsx,ts,tsx}`)),
      ...packagePaths,
    ])
    .on(`change`, path => {
      report.pendingActivity({ id: `query-extraction` })
      debounceCompile()
    })

  filesToWatch.forEach(filePath => watcher.add(filePath))
}

exports.startWatchDeletePage = () => {
  emitter.on(`DELETE_PAGE`, action => {
    const componentPath = slash(action.payload.component)
    const { pages } = store.getState()
    let otherPageWithTemplateExists = false
    for (let page of pages.values()) {
      if (slash(page.component) === componentPath) {
        otherPageWithTemplateExists = true
        break
      }
    }
    if (!otherPageWithTemplateExists) {
      store.dispatch({
        type: `REMOVE_TEMPLATE_COMPONENT`,
        payload: {
          componentPath,
        },
      })
    }
  })
}

exports.updateStateAndRunQueries = updateStateAndRunQueries
<commit_msg>fix(gatsby): don't rerun static queries if text didn't change (#19616)<commit_after>/** *
 * Jobs of this module
 * - Maintain the list of components in the Redux store. So monitor new components
 *   and add/remove components.
 * - Watch components for query changes and extract these and update the store.
 * - Ensure all page queries are run as part of bootstrap and report back when
 *   this is done
 * - Whenever a query changes, re-run all pages that rely on this query.
 ***/

const _ = require(`lodash`)
const chokidar = require(`chokidar`)

const path = require(`path`)
const { slash } = require(`gatsby-core-utils`)

const { store, emitter } = require(`../redux/`)
const { boundActionCreators } = require(`../redux/actions`)
const queryCompiler = require(`./query-compiler`).default
const report = require(`gatsby-cli/lib/reporter`)
const queryUtil = require(`./index`)
const debug = require(`debug`)(`gatsby:query-watcher`)
const getGatsbyDependents = require(`../utils/gatsby-dependents`)

const getQueriesSnapshot = () => {
  const state = store.getState()

  const snapshot = {
    components: new Map(state.components),
    staticQueryComponents: new Map(state.staticQueryComponents),
  }

  return snapshot
}

const handleComponentsWithRemovedQueries = (
  { components, staticQueryComponents },
  queries
) => {
  // If a component had static query and it doesn't have it
  // anymore - update the store
  staticQueryComponents.forEach(c => {
    if (c.query !== `` && !queries.has(c.componentPath)) {
      debug(`Static query was removed from ${c.componentPath}`)
      store.dispatch({
        type: `REMOVE_STATIC_QUERY`,
        payload: c.id,
      })
      boundActionCreators.deleteComponentsDependencies([c.id])
    }
  })
}

const handleQuery = (
  { components, staticQueryComponents },
  query,
  component
) => {
  // If this is a static query
  // Add action / reducer + watch staticquery files
  if (query.isStaticQuery) {
    const oldQuery = staticQueryComponents.get(query.id)
    const isNewQuery = !oldQuery

    // Compare query text because text is compiled query with any attached
    // fragments and we want to rerun queries if fragments are edited.
    // Compare hash because hash is used for identyfing query and
    // passing data to component in development. Hash can change if user will
    // format query text, but it doesn't mean that compiled text will change.
    if (
      isNewQuery ||
      oldQuery.hash !== query.hash ||
      oldQuery.query !== query.text
    ) {
      boundActionCreators.replaceStaticQuery({
        name: query.name,
        componentPath: query.path,
        id: query.id,
        query: query.text,
        hash: query.hash,
      })

      debug(
        `Static query in ${component} ${
          isNewQuery ? `was added` : `has changed`
        }.`
      )

      boundActionCreators.deleteComponentsDependencies([query.id])
      queryUtil.enqueueExtractedQueryId(query.id)
    }
    return true
  }

  return false
}

const updateStateAndRunQueries = (isFirstRun, { parentSpan } = {}) => {
  const snapshot = getQueriesSnapshot()
  return queryCompiler({ parentSpan }).then(queries => {
    // If there's an error while extracting queries, the queryCompiler returns false
    // or zero results.
    // Yeah, should probably be an error but don't feel like threading the error
    // all the way here.
    if (!queries || queries.size === 0) {
      return null
    }
    handleComponentsWithRemovedQueries(snapshot, queries)

    // Run action for each component
    const { components } = snapshot
    components.forEach(c =>
      boundActionCreators.queryExtracted({
        componentPath: c.componentPath,
        query: queries.get(c.componentPath)?.text || ``,
      })
    )

    let queriesWillNotRun = false
    queries.forEach((query, component) => {
      const queryWillRun = handleQuery(snapshot, query, component)

      if (queryWillRun) {
        watchComponent(component)
        // Check if this is a page component.
        // If it is and this is our first run during bootstrap,
        // show a warning about having a query in a non-page component.
      } else if (isFirstRun && !snapshot.components.has(component)) {
        report.warn(
          `The GraphQL query in the non-page component "${component}" will not be run.`
        )
        queriesWillNotRun = true
      }
    })

    if (queriesWillNotRun) {
      report.log(report.stripIndent`

        Exported queries are only executed for Page components. It's possible you're
        trying to create pages in your gatsby-node.js and that's failing for some
        reason.

        If the failing component(s) is a regular component and not intended to be a page
        component, you generally want to use a <StaticQuery> (https://gatsbyjs.org/docs/static-query)
        instead of exporting a page query.

        If you're more experienced with GraphQL, you can also export GraphQL
        fragments from components and compose the fragments in the Page component
        query and pass data down into the child component — http://graphql.org/learn/queries/#fragments

      `)
    }

    queryUtil.runQueuedQueries()

    return null
  })
}

/**
 * Removes components templates that aren't used by any page from redux store.
 */
const clearInactiveComponents = () => {
  const { components, pages } = store.getState()

  const activeTemplates = new Set()
  pages.forEach(page => {
    // Set will guarantee uniqeness of entires
    activeTemplates.add(slash(page.component))
  })

  components.forEach(component => {
    if (!activeTemplates.has(component.componentPath)) {
      debug(
        `${component.componentPath} component was removed because it isn't used by any page`
      )
      store.dispatch({
        type: `REMOVE_TEMPLATE_COMPONENT`,
        payload: component,
      })
    }
  })
}

exports.extractQueries = ({ parentSpan } = {}) => {
  // Remove template components that point to not existing page templates.
  // We need to do this, because components data is cached and there might
  // be changes applied when development server isn't running. This is needed
  // only in initial run, because during development state will be adjusted.
  clearInactiveComponents()

  return updateStateAndRunQueries(true, { parentSpan }).then(() => {
    // During development start watching files to recompile & run
    // queries on the fly.
    if (process.env.NODE_ENV !== `production`) {
      watch(store.getState().program.directory)
    }
  })
}

const filesToWatch = new Set()
let watcher
const watchComponent = componentPath => {
  // We don't start watching until mid-way through the bootstrap so ignore
  // new components being added until then. This doesn't affect anything as
  // when extractQueries is called from bootstrap, we make sure that all
  // components are being watched.
  if (
    process.env.NODE_ENV !== `production` &&
    !filesToWatch.has(componentPath)
  ) {
    filesToWatch.add(componentPath)
    if (watcher) {
      watcher.add(componentPath)
    }
  }
}

const debounceCompile = _.debounce(() => {
  updateStateAndRunQueries()
}, 100)

const watch = async rootDir => {
  if (watcher) return

  const modulesThatUseGatsby = await getGatsbyDependents()

  const packagePaths = modulesThatUseGatsby.map(module => {
    const filesRegex = `*.+(t|j)s?(x)`
    const pathRegex = `/{${filesRegex},!(node_modules)/**/${filesRegex}}`
    return slash(path.join(module.path, pathRegex))
  })

  watcher = chokidar
    .watch([
      slash(path.join(rootDir, `/src/**/*.{js,jsx,ts,tsx}`)),
      ...packagePaths,
    ])
    .on(`change`, path => {
      report.pendingActivity({ id: `query-extraction` })
      debounceCompile()
    })

  filesToWatch.forEach(filePath => watcher.add(filePath))
}

exports.startWatchDeletePage = () => {
  emitter.on(`DELETE_PAGE`, action => {
    const componentPath = slash(action.payload.component)
    const { pages } = store.getState()
    let otherPageWithTemplateExists = false
    for (let page of pages.values()) {
      if (slash(page.component) === componentPath) {
        otherPageWithTemplateExists = true
        break
      }
    }
    if (!otherPageWithTemplateExists) {
      store.dispatch({
        type: `REMOVE_TEMPLATE_COMPONENT`,
        payload: {
          componentPath,
        },
      })
    }
  })
}

exports.updateStateAndRunQueries = updateStateAndRunQueries
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import Link from 'gatsby-link';

import './Navigation.scss';
import logo from './logo.jpg';

const Navigation = ({ location }) => (

         UIKit

      <button
        className="navbar-toggler"
        type="button"
        data-toggle="collapse"
        data-target="#navbarSupportedContentTop"
        aria-controls="navbarSupportedContentTop"
        aria-expanded="false"
        aria-label="Toggle navigation"
      >

      </button>

            <Link className="nav-link docs-nav-link" to="/">
              Home
            </Link>

            <Link className="nav-link docs-nav-link" to="/components">
              Components
            </Link>

              Github

);

Navigation.propTypes = {
  location: PropTypes.shape({
    pathname: PropTypes.string,
  }),
};

export default Navigation;
<commit_msg>docs(www): use withPrefix helper from Gatsby<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import Link, { withPrefix } from 'gatsby-link';

import './Navigation.scss';
import logo from './logo.jpg';

const Navigation = ({ location }) => (

         UIKit

      <button
        className="navbar-toggler"
        type="button"
        data-toggle="collapse"
        data-target="#navbarSupportedContentTop"
        aria-controls="navbarSupportedContentTop"
        aria-expanded="false"
        aria-label="Toggle navigation"
      >

      </button>

            <Link className="nav-link docs-nav-link" to={withPrefix('/')}>
              Home
            </Link>

            <Link className="nav-link docs-nav-link" to={withPrefix('/components')}>
              Components
            </Link>

              Github

);

Navigation.propTypes = {
  location: PropTypes.shape({
    pathname: PropTypes.string,
  }),
};

export default Navigation;
<|endoftext|>


<commit_before>
// this sets the background color of the master UIView (when there are no windows/tab groups on it)
Titanium.UI.setBackgroundColor('#000');

// create tab group
var tabGroup = Titanium.UI.createTabGroup();

//
// create base UI tab and root window
//
var win1 = Titanium.UI.createWindow({
    title:'Friday, April 17th',
    backgroundImage:"pictures/banner.jpg"
});
var tab1 = Titanium.UI.createTab({
    icon:'KS_nav_ui.png',
    title:'Friday Events',
    window:win1
});

var label1 = Titanium.UI.createLabel({
	color:'black',
	top:'37%',
	text:'April 17th-18th',
	font:{fontSize:60,fontFamily:'Helvetica Neue'},
	textAlign:'center',
	width:'auto',
	layout:'vertical'
});

var ring = Titanium.UI.createButton({
	title:'Official UI Class Ring Sales',
	top:'40%',
	left:'20%'
});
ring.addEventListener('click', function(e) {
	alert('Time - 1pm to 5pm\nPlace - VandaStore Plaza');
	});

var race = Titanium.UI.createButton({
	title:'Amazing Race Traditions Challenge',
	top:'40%',
	left:'50%'
});
race.addEventListener('click', function(e) {
	alert('Time - 5pm to 6pm\nPlace - Meet at VandalStore\nCost - $10, includes Tradition Keepers book');
});

var gala = Titanium.UI.createButton({
	title:'CALS Moms Weekend Gala Wine and Cheese Tasting',
	top:'50%',
	left:'20%'
});
gala.addEventListener('click', function(e) {
	alert('Time - 5pm to 8pm\nPlace - Pitman Center International Ballroom\nCost - $20/person or $35/couple\nRSVP Required');
});

var bella = Titanium.UI.createButton({
	title:'Bella Notte: An Italian Dinner',
	top:'50%',
	left:'50%'
});
bella.addEventListener('click', function(e) {
	alert('Time - 5pm to 8:30pm\nPlace - St. Augustines Catholic Center\nCost - $5/student, $6/person, $18/group of 4');
});

label1.add(ring);
label1.add(race);
label1.add(gala);
label1.add(bella);

win1.add(label1);

//
// create controls tab and root window
//
var win2 = Titanium.UI.createWindow({
    title:'Contact Information',
    backgroundImage:'pictures/banner.jpg',
    layout:'vertical',
});
var tab2 = Titanium.UI.createTab({
    icon:'KS_nav_ui.png',
    title:'Contact',
    window:win2
});

var label2 = Titanium.UI.createLabel({
	color:'black',
	top:'30%',
	text:'Welcome Moms',
	font:{fontSize:35,fontFamily:'Helvetica Neue'},
	width:'100%'
});

win2.add(label2);

//tab 3
var win3 = Titanium.UI.createWindow({
    title:'Saturday, April 18th',
    backgroundImage:"pictures/banner.jpg"
});
var tab3 = Titanium.UI.createTab({
    icon:'KS_nav_ui.png',
    title:'Saturday Events',
    window:win3
});
var label3 = Titanium.UI.createLabel({
	color:'black',
	text:'April 17th-18th',
	font:{fontSize:60,fontFamily:'Helvetica Neue'},
	textAlign:'center',
	width:'auto'
});

var button6 = Titanium.UI.createButton({
	title:'Brunch featuring University of Idaho Jazz Choir',
	top:'40%',
	left:'20%'
	});

var button7 = Titanium.UI.createButton({
	top:'40%',
	left:'60%',
	title:'Key for a Cure Fun Run',
});

var button8 = Titanium.UI.createButton({
	top:'50%',
	left:'20%',
	title:'Official UI Class Ring Sales',

});
	var button9 = Titanium.UI.createButton({
	top:'50%',
	left:'60%',
	title:'Annual Phi Delta Theta Turtle Derby',
});

var button10 = Titanium.UI.createButton({
	top:'60%',
	left:'20%',
	title:'Greenthumb 101',
});

var button11 = Titanium.UI.createButton({
	top:'60%',
	left:'60%',
	title:'Greenthumb 201',
});

var button12 = Titanium.UI.createButton({
	top:'70%',
	left:'20%',
	title:'Dinner and Entertainment with FRANGELA',
});

button6.addEventListener('click', function(e) {alert
	('Brunch featuring University of Idaho Jazz Choir\nPitman Center Ballroom\nApril 18th, 9:30 a.m.\nCost: $20/person');
});

button7.addEventListener('click', function(e) {alert
	('Key for a Cure Fun Run\nStart at Memorial Gym\nApril 18th, 10:00 a.m.\nCost: $17 including T-shirt; $10 without');
});

button9.addEventListener('click', function(e) {alert
	('Official UI Class Ring Sales\nVandalStore Plaza, 710 Deakin Ave.\nApril 18th, 10:00 a.m.-3:00 p.m.');
});
button10.addEventListener('click', function(e) {alert
	('Greenthumb 101\n6th Street Greenhouse.\nApril 18th, 10:30 a.m.-11:30 a.m.\nCost:$15 per pot/basket | Pay at the door');
});

button11.addEventListener('click', function(e) {alert
	('Annual Phi Delta Theta Turtle Derby\n804 Elm St.\nApril 18th, 11:00 a.m.\nCost: Free');
});

button12.addEventListener('click', function(e) {alert
	('Greenthumb 201\n6th Street Greenhouse\nApril 18th, 1:00 p.m. - 2:00 p.m.\nCost: $15 per pot/basket | Pay at the door');
});

win3.add(label3);
label3.add(button6);
label3.add(button7);
label3.add(button9);
label3.add(button10);
label3.add(button11);
label3.add(button12);

//
//  add tabs
//
tabGroup.addTab(tab1);
tabGroup.addTab(tab2);
tabGroup.addTab(tab3);

// open tab group
tabGroup.open();

<commit_msg>Update app.js<commit_after>
// this sets the background color of the master UIView (when there are no windows/tab groups on it)
Titanium.UI.setBackgroundColor('#000');

// create tab group
var tabGroup = Titanium.UI.createTabGroup();

//
// create base UI tab and root window
//
var win1 = Titanium.UI.createWindow({
    title:'Friday, April 17th',
    backgroundImage:"images/banner.jpg"
});
var tab1 = Titanium.UI.createTab({
    icon:'KS_nav_ui.png',
    title:'Friday Events',
    window:win1
});

var label1 = Titanium.UI.createLabel({
	color:'black',
	top:'37%',
	text:'April 17th-18th',
	font:{fontSize:60,fontFamily:'Helvetica Neue'},
	textAlign:'center',
	width:'auto',
	layout:'vertical'
});

var ring = Titanium.UI.createButton({
	title:'Official UI Class Ring Sales',
	top:'40%',
	left:'20%'
});
ring.addEventListener('click', function(e) {
	alert('Time - 1pm to 5pm\nPlace - VandaStore Plaza');
	});

var race = Titanium.UI.createButton({
	title:'Amazing Race Traditions Challenge',
	top:'40%',
	left:'50%'
});
race.addEventListener('click', function(e) {
	alert('Time - 5pm to 6pm\nPlace - Meet at VandalStore\nCost - $10, includes Tradition Keepers book');
});

var gala = Titanium.UI.createButton({
	title:'CALS Moms Weekend Gala Wine and Cheese Tasting',
	top:'50%',
	left:'20%'
});
gala.addEventListener('click', function(e) {
	alert('Time - 5pm to 8pm\nPlace - Pitman Center International Ballroom\nCost - $20/person or $35/couple\nRSVP Required');
});

var bella = Titanium.UI.createButton({
	title:'Bella Notte: An Italian Dinner',
	top:'50%',
	left:'50%'
});
bella.addEventListener('click', function(e) {
	alert('Time - 5pm to 8:30pm\nPlace - St. Augustines Catholic Center\nCost - $5/student, $6/person, $18/group of 4');
});

label1.add(ring);
label1.add(race);
label1.add(gala);
label1.add(bella);

win1.add(label1);

//
// create controls tab and root window
//
var win2 = Titanium.UI.createWindow({
    title:'Contact Information',
    backgroundImage:'images/banner.jpg',
    layout:'vertical',
});
var tab2 = Titanium.UI.createTab({
    icon:'KS_nav_ui.png',
    title:'Contact',
    window:win2
});

var label2 = Titanium.UI.createLabel({
	color:'black',
	top:'30%',
	text:'Welcome Moms',
	font:{fontSize:35,fontFamily:'Helvetica Neue'},
	width:'100%'
});

win2.add(label2);

//tab 3
var win3 = Titanium.UI.createWindow({
    title:'Saturday, April 18th',
    backgroundImage:"images/banner.jpg"
});
var tab3 = Titanium.UI.createTab({
    icon:'KS_nav_ui.png',
    title:'Saturday Events',
    window:win3
});
var label3 = Titanium.UI.createLabel({
	color:'black',
	text:'April 17th-18th',
	font:{fontSize:60,fontFamily:'Helvetica Neue'},
	textAlign:'center',
	width:'auto'
});

var button6 = Titanium.UI.createButton({
	title:'Brunch featuring University of Idaho Jazz Choir',
	top:'40%',
	left:'20%'
	});

var button7 = Titanium.UI.createButton({
	top:'40%',
	left:'60%',
	title:'Key for a Cure Fun Run',
});

var button8 = Titanium.UI.createButton({
	top:'50%',
	left:'20%',
	title:'Official UI Class Ring Sales',

});
	var button9 = Titanium.UI.createButton({
	top:'50%',
	left:'60%',
	title:'Annual Phi Delta Theta Turtle Derby',
});

var button10 = Titanium.UI.createButton({
	top:'60%',
	left:'20%',
	title:'Greenthumb 101',
});

var button11 = Titanium.UI.createButton({
	top:'60%',
	left:'60%',
	title:'Greenthumb 201',
});

var button12 = Titanium.UI.createButton({
	top:'70%',
	left:'20%',
	title:'Dinner and Entertainment with FRANGELA',
});

button6.addEventListener('click', function(e) {alert
	('Brunch featuring University of Idaho Jazz Choir\nPitman Center Ballroom\nApril 18th, 9:30 a.m.\nCost: $20/person');
});

button7.addEventListener('click', function(e) {alert
	('Key for a Cure Fun Run\nStart at Memorial Gym\nApril 18th, 10:00 a.m.\nCost: $17 including T-shirt; $10 without');
});

button9.addEventListener('click', function(e) {alert
	('Official UI Class Ring Sales\nVandalStore Plaza, 710 Deakin Ave.\nApril 18th, 10:00 a.m.-3:00 p.m.');
});
button10.addEventListener('click', function(e) {alert
	('Greenthumb 101\n6th Street Greenhouse.\nApril 18th, 10:30 a.m.-11:30 a.m.\nCost:$15 per pot/basket | Pay at the door');
});

button11.addEventListener('click', function(e) {alert
	('Annual Phi Delta Theta Turtle Derby\n804 Elm St.\nApril 18th, 11:00 a.m.\nCost: Free');
});

button12.addEventListener('click', function(e) {alert
	('Greenthumb 201\n6th Street Greenhouse\nApril 18th, 1:00 p.m. - 2:00 p.m.\nCost: $15 per pot/basket | Pay at the door');
});

win3.add(label3);
label3.add(button6);
label3.add(button7);
label3.add(button9);
label3.add(button10);
label3.add(button11);
label3.add(button12);

//
//  add tabs
//
tabGroup.addTab(tab1);
tabGroup.addTab(tab2);
tabGroup.addTab(tab3);

// open tab group
tabGroup.open();

<|endoftext|>


<commit_before>'use strict';

var Reflux = require('Reflux');

var _actions = ['search', 'filter'];

module.exports = Reflux.createActions(_actions);

<commit_msg>fixed reflux typo<commit_after>'use strict';

var Reflux = require('reflux');

var _actions = ['search', 'filter'];

module.exports = Reflux.createActions(_actions);

<|endoftext|>


<commit_before>// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// MIT License. See license.txt

frappe.provide("frappe.ui.toolbar");
frappe.provide('frappe.search');

frappe.ui.toolbar.Toolbar = class {
	constructor () {
		$('header').replaceWith(frappe.render_template("navbar", {
			avatar: frappe.avatar(frappe.session.user, 'avatar-medium'),
			navbar_settings: frappe.boot.navbar_settings
		}));
		$('.dropdown-toggle').dropdown();

		this.setup_awesomebar();
		this.setup_notifications();
		this.make();
	}

	make () {
		this.setup_sidebar();
		this.setup_help();

		this.bind_events();

		$(document).trigger('toolbar_setup');
	}

	bind_events () {
		// clear all custom menus on page change
		$(document).on("page-change", function() {
			$("header .navbar .custom-menu").remove();
		});

		//focus search-modal on show in mobile view
		$('#search-modal').on('shown.bs.modal', function() {
			var search_modal = $(this);
			setTimeout(function() {
				search_modal.find('#modal-search').focus();
			}, 300);
		});
		$('.navbar-toggle-full-width').click(() => {
			frappe.ui.toolbar.toggle_full_width();
		});
	}

	setup_sidebar () {
		var header = $('header');
		header.find(".toggle-sidebar").on("click", function() {
			var layout_side_section = $('.layout-side-section');
			var overlay_sidebar = layout_side_section.find('.overlay-sidebar');

			overlay_sidebar.addClass('opened');
			overlay_sidebar.find('.reports-dropdown')
				.removeClass('dropdown-menu')
				.addClass('list-unstyled');
			overlay_sidebar.find('.dropdown-toggle')
				.addClass('text-muted').find('.caret')
				.addClass('hidden-xs hidden-sm');

			$('
').hide().appendTo(layout_side_section).fadeIn();

			var scroll_container = $('html');
			scroll_container.css("overflow-y", "hidden");

			layout_side_section.find(".close-sidebar").on('click', close_sidebar);
			layout_side_section.on("click", "a:not(.dropdown-toggle)", close_sidebar);

			function close_sidebar(e) {
				scroll_container.css("overflow-y", "");

				layout_side_section.find("div.close-sidebar").fadeOut(function() {
					overlay_sidebar.removeClass('opened')
						.find('.dropdown-toggle')
						.removeClass('text-muted');
					overlay_sidebar.find('.reports-dropdown')
						.addClass('dropdown-menu');
				});
			}
		});
	}

	setup_help () {
		frappe.provide('frappe.help');
		frappe.help.show_results = show_results;

		this.search = new frappe.search.SearchDialog();
		frappe.provide('frappe.searchdialog');
		frappe.searchdialog.search = this.search;

		$(".dropdown-help .dropdown-toggle").on("click", function() {
			$(".dropdown-help input").focus();
		});

		$(".dropdown-help .dropdown-menu").on("click", "input, button", function(e) {
			e.stopPropagation();
		});

		$("#input-help").on("keydown", function(e) {
			if(e.which == 13) {
				$(this).val("");
			}
		});

		$(document).on("page-change", function () {
			var $help_links = $(".dropdown-help #help-links");
			$help_links.html("");

			var route = frappe.get_route_str();
			var breadcrumbs = route.split("/");

			var links = [];
			for (var i = 0; i < breadcrumbs.length; i++) {
				var r = route.split("/", i + 1);
				var key = r.join("/");
				var help_links = frappe.help.help_links[key] || [];
				links = $.merge(links, help_links);
			}

			if(links.length === 0) {
				$help_links.next().hide();
			} else {
				$help_links.next().show();
			}

			for (var i = 0; i < links.length; i++) {
				var link = links[i];
				var url = link.url;
				$("", {
					href: link.url,
					text: link.label,
					target: "_blank"
				}).appendTo($help_links);
			}

			$('.dropdown-help .dropdown-menu').on('click', 'a', show_results);
		});

		var $result_modal = frappe.get_modal("", "");
		$result_modal.addClass("help-modal");

		$(document).on("click", ".help-modal a", show_results);

		function show_results(e) {
			//edit links
			var href = e.target.href;
			if(href.indexOf('blob') > 0) {
				window.open(href, '_blank');
			}
			var path = $(e.target).attr("data-path");
			if(path) {
				e.preventDefault();
			}
		}
	}

	setup_awesomebar() {
		if (frappe.boot.desk_settings.search_bar) {
			let awesome_bar = new frappe.search.AwesomeBar();
			awesome_bar.setup("#navbar-search");
		}
	}

	setup_notifications () {
		if (frappe.boot.desk_settings.notifications) {
			this.notifications = new frappe.ui.Notifications();
		}
	}

}

$.extend(frappe.ui.toolbar, {
	add_dropdown_button: function(parent, label, click, icon) {
		var menu = frappe.ui.toolbar.get_menu(parent);
		if(menu.find("li:not(.custom-menu)").length && !menu.find(".divider").length) {
			frappe.ui.toolbar.add_menu_divider(menu);
		}

		return $('
 '+label+'
')
			.insertBefore(menu.find(".divider"))
			.find("a")
			.click(function() {
				click.apply(this);
			});
	},
	get_menu: function(label) {
		return $("#navbar-" + label.toLowerCase());
	},
	add_menu_divider: function(menu) {
		menu = typeof menu == "string" ?
			frappe.ui.toolbar.get_menu(menu) : menu;

		$('

').prependTo(menu);
	},
	add_icon_link(route, icon, index, class_name) {
		let parent_element = $(".navbar-right").get(0);
		let new_element = $(`

`).get(0);

		parent_element.insertBefore(new_element, parent_element.children[index]);
	},
	toggle_full_width() {
		let fullwidth = JSON.parse(localStorage.container_fullwidth || 'false');
		fullwidth = !fullwidth;
		localStorage.container_fullwidth = fullwidth;
		frappe.ui.toolbar.set_fullwidth_if_enabled();
		$(document.body).trigger('toggleFullWidth');
	},
	set_fullwidth_if_enabled() {
		let fullwidth = JSON.parse(localStorage.container_fullwidth || 'false');
		$(document.body).toggleClass('full-width', fullwidth);
	},
	show_shortcuts (e) {
		e.preventDefault();
		frappe.ui.keys.show_keyboard_shortcut_dialog();
		return false;
	},
});

frappe.ui.toolbar.clear_cache = frappe.utils.throttle(function() {
	frappe.assets.clear_local_storage();
	frappe.xcall('frappe.sessions.clear').then(message => {
		frappe.show_alert({
			message: message,
			indicator: 'info'
		});
		location.reload(true);
	});
}, 10000);

frappe.ui.toolbar.show_about = function() {
	try {
		frappe.ui.misc.about();
	} catch(e) {
		console.log(e);
	}
	return false;
};

frappe.ui.toolbar.route_to_user = function() {
	frappe.set_route('Form', 'User', frappe.session.user);
};

frappe.ui.toolbar.view_website = function() {
	let website_tab = window.open();
	website_tab.opener = null;
	website_tab.location = '/index';
};

frappe.ui.toolbar.setup_session_defaults = function() {
	let fields = [];
	frappe.call({
		method: 'frappe.core.doctype.session_default_settings.session_default_settings.get_session_default_values',
		callback: function (data) {
			fields = JSON.parse(data.message);
			let perms = frappe.perm.get_perm('Session Default Settings');
			//add settings button only if user is a System Manager or has permission on 'Session Default Settings'
			if ((in_list(frappe.user_roles, 'System Manager')) || (perms[0].read == 1))  {
				fields[fields.length] = {
					'fieldname': 'settings',
					'fieldtype': 'Button',
					'label': __('Settings'),
					'click': () => {
						frappe.set_route('Form', 'Session Default Settings', 'Session Default Settings');
					}
				};
			}
			frappe.prompt(fields, function(values) {
				//if default is not set for a particular field in prompt
				fields.forEach(function(d) {
					if (!values[d.fieldname]) {
						values[d.fieldname] = "";
					}
				});
				frappe.call({
					method: 'frappe.core.doctype.session_default_settings.session_default_settings.set_session_default_values',
					args: {
						default_values: values,
					},
					callback: function(data) {
						if (data.message == "success") {
							frappe.show_alert({
								'message': __('Session Defaults Saved'),
								'indicator': 'green'
							});
							frappe.ui.toolbar.clear_cache();
						}	else {
							frappe.show_alert({
								'message': __('An error occurred while setting Session Defaults'),
								'indicator': 'red'
							});
						}
					}
				});
			},
			__('Session Defaults'),
			__('Save'),
			);
		}
	});
};<commit_msg>fix: typo in desk_settings key<commit_after>// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// MIT License. See license.txt

frappe.provide("frappe.ui.toolbar");
frappe.provide('frappe.search');

frappe.ui.toolbar.Toolbar = class {
	constructor () {
		$('header').replaceWith(frappe.render_template("navbar", {
			avatar: frappe.avatar(frappe.session.user, 'avatar-medium'),
			navbar_settings: frappe.boot.navbar_settings
		}));
		$('.dropdown-toggle').dropdown();

		this.setup_awesomebar();
		this.setup_notifications();
		this.make();
	}

	make () {
		this.setup_sidebar();
		this.setup_help();

		this.bind_events();

		$(document).trigger('toolbar_setup');
	}

	bind_events () {
		// clear all custom menus on page change
		$(document).on("page-change", function() {
			$("header .navbar .custom-menu").remove();
		});

		//focus search-modal on show in mobile view
		$('#search-modal').on('shown.bs.modal', function() {
			var search_modal = $(this);
			setTimeout(function() {
				search_modal.find('#modal-search').focus();
			}, 300);
		});
		$('.navbar-toggle-full-width').click(() => {
			frappe.ui.toolbar.toggle_full_width();
		});
	}

	setup_sidebar () {
		var header = $('header');
		header.find(".toggle-sidebar").on("click", function() {
			var layout_side_section = $('.layout-side-section');
			var overlay_sidebar = layout_side_section.find('.overlay-sidebar');

			overlay_sidebar.addClass('opened');
			overlay_sidebar.find('.reports-dropdown')
				.removeClass('dropdown-menu')
				.addClass('list-unstyled');
			overlay_sidebar.find('.dropdown-toggle')
				.addClass('text-muted').find('.caret')
				.addClass('hidden-xs hidden-sm');

			$('
').hide().appendTo(layout_side_section).fadeIn();

			var scroll_container = $('html');
			scroll_container.css("overflow-y", "hidden");

			layout_side_section.find(".close-sidebar").on('click', close_sidebar);
			layout_side_section.on("click", "a:not(.dropdown-toggle)", close_sidebar);

			function close_sidebar(e) {
				scroll_container.css("overflow-y", "");

				layout_side_section.find("div.close-sidebar").fadeOut(function() {
					overlay_sidebar.removeClass('opened')
						.find('.dropdown-toggle')
						.removeClass('text-muted');
					overlay_sidebar.find('.reports-dropdown')
						.addClass('dropdown-menu');
				});
			}
		});
	}

	setup_help () {
		frappe.provide('frappe.help');
		frappe.help.show_results = show_results;

		this.search = new frappe.search.SearchDialog();
		frappe.provide('frappe.searchdialog');
		frappe.searchdialog.search = this.search;

		$(".dropdown-help .dropdown-toggle").on("click", function() {
			$(".dropdown-help input").focus();
		});

		$(".dropdown-help .dropdown-menu").on("click", "input, button", function(e) {
			e.stopPropagation();
		});

		$("#input-help").on("keydown", function(e) {
			if(e.which == 13) {
				$(this).val("");
			}
		});

		$(document).on("page-change", function () {
			var $help_links = $(".dropdown-help #help-links");
			$help_links.html("");

			var route = frappe.get_route_str();
			var breadcrumbs = route.split("/");

			var links = [];
			for (var i = 0; i < breadcrumbs.length; i++) {
				var r = route.split("/", i + 1);
				var key = r.join("/");
				var help_links = frappe.help.help_links[key] || [];
				links = $.merge(links, help_links);
			}

			if(links.length === 0) {
				$help_links.next().hide();
			} else {
				$help_links.next().show();
			}

			for (var i = 0; i < links.length; i++) {
				var link = links[i];
				var url = link.url;
				$("", {
					href: link.url,
					text: link.label,
					target: "_blank"
				}).appendTo($help_links);
			}

			$('.dropdown-help .dropdown-menu').on('click', 'a', show_results);
		});

		var $result_modal = frappe.get_modal("", "");
		$result_modal.addClass("help-modal");

		$(document).on("click", ".help-modal a", show_results);

		function show_results(e) {
			//edit links
			var href = e.target.href;
			if(href.indexOf('blob') > 0) {
				window.open(href, '_blank');
			}
			var path = $(e.target).attr("data-path");
			if(path) {
				e.preventDefault();
			}
		}
	}

	setup_awesomebar() {
		if (frappe.boot.desk_settings.search_bar) {
			let awesome_bar = new frappe.search.AwesomeBar();
			awesome_bar.setup("#navbar-search");
		}
	}

	setup_notifications () {
		if (frappe.boot.desk_settings.notification) {
			this.notifications = new frappe.ui.Notifications();
		}
	}

}

$.extend(frappe.ui.toolbar, {
	add_dropdown_button: function(parent, label, click, icon) {
		var menu = frappe.ui.toolbar.get_menu(parent);
		if(menu.find("li:not(.custom-menu)").length && !menu.find(".divider").length) {
			frappe.ui.toolbar.add_menu_divider(menu);
		}

		return $('
 '+label+'
')
			.insertBefore(menu.find(".divider"))
			.find("a")
			.click(function() {
				click.apply(this);
			});
	},
	get_menu: function(label) {
		return $("#navbar-" + label.toLowerCase());
	},
	add_menu_divider: function(menu) {
		menu = typeof menu == "string" ?
			frappe.ui.toolbar.get_menu(menu) : menu;

		$('

').prependTo(menu);
	},
	add_icon_link(route, icon, index, class_name) {
		let parent_element = $(".navbar-right").get(0);
		let new_element = $(`

`).get(0);

		parent_element.insertBefore(new_element, parent_element.children[index]);
	},
	toggle_full_width() {
		let fullwidth = JSON.parse(localStorage.container_fullwidth || 'false');
		fullwidth = !fullwidth;
		localStorage.container_fullwidth = fullwidth;
		frappe.ui.toolbar.set_fullwidth_if_enabled();
		$(document.body).trigger('toggleFullWidth');
	},
	set_fullwidth_if_enabled() {
		let fullwidth = JSON.parse(localStorage.container_fullwidth || 'false');
		$(document.body).toggleClass('full-width', fullwidth);
	},
	show_shortcuts (e) {
		e.preventDefault();
		frappe.ui.keys.show_keyboard_shortcut_dialog();
		return false;
	},
});

frappe.ui.toolbar.clear_cache = frappe.utils.throttle(function() {
	frappe.assets.clear_local_storage();
	frappe.xcall('frappe.sessions.clear').then(message => {
		frappe.show_alert({
			message: message,
			indicator: 'info'
		});
		location.reload(true);
	});
}, 10000);

frappe.ui.toolbar.show_about = function() {
	try {
		frappe.ui.misc.about();
	} catch(e) {
		console.log(e);
	}
	return false;
};

frappe.ui.toolbar.route_to_user = function() {
	frappe.set_route('Form', 'User', frappe.session.user);
};

frappe.ui.toolbar.view_website = function() {
	let website_tab = window.open();
	website_tab.opener = null;
	website_tab.location = '/index';
};

frappe.ui.toolbar.setup_session_defaults = function() {
	let fields = [];
	frappe.call({
		method: 'frappe.core.doctype.session_default_settings.session_default_settings.get_session_default_values',
		callback: function (data) {
			fields = JSON.parse(data.message);
			let perms = frappe.perm.get_perm('Session Default Settings');
			//add settings button only if user is a System Manager or has permission on 'Session Default Settings'
			if ((in_list(frappe.user_roles, 'System Manager')) || (perms[0].read == 1))  {
				fields[fields.length] = {
					'fieldname': 'settings',
					'fieldtype': 'Button',
					'label': __('Settings'),
					'click': () => {
						frappe.set_route('Form', 'Session Default Settings', 'Session Default Settings');
					}
				};
			}
			frappe.prompt(fields, function(values) {
				//if default is not set for a particular field in prompt
				fields.forEach(function(d) {
					if (!values[d.fieldname]) {
						values[d.fieldname] = "";
					}
				});
				frappe.call({
					method: 'frappe.core.doctype.session_default_settings.session_default_settings.set_session_default_values',
					args: {
						default_values: values,
					},
					callback: function(data) {
						if (data.message == "success") {
							frappe.show_alert({
								'message': __('Session Defaults Saved'),
								'indicator': 'green'
							});
							frappe.ui.toolbar.clear_cache();
						}	else {
							frappe.show_alert({
								'message': __('An error occurred while setting Session Defaults'),
								'indicator': 'red'
							});
						}
					}
				});
			},
			__('Session Defaults'),
			__('Save'),
			);
		}
	});
};<|endoftext|>


<commit_before>var oauthSignature = (function() {
	'use strict';

	function OAuthSignature() {
	}

	OAuthSignature.prototype.generate = function (httpMethod, url, parameters, tokenSecret, consumerSecret) {
		var signatureBaseString = new SignatureBaseString(httpMethod, url, parameters).generate();
		var signature = new HmacSha1Signature(signatureBaseString, tokenSecret, consumerSecret).generate();
		return signature;
	}

	// Specification: http://oauth.net/core/1.0/#anchor14
	// url: if the scheme is missing, http will be added automatically
	function SignatureBaseString(httpMethod, url, parameters) {
		parameters = new ParametersLoader(parameters).get();
		this._httpMethod = new HttpMethodElement(httpMethod).get();
		this._url = new UrlElement(url).get();
		this._parameters = new ParametersElement(parameters).get();
		this._rfc3986 = new Rfc3986();
	}

	SignatureBaseString.prototype = {
		generate : function () {
			// HTTP_METHOD & url & parameters
			return this._rfc3986.encode(this._httpMethod) + '&'
				+ this._rfc3986.encode(this._url) + '&'
				+ this._rfc3986.encode(this._parameters);
		}
	};

	function HttpMethodElement(httpMethod) {
		this._httpMethod = httpMethod || '';
	}

	HttpMethodElement.prototype = {
		get : function () {
			return this._httpMethod.toUpperCase();
		}
	};

	function UrlElement(url) {
		this._url = url || '';
	}

	UrlElement.prototype = {
		get : function () {
			// The following is to prevent js-url from loading the window.location
			if (!this._url) {
				return this._url;
			}
			var scheme = url('protocol', this._url).toLowerCase(),
				authority = url('hostname', this._url).toLocaleLowerCase(),
				port = url('port', this._url),
				path = url('path', this._url);
			if (this._url.toLowerCase().indexOf(scheme) != 0) {
				scheme = 'http';
			}
			if ((port == 80 && scheme == 'http')
				|| (port == 443 && scheme == 'https'))
			{
				port = '';
			}
			this._url =
				(scheme ? scheme + '://' : '')
					+ authority
					+ (port ? ':' + port : '')
					+ path;
			return this._url;
		}
	};

	function ParametersElement (parameters) {
		this._parameters = parameters; // Format: { 'key': ['value 1', 'value 2'] };
		this._sortedKeys = [ ];
		this._normalizedParameters = [ ];
		this._rfc3986 = new Rfc3986();
		this._sortParameters();
		this._concatenateParameters();
	}

	ParametersElement .prototype = {
		_sortParameters : function () {
			var key;
			for (key in this._parameters) {
				this._sortedKeys.push(key);
			}
			this._sortedKeys.sort();
		},
		_concatenateParameters : function () {
			var i;
			for (i = 0; i < this._sortedKeys.length; i++) {
				this._normalizeParameter(this._sortedKeys[i]);
			}
		},
		_normalizeParameter : function (key) {
			var i,
				values = this._parameters[key],
				encodedKey = this._rfc3986.encode(key),
				encodedValue;
			values.sort();
			for (i = 0; i < values.length; i++) {
				encodedValue = this._rfc3986.encode(values[i]);
				this._normalizedParameters.push(encodedKey + '=' + encodedValue)
			}
		},
		get : function () {
			return this._normalizedParameters.join('&');
		}
	};

	function ParametersLoader (parameters) {
		this._parameters = { }; // Format: { 'key': ['value 1', 'value 2'] }
		this._loadParameters(parameters || { });
	}

	ParametersLoader.prototype = {
		_loadParameters : function (parameters) {
			if (parameters instanceof Array) {
				this._loadParametersFromArray(parameters);
				return;
			}
			if (typeof parameters === 'object') {
				this._loadParametersFromObject(parameters);
			}
		},
		_loadParametersFromArray : function (parameters) {
			var i;
			for (i = 0; i < parameters.length; i++) {
				this._loadParametersFromObject(parameters[i]);
			}
		},
		_loadParametersFromObject : function (parameters) {
			var key;
			for (key in parameters) {
				if (parameters.hasOwnProperty(key)) {
					this._loadParameterValue(key, parameters[key] || '');
				}
			}
		},
		_loadParameterValue : function (key, value) {
			var i;
			if (value instanceof Array) {
				for (i = 0; i < value.length; i++) {
					this._addParameter(key, value[i]);
				}
				if (value.length == 0) {
					this._addParameter(key, '');
				}
			} else {
				this._addParameter(key, value);
			}
		},
		_addParameter : function (key, value) {
			if (!this._parameters[key]) {
				this._parameters[key] = [];
			}
			this._parameters[key].push(value);
		},
		get : function () {
			return this._parameters;
		}
	};

	function Rfc3986() {

	}

	Rfc3986.prototype = {
		encode : function (decoded) {
			if (!decoded) {
				return '';
			}
			// using implementation from: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FencodeURIComponent
			return encodeURIComponent(decoded)
				.replace(/[!'()]/g, escape)
				.replace(/\*/g, "%2A");
		},
		decode : function (encoded) {
			if (!encoded) {
				return '';
			}
			return decodeURIComponent(encoded);
		}
	};

	function HmacSha1Signature(signatureBaseString, consumerSecret, tokenSecret) {
		this._rfc3986 = new Rfc3986();
		this._text = signatureBaseString;
		this._key = this._rfc3986.encode(consumerSecret) + '&' + this._rfc3986.encode(tokenSecret);
		this._base64EncodedHash = new HmacSha1(this._text, this._key).getBase64EncodedHash();
	}

	HmacSha1Signature.prototype = {
		generate : function () {
			return this._rfc3986.encode(this._base64EncodedHash);
		}
	};

	function HmacSha1(text, key) {
		this._text = text || '';
		this._key = key || '';
		this._hash = CryptoJS.HmacSHA1(this._text, this._key);
	}

	HmacSha1.prototype = {
		getBase64EncodedHash : function () {
			return this._hash.toString(CryptoJS.enc.Base64);
		}
	};

	var oauthSignature = new OAuthSignature();
	oauthSignature.SignatureBaseString = SignatureBaseString;
	oauthSignature.HttpMethodElement = HttpMethodElement;
	oauthSignature.UrlElement = UrlElement;
	oauthSignature.ParametersElement = ParametersElement;
	oauthSignature.ParametersLoader = ParametersLoader;
	oauthSignature.Rfc3986 = Rfc3986;
	oauthSignature.HmacSha1Signature = HmacSha1Signature;
	oauthSignature.HmacSha1 = HmacSha1;
	return oauthSignature;
})();<commit_msg>Fixed inverted variable names<commit_after>var oauthSignature = (function() {
	'use strict';

	function OAuthSignature() {
	}

	OAuthSignature.prototype.generate = function (httpMethod, url, parameters, consumerSecret, tokenSecret) {
		var signatureBaseString = new SignatureBaseString(httpMethod, url, parameters).generate();
		return new HmacSha1Signature(signatureBaseString, consumerSecret, tokenSecret).generate();
	}

	// Specification: http://oauth.net/core/1.0/#anchor14
	// url: if the scheme is missing, http will be added automatically
	function SignatureBaseString(httpMethod, url, parameters) {
		parameters = new ParametersLoader(parameters).get();
		this._httpMethod = new HttpMethodElement(httpMethod).get();
		this._url = new UrlElement(url).get();
		this._parameters = new ParametersElement(parameters).get();
		this._rfc3986 = new Rfc3986();
	}

	SignatureBaseString.prototype = {
		generate : function () {
			// HTTP_METHOD & url & parameters
			return this._rfc3986.encode(this._httpMethod) + '&'
				+ this._rfc3986.encode(this._url) + '&'
				+ this._rfc3986.encode(this._parameters);
		}
	};

	function HttpMethodElement(httpMethod) {
		this._httpMethod = httpMethod || '';
	}

	HttpMethodElement.prototype = {
		get : function () {
			return this._httpMethod.toUpperCase();
		}
	};

	function UrlElement(url) {
		this._url = url || '';
	}

	UrlElement.prototype = {
		get : function () {
			// The following is to prevent js-url from loading the window.location
			if (!this._url) {
				return this._url;
			}
			var scheme = url('protocol', this._url).toLowerCase(),
				authority = url('hostname', this._url).toLocaleLowerCase(),
				port = url('port', this._url),
				path = url('path', this._url);
			if (this._url.toLowerCase().indexOf(scheme) != 0) {
				scheme = 'http';
			}
			if ((port == 80 && scheme == 'http')
				|| (port == 443 && scheme == 'https'))
			{
				port = '';
			}
			this._url =
				(scheme ? scheme + '://' : '')
					+ authority
					+ (port ? ':' + port : '')
					+ path;
			return this._url;
		}
	};

	function ParametersElement (parameters) {
		this._parameters = parameters; // Format: { 'key': ['value 1', 'value 2'] };
		this._sortedKeys = [ ];
		this._normalizedParameters = [ ];
		this._rfc3986 = new Rfc3986();
		this._sortParameters();
		this._concatenateParameters();
	}

	ParametersElement .prototype = {
		_sortParameters : function () {
			var key;
			for (key in this._parameters) {
				this._sortedKeys.push(key);
			}
			this._sortedKeys.sort();
		},
		_concatenateParameters : function () {
			var i;
			for (i = 0; i < this._sortedKeys.length; i++) {
				this._normalizeParameter(this._sortedKeys[i]);
			}
		},
		_normalizeParameter : function (key) {
			var i,
				values = this._parameters[key],
				encodedKey = this._rfc3986.encode(key),
				encodedValue;
			values.sort();
			for (i = 0; i < values.length; i++) {
				encodedValue = this._rfc3986.encode(values[i]);
				this._normalizedParameters.push(encodedKey + '=' + encodedValue)
			}
		},
		get : function () {
			return this._normalizedParameters.join('&');
		}
	};

	function ParametersLoader (parameters) {
		this._parameters = { }; // Format: { 'key': ['value 1', 'value 2'] }
		this._loadParameters(parameters || { });
	}

	ParametersLoader.prototype = {
		_loadParameters : function (parameters) {
			if (parameters instanceof Array) {
				this._loadParametersFromArray(parameters);
				return;
			}
			if (typeof parameters === 'object') {
				this._loadParametersFromObject(parameters);
			}
		},
		_loadParametersFromArray : function (parameters) {
			var i;
			for (i = 0; i < parameters.length; i++) {
				this._loadParametersFromObject(parameters[i]);
			}
		},
		_loadParametersFromObject : function (parameters) {
			var key;
			for (key in parameters) {
				if (parameters.hasOwnProperty(key)) {
					this._loadParameterValue(key, parameters[key] || '');
				}
			}
		},
		_loadParameterValue : function (key, value) {
			var i;
			if (value instanceof Array) {
				for (i = 0; i < value.length; i++) {
					this._addParameter(key, value[i]);
				}
				if (value.length == 0) {
					this._addParameter(key, '');
				}
			} else {
				this._addParameter(key, value);
			}
		},
		_addParameter : function (key, value) {
			if (!this._parameters[key]) {
				this._parameters[key] = [];
			}
			this._parameters[key].push(value);
		},
		get : function () {
			return this._parameters;
		}
	};

	function Rfc3986() {

	}

	Rfc3986.prototype = {
		encode : function (decoded) {
			if (!decoded) {
				return '';
			}
			// using implementation from: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FencodeURIComponent
			return encodeURIComponent(decoded)
				.replace(/[!'()]/g, escape)
				.replace(/\*/g, "%2A");
		},
		decode : function (encoded) {
			if (!encoded) {
				return '';
			}
			return decodeURIComponent(encoded);
		}
	};

	function HmacSha1Signature(signatureBaseString, consumerSecret, tokenSecret) {
		this._rfc3986 = new Rfc3986();
		this._text = signatureBaseString;
		this._key = this._rfc3986.encode(consumerSecret) + '&' + this._rfc3986.encode(tokenSecret);
		this._base64EncodedHash = new HmacSha1(this._text, this._key).getBase64EncodedHash();
	}

	HmacSha1Signature.prototype = {
		generate : function () {
			return this._rfc3986.encode(this._base64EncodedHash);
		}
	};

	function HmacSha1(text, key) {
		this._text = text || '';
		this._key = key || '';
		this._hash = CryptoJS.HmacSHA1(this._text, this._key);
	}

	HmacSha1.prototype = {
		getBase64EncodedHash : function () {
			return this._hash.toString(CryptoJS.enc.Base64);
		}
	};

	var oauthSignature = new OAuthSignature();
	oauthSignature.SignatureBaseString = SignatureBaseString;
	oauthSignature.HttpMethodElement = HttpMethodElement;
	oauthSignature.UrlElement = UrlElement;
	oauthSignature.ParametersElement = ParametersElement;
	oauthSignature.ParametersLoader = ParametersLoader;
	oauthSignature.Rfc3986 = Rfc3986;
	oauthSignature.HmacSha1Signature = HmacSha1Signature;
	oauthSignature.HmacSha1 = HmacSha1;
	return oauthSignature;
})();<|endoftext|>