<commit_before>const path = require("path");
const _ = require("lodash");
const webpackLodashPlugin = require("lodash-webpack-plugin");
const moment = require("moment");
const siteConfig = require("./data/SiteConfig");

const postNodes = [];

function addSiblingNodes(createNodeField) {
  postNodes.sort(
    ({ frontmatter: { date: date1 } }, { frontmatter: { date: date2 } }) => {
      const dateA = moment(date1, siteConfig.dateFromFormat);
      const dateB = moment(date2, siteConfig.dateFromFormat);

      if (dateA.isBefore(dateB)) return 1;

      if (dateB.isBefore(dateA)) return -1;

      return 0;
    }
  );
  for (let i = 0; i < postNodes.length; i += 1) {
    const nextID = i + 1 < postNodes.length ? i + 1 : 0;
    const prevID = i - 1 > 0 ? i - 1 : postNodes.length - 1;
    const currNode = postNodes[i];
    const nextNode = postNodes[nextID];
    const prevNode = postNodes[prevID];
    createNodeField({
      node: currNode,
      name: "nextTitle",
      value: nextNode.frontmatter.title
    });
    createNodeField({
      node: currNode,
      name: "nextSlug",
      value: nextNode.fields.slug
    });
    createNodeField({
      node: currNode,
      name: "prevTitle",
      value: prevNode.frontmatter.title
    });
    createNodeField({
      node: currNode,
      name: "prevSlug",
      value: prevNode.fields.slug
    });
  }
}

exports.onCreateNode = ({ node, boundActionCreators, getNode }) => {
  const { createNodeField } = boundActionCreators;
  let slug;
  if (node.internal.type === "MarkdownRemark") {
    const fileNode = getNode(node.parent);
    const parsedFilePath = path.parse(fileNode.relativePath);
    if (
      Object.prototype.hasOwnProperty.call(node, "frontmatter") &&
      Object.prototype.hasOwnProperty.call(node.frontmatter, "title")
    ) {
      slug = `/${_.kebabCase(node.frontmatter.title)}`;
    } else if (parsedFilePath.name !== "index" && parsedFilePath.dir !== "") {
      slug = `/${parsedFilePath.dir}/${parsedFilePath.name}/`;
    } else if (parsedFilePath.dir === "") {
      slug = `/${parsedFilePath.name}/`;
    } else {
      slug = `/${parsedFilePath.dir}/`;
    }

    if (Object.prototype.hasOwnProperty.call(node, "frontmatter")) {
      if (Object.prototype.hasOwnProperty.call(node.frontmatter, "slug"))
        slug = `/${_.kebabCase(node.frontmatter.slug)}`;
      if (Object.prototype.hasOwnProperty.call(node.frontmatter, "date")) {
        const date = moment(node.frontmatter.date, siteConfig.dateFromFormat);
        if (!date.isValid)
          console.warn(`WARNING: Invalid date.`, node.frontmatter);

        createNodeField({
          node,
          name: "date",
          value: date.toISOString()
        });
      }
    }
    createNodeField({ node, name: "slug", value: slug });
    postNodes.push(node);
  }
};

exports.setFieldsOnGraphQLNodeType = ({ type, boundActionCreators }) => {
  const { name } = type;
  const { createNodeField } = boundActionCreators;
  if (name === "MarkdownRemark") {
    addSiblingNodes(createNodeField);
  }
};

exports.createPages = ({ graphql, boundActionCreators }) => {
  const { createPage } = boundActionCreators;

  return new Promise((resolve, reject) => {
    const postPage = path.resolve("src/templates/post.jsx");
    const tagPage = path.resolve("src/templates/tag.jsx");
    const categoryPage = path.resolve("src/templates/category.jsx");
    resolve(
      graphql(
        `
          {
            allMarkdownRemark {
              edges {
                node {
                  frontmatter {
                    tags
                    category
                  }
                  fields {
                    slug
                  }
                }
              }
            }
          }
        `
      ).then(result => {
        if (result.errors) {
          /* eslint no-console: "off" */
          console.log(result.errors);
          reject(result.errors);
        }

        const tagSet = new Set();
        const categorySet = new Set();
        result.data.allMarkdownRemark.edges.forEach(edge => {
          if (edge.node.frontmatter.tags) {
            edge.node.frontmatter.tags.forEach(tag => {
              tagSet.add(tag);
            });
          }

          if (edge.node.frontmatter.category) {
            categorySet.add(edge.node.frontmatter.category);
          }

          createPage({
            path: edge.node.fields.slug,
            component: postPage,
            context: {
              slug: edge.node.fields.slug
            }
          });
        });

        const tagList = Array.from(tagSet);
        tagList.forEach(tag => {
          createPage({
            path: `/tags/${_.kebabCase(tag)}/`,
            component: tagPage,
            context: {
              tag
            }
          });
        });

        const categoryList = Array.from(categorySet);
        categoryList.forEach(category => {
          createPage({
            path: `/categories/${_.kebabCase(category)}/`,
            component: categoryPage,
            context: {
              category
            }
          });
        });
      })
    );
  });
};

exports.modifyWebpackConfig = ({ config, stage }) => {
  if (stage === "build-javascript") {
    config.plugin("Lodash", webpackLodashPlugin, null);
  }
};
<commit_msg>Rename boundActionCreators to actions.<commit_after>const path = require("path");
const _ = require("lodash");
const webpackLodashPlugin = require("lodash-webpack-plugin");
const moment = require("moment");
const siteConfig = require("./data/SiteConfig");

const postNodes = [];

function addSiblingNodes(createNodeField) {
  postNodes.sort(
    ({ frontmatter: { date: date1 } }, { frontmatter: { date: date2 } }) => {
      const dateA = moment(date1, siteConfig.dateFromFormat);
      const dateB = moment(date2, siteConfig.dateFromFormat);

      if (dateA.isBefore(dateB)) return 1;

      if (dateB.isBefore(dateA)) return -1;

      return 0;
    }
  );
  for (let i = 0; i < postNodes.length; i += 1) {
    const nextID = i + 1 < postNodes.length ? i + 1 : 0;
    const prevID = i - 1 > 0 ? i - 1 : postNodes.length - 1;
    const currNode = postNodes[i];
    const nextNode = postNodes[nextID];
    const prevNode = postNodes[prevID];
    createNodeField({
      node: currNode,
      name: "nextTitle",
      value: nextNode.frontmatter.title
    });
    createNodeField({
      node: currNode,
      name: "nextSlug",
      value: nextNode.fields.slug
    });
    createNodeField({
      node: currNode,
      name: "prevTitle",
      value: prevNode.frontmatter.title
    });
    createNodeField({
      node: currNode,
      name: "prevSlug",
      value: prevNode.fields.slug
    });
  }
}

exports.onCreateNode = ({ node, actions, getNode }) => {
  const { createNodeField } = actions;
  let slug;
  if (node.internal.type === "MarkdownRemark") {
    const fileNode = getNode(node.parent);
    const parsedFilePath = path.parse(fileNode.relativePath);
    if (
      Object.prototype.hasOwnProperty.call(node, "frontmatter") &&
      Object.prototype.hasOwnProperty.call(node.frontmatter, "title")
    ) {
      slug = `/${_.kebabCase(node.frontmatter.title)}`;
    } else if (parsedFilePath.name !== "index" && parsedFilePath.dir !== "") {
      slug = `/${parsedFilePath.dir}/${parsedFilePath.name}/`;
    } else if (parsedFilePath.dir === "") {
      slug = `/${parsedFilePath.name}/`;
    } else {
      slug = `/${parsedFilePath.dir}/`;
    }

    if (Object.prototype.hasOwnProperty.call(node, "frontmatter")) {
      if (Object.prototype.hasOwnProperty.call(node.frontmatter, "slug"))
        slug = `/${_.kebabCase(node.frontmatter.slug)}`;
      if (Object.prototype.hasOwnProperty.call(node.frontmatter, "date")) {
        const date = moment(node.frontmatter.date, siteConfig.dateFromFormat);
        if (!date.isValid)
          console.warn(`WARNING: Invalid date.`, node.frontmatter);

        createNodeField({
          node,
          name: "date",
          value: date.toISOString()
        });
      }
    }
    createNodeField({ node, name: "slug", value: slug });
    postNodes.push(node);
  }
};

exports.setFieldsOnGraphQLNodeType = ({ type, actions }) => {
  const { name } = type;
  const { createNodeField } = actions;
  if (name === "MarkdownRemark") {
    addSiblingNodes(createNodeField);
  }
};

exports.createPages = ({ graphql, actions }) => {
  const { createPage } = actions;

  return new Promise((resolve, reject) => {
    const postPage = path.resolve("src/templates/post.jsx");
    const tagPage = path.resolve("src/templates/tag.jsx");
    const categoryPage = path.resolve("src/templates/category.jsx");
    resolve(
      graphql(
        `
          {
            allMarkdownRemark {
              edges {
                node {
                  frontmatter {
                    tags
                    category
                  }
                  fields {
                    slug
                  }
                }
              }
            }
          }
        `
      ).then(result => {
        if (result.errors) {
          /* eslint no-console: "off" */
          console.log(result.errors);
          reject(result.errors);
        }

        const tagSet = new Set();
        const categorySet = new Set();
        result.data.allMarkdownRemark.edges.forEach(edge => {
          if (edge.node.frontmatter.tags) {
            edge.node.frontmatter.tags.forEach(tag => {
              tagSet.add(tag);
            });
          }

          if (edge.node.frontmatter.category) {
            categorySet.add(edge.node.frontmatter.category);
          }

          createPage({
            path: edge.node.fields.slug,
            component: postPage,
            context: {
              slug: edge.node.fields.slug
            }
          });
        });

        const tagList = Array.from(tagSet);
        tagList.forEach(tag => {
          createPage({
            path: `/tags/${_.kebabCase(tag)}/`,
            component: tagPage,
            context: {
              tag
            }
          });
        });

        const categoryList = Array.from(categorySet);
        categoryList.forEach(category => {
          createPage({
            path: `/categories/${_.kebabCase(category)}/`,
            component: categoryPage,
            context: {
              category
            }
          });
        });
      })
    );
  });
};

exports.modifyWebpackConfig = ({ config, stage }) => {
  if (stage === "build-javascript") {
    config.plugin("Lodash", webpackLodashPlugin, null);
  }
};
<|endoftext|>


<commit_before>define(["sugar-web/activity/activity","webL10n","sugar-web/graphics/palette","sugar-web/graphics/presencepalette","sugar-web/datastore","sugar-web/graphics/journalchooser"], function (activity,wl10n, palette,presencepalette,datastore,chooser) {
    var activity = requirejs("sugar-web/activity/activity");

    // Manipulate the DOM only when it is ready.
    requirejs(['domReady!'], function (doc) {

        // Initialize the activity.
		activity.setup();

		var tagBody = '(?:[^"\'>]|"[^"]*"|\'[^\']*\')*';
		//sanitize html messages
		var tagOrComment = new RegExp(
			'<(?:'
			// Comment body.
			+ '!--(?:(?:-*[^->])*--+|-?)'
			// Special "raw text" elements whose content should be elided.
			+ '|script\\b' + tagBody + '>[\\s\\S]*?</script\\s*'
			+ '|style\\b' + tagBody + '>[\\s\\S]*?</style\\s*'
			// Regular name
			+ '|/?[a-z]'
			+ tagBody
			+ ')>',
			'gi');
		function removeTags(html) {
			var oldHtml;
			do {
				oldHtml = html;
				html = html.replace(tagOrComment, '');
			} while (html !== oldHtml);
		return html.replace(/</g, '<');
		}

        var form = document.getElementById('message-form');
        var messageField = document.getElementById('message');
        var messagesList = document.getElementById('messages');
        var socketStatus = document.getElementById('status');
        var messageContent = document.getElementById('content');
        var imageUpload = document.getElementById('image-upload');

	document.getElementById("status").innerHTML = l10n_s.get("status");
	messageField.placeholder = l10n_s.get("WriteYourMessage");

	    var userSettings = null;

		// Connect to network
        var presenceObject;
		function shareActivity() {
			presenceObject = activity.getPresenceObject(function (error, presence) {
				// Unable to join
				if (error)  {
					socketStatus.innerHTML = l10n_s.get('Error');
					socketStatus.className = 'error';
					return;
				}

				// Store settings
				userSettings = presence.getUserInfo();
				socketStatus.innerHTML = l10n_s.get('Connected');
				socketStatus.className = 'open';
				messageField.readOnly = false;

				// Not found, create a new shared activity
				if (!window.top.sugar.environment.sharedId) {
					presence.createSharedActivity('org.sugarlabs.ChatPrototype', function (groupId) {
					});
				}

				// Show a disconnected message when the WebSocket is closed.
				presence.onConnectionClosed(function (event) {
					console.log(l10n_s.get("ConnectionClosed"));
					socketStatus.innerHTML = l10n_s.get('DisconnectedFromWebSocket');
					socketStatus.className = 'closed';
				});

				// Display connection changed
				presence.onSharedActivityUserChanged(function (msg) {
					var userName = msg.user.name.replace('<','<').replace('>','>');
					messagesList.innerHTML += '
' + userName + ' ' + (msg.move>0?l10n_s.get('Join'):l10n_s.get('Leave')) + ' '+l10n_s.get('Chat')+'
';
					imageUpload.style.visibility = "visible";
				});

				// Handle messages received
				presence.onDataReceived(function (msg) {

					if(msg.type=='text'){
						var text = msg.content;
						var author = msg.user.name.replace('<','<').replace('>','>');
						var colour = msg.user.colorvalue;

						var authorElem = '' + author + '';

						myElem = document.createElement('li');
						myElem.class = 'received';
						myElem.style.background = colour.fill;
						myElem.innerHTML = authorElem + text;
						myElem.style.color = colour.stroke;

						messagesList.appendChild(myElem);
						messageContent.scrollTop = messageContent.scrollHeight;
					}
					else if(msg.type == "image"){
						var source = msg.content;
						var author = msg.user.name.replace('<','<').replace('>','>');
						var colour = msg.user.colorvalue;

						var authorElem = '' + author + '';
						myElem = document.createElement('li');
						myElem.class = 'received';
						myElem.style.background = colour.fill;
						myElem.innerHTML = authorElem + "";
						myElem.style.color = colour.stroke;

						messagesList.appendChild(myElem);
						messageContent.scrollTop = messageContent.scrollHeight;

					}
				});
			});
		}

		function senddata(data,mediatype){
			var toSend = {user: userSettings, content: data , type:mediatype};
			presenceObject.sendMessage(presenceObject.getSharedInfo().id, toSend);
		}

		// Create network palette
        var networkButton = document.getElementById("network-button");
		presencepalette = new presencepalette.PresencePalette(networkButton, undefined);
		presencepalette.addEventListener('shared', shareActivity);

		// Launched with a shared id, activity is already shared
		if (window.top.sugar.environment.sharedId) {
			shareActivity();
			presencepalette.setShared(true);
		}

		// Handle message text update
        messageField.onkeydown = function (e) {
            if (e.keyCode === 13) {
				var message = removeTags(messageField.value);
				senddata(message,'text');

				// Send the message through the WebSocket.

                // Clear out the message field
				messageField.placeholder = l10n_s.get("WriteYourMessage");
                messageField.value = "";
				messageField.setSelectionRange(0,0);
				return false;
            }
        };

		imageUpload.addEventListener('click', function (e) {
			chooser.show(function (entry) {
				// No selection
				if (!entry) {
					return;
				}
				// Get object content
				let src;
				var dataentry = new datastore.DatastoreObject(entry.objectId);
				dataentry.loadAsText(function (err, metadata, data) {
					senddata(data,'image');
				});
			}, { mimetype: 'image/png' }, { mimetype: 'image/jpeg' });
		});

	    //Smiley Emoji options
        var selectSmiley = document.getElementById('smiley-button')
        var smileyOption;
        var smileyRange = [
          [128513, 128515], [128517, 128519], [128521, 128528] //Array of happy emojis
        ];

        for (var i = 0; i < smileyRange.length; i++) {
          var range = smileyRange[i];
          for (var x = range[0]; x < range[1]; x++) {

            smileyOption = document.createElement('option');
            smileyOption.value = x;
            smileyOption.innerHTML = "&#" + x + ";";
            selectSmiley.appendChild(smileyOption);
          }

        }

        //Sad Emoji options
          var selectSad = document.getElementById('sad-button')
          var sadOption;
          var sadRange = [
            [128531, 128533], [128545, 128551], [128555, 128558] //Array of sad or upset emojis
          ];

          for (var i = 0; i < sadRange.length; i++) {
            var range = sadRange[i];
            for (var x = range[0]; x < range[1]; x++) {

              sadOption = document.createElement('option');
              sadOption.value = x;
              sadOption.innerHTML = "&#" + x + ";";
              selectSad.appendChild(sadOption);
            }

          }

          //Others Emoji options
            var selectOthers = document.getElementById('others-button')
            var otherOption;
            var otherRange = [
              [128568, 128573], [128582, 128588] //Array of other emojis
            ];

            for (var i = 0; i < otherRange.length; i++) {
              var range = otherRange[i];
              for (var x = range[0]; x < range[1]; x++) {

                otherOption = document.createElement('option');
                otherOption.value = x;
                otherOption.innerHTML = "&#" + x + ";";
                selectOthers.appendChild(otherOption);
              }

            }
    });

});
<commit_msg>Integrated older versions<commit_after>define(["sugar-web/activity/activity","webL10n","sugar-web/graphics/palette","sugar-web/graphics/presencepalette","sugar-web/datastore","sugar-web/graphics/journalchooser"], function (activity,wl10n, palette,presencepalette,datastore,chooser) {
    var activity = requirejs("sugar-web/activity/activity");

    // Manipulate the DOM only when it is ready.
    requirejs(['domReady!'], function (doc) {

        // Initialize the activity.
		activity.setup();

		var tagBody = '(?:[^"\'>]|"[^"]*"|\'[^\']*\')*';
		//sanitize html messages
		var tagOrComment = new RegExp(
			'<(?:'
			// Comment body.
			+ '!--(?:(?:-*[^->])*--+|-?)'
			// Special "raw text" elements whose content should be elided.
			+ '|script\\b' + tagBody + '>[\\s\\S]*?</script\\s*'
			+ '|style\\b' + tagBody + '>[\\s\\S]*?</style\\s*'
			// Regular name
			+ '|/?[a-z]'
			+ tagBody
			+ ')>',
			'gi');
		function removeTags(html) {
			var oldHtml;
			do {
				oldHtml = html;
				html = html.replace(tagOrComment, '');
			} while (html !== oldHtml);
		return html.replace(/</g, '<');
		}

        var form = document.getElementById('message-form');
        var messageField = document.getElementById('message');
        var messagesList = document.getElementById('messages');
        var socketStatus = document.getElementById('status');
        var messageContent = document.getElementById('content');
        var imageUpload = document.getElementById('image-upload');

	document.getElementById("status").innerHTML = l10n_s.get("status");
	messageField.placeholder = l10n_s.get("WriteYourMessage");

	    var userSettings = null;

		// Connect to network
        var presenceObject;
		function shareActivity() {
			presenceObject = activity.getPresenceObject(function (error, presence) {
				// Unable to join
				if (error)  {
					socketStatus.innerHTML = l10n_s.get('Error');
					socketStatus.className = 'error';
					return;
				}

				// Store settings
				userSettings = presence.getUserInfo();
				socketStatus.innerHTML = l10n_s.get('Connected');
				socketStatus.className = 'open';
				messageField.readOnly = false;

				// Not found, create a new shared activity
				if (!window.top.sugar.environment.sharedId) {
					presence.createSharedActivity('org.sugarlabs.ChatPrototype', function (groupId) {
					});
				}

				// Show a disconnected message when the WebSocket is closed.
				presence.onConnectionClosed(function (event) {
					console.log(l10n_s.get("ConnectionClosed"));
					socketStatus.innerHTML = l10n_s.get('DisconnectedFromWebSocket');
					socketStatus.className = 'closed';
				});

				// Display connection changed
				presence.onSharedActivityUserChanged(function (msg) {
					var userName = msg.user.name.replace('<','<').replace('>','>');
					messagesList.innerHTML += '
' + userName + ' ' + (msg.move>0?l10n_s.get('Join'):l10n_s.get('Leave')) + ' '+l10n_s.get('Chat')+'
';
					imageUpload.style.visibility = "visible";
				});

				// Handle messages received
				presence.onDataReceived(function (msg) {

					if(msg.type=='text' || typeof(msg.type) == 'undefined'){
						var text = msg.content;
						var author = msg.user.name.replace('<','<').replace('>','>');
						var colour = msg.user.colorvalue;

						var authorElem = '' + author + '';

						myElem = document.createElement('li');
						myElem.class = 'received';
						myElem.style.background = colour.fill;
						myElem.innerHTML = authorElem + text;
						myElem.style.color = colour.stroke;

						messagesList.appendChild(myElem);
						messageContent.scrollTop = messageContent.scrollHeight;
					}
					else if(msg.type == "image"){
						var source = msg.content;
						var author = msg.user.name.replace('<','<').replace('>','>');
						var colour = msg.user.colorvalue;

						var authorElem = '' + author + '';
						myElem = document.createElement('li');
						myElem.class = 'received';
						myElem.style.background = colour.fill;
						myElem.innerHTML = authorElem + "";
						myElem.style.color = colour.stroke;

						messagesList.appendChild(myElem);
						messageContent.scrollTop = messageContent.scrollHeight;

					}
				});
			});
		}

		function senddata(data,mediatype){
			var toSend = {user: userSettings, content: data , type:mediatype};
			presenceObject.sendMessage(presenceObject.getSharedInfo().id, toSend);
		}

		// Create network palette
        var networkButton = document.getElementById("network-button");
		presencepalette = new presencepalette.PresencePalette(networkButton, undefined);
		presencepalette.addEventListener('shared', shareActivity);

		// Launched with a shared id, activity is already shared
		if (window.top.sugar.environment.sharedId) {
			shareActivity();
			presencepalette.setShared(true);
		}

		// Handle message text update
        messageField.onkeydown = function (e) {
            if (e.keyCode === 13) {
				var message = removeTags(messageField.value);
				senddata(message,'text');

				// Send the message through the WebSocket.

                // Clear out the message field
				messageField.placeholder = l10n_s.get("WriteYourMessage");
                messageField.value = "";
				messageField.setSelectionRange(0,0);
				return false;
            }
        };

		imageUpload.addEventListener('click', function (e) {
			chooser.show(function (entry) {
				// No selection
				if (!entry) {
					return;
				}
				// Get object content
				let src;
				var dataentry = new datastore.DatastoreObject(entry.objectId);
				dataentry.loadAsText(function (err, metadata, data) {
					senddata(data,'image');
				});
			}, { mimetype: 'image/png' }, { mimetype: 'image/jpeg' });
		});

	    //Smiley Emoji options
        var selectSmiley = document.getElementById('smiley-button')
        var smileyOption;
        var smileyRange = [
          [128513, 128515], [128517, 128519], [128521, 128528] //Array of happy emojis
        ];

        for (var i = 0; i < smileyRange.length; i++) {
          var range = smileyRange[i];
          for (var x = range[0]; x < range[1]; x++) {

            smileyOption = document.createElement('option');
            smileyOption.value = x;
            smileyOption.innerHTML = "&#" + x + ";";
            selectSmiley.appendChild(smileyOption);
          }

        }

        //Sad Emoji options
          var selectSad = document.getElementById('sad-button')
          var sadOption;
          var sadRange = [
            [128531, 128533], [128545, 128551], [128555, 128558] //Array of sad or upset emojis
          ];

          for (var i = 0; i < sadRange.length; i++) {
            var range = sadRange[i];
            for (var x = range[0]; x < range[1]; x++) {

              sadOption = document.createElement('option');
              sadOption.value = x;
              sadOption.innerHTML = "&#" + x + ";";
              selectSad.appendChild(sadOption);
            }

          }

          //Others Emoji options
            var selectOthers = document.getElementById('others-button')
            var otherOption;
            var otherRange = [
              [128568, 128573], [128582, 128588] //Array of other emojis
            ];

            for (var i = 0; i < otherRange.length; i++) {
              var range = otherRange[i];
              for (var x = range[0]; x < range[1]; x++) {

                otherOption = document.createElement('option');
                otherOption.value = x;
                otherOption.innerHTML = "&#" + x + ";";
                selectOthers.appendChild(otherOption);
              }

            }
    });

});
<|endoftext|>


<commit_before>'use strict';

var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();

Object.defineProperty(exports, "__esModule", {
    value: true
});
exports.parseText = exports.parseFile = exports.parseStream = exports.GCodeParser = undefined;

var _lodash = require('lodash');

var _lodash2 = _interopRequireDefault(_lodash);

var _fs = require('fs');

var _fs2 = _interopRequireDefault(_fs);

var _stream = require('stream');

var _stream2 = _interopRequireDefault(_stream);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

var streamify = function streamify(text) {
    var s = new _stream2.default.Readable();
    s.push(text);
    s.push(null);
    return s;
};

var stripComments = function stripComments(s) {
    var re1 = /^\s+|\s+$/g; // Strip leading and trailing spaces
    var re2 = /\s*[#;].*$/g; // Strip everything after # or ; to the end of the line, including preceding spaces
    return s.replace(re1, '').replace(re2, '');
};

var removeSpaces = function removeSpaces(s) {
    return s.replace(/\s+/g, '');
};

var GCodeParser = (function (_Transform) {
    _inherits(GCodeParser, _Transform);

    function GCodeParser(options) {
        _classCallCheck(this, GCodeParser);

        var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(GCodeParser).call(this, _lodash2.default.extend({}, options, { objectMode: true })));

        _this.options = options || {};
        return _this;
    }

    _createClass(GCodeParser, [{
        key: '_transform',
        value: function _transform(chunk, encoding, next) {
            var _this2 = this;

            // decode binary chunks as UTF-8
            encoding = encoding || 'utf8';

            if (Buffer.isBuffer(chunk)) {
                if (encoding === 'buffer') {
                    encoding = 'utf8';
                }
                chunk = chunk.toString(encoding);
            }

            var lines = chunk.split(/\r\n|\r|\n/g);
            _lodash2.default.each(lines, function (line) {
                line = _lodash2.default.trim(stripComments(line));
                if (line.length === 0) {
                    return;
                }

                var n = undefined;
                var words = [];
                var list = removeSpaces(line).match(/([a-zA-Z][^a-zA-Z]*)/igm) || [];
                _lodash2.default.each(list, function (word) {
                    var r = word.match(/([a-zA-Z])([^a-zA-Z]*)/) || [];
                    var letter = (r[1] || '').toUpperCase();
                    var argument = _lodash2.default.isNaN(parseFloat(r[2])) ? r[2] : Number(r[2]);

                    if (letter === 'N' && typeof n === 'undefined') {
                        // Line (block) number in program
                        n = Number(argument);
                        return;
                    }

                    words.push([letter, argument]);
                });

                _this2.push({
                    line: line,
                    N: n,
                    words: words
                });
            });

            next();
        }
    }, {
        key: '_flush',
        value: function _flush(done) {
            done();
        }
    }]);

    return GCodeParser;
})(_stream.Transform);

var parseStream = function parseStream(stream, callback) {
    callback = callback || function (err) {};

    try {
        (function () {
            var results = [];
            stream.pipe(new GCodeParser()).on('data', function (data) {
                results.push(data);
            }).on('end', function () {
                callback(null, results);
            }).on('error', callback);
        })();
    } catch (err) {
        callback(err);
        return;
    }

    return stream;
};

var parseFile = function parseFile(file, callback) {
    file = file || '';
    var s = _fs2.default.createReadStream(file, { encoding: 'utf8' });
    s.on('error', callback);
    return parseStream(s, callback);
};

var parseText = function parseText(text, callback) {
    var s = streamify(text);
    return parseStream(s, callback);
};

exports.GCodeParser = GCodeParser;
exports.parseStream = parseStream;
exports.parseFile = parseFile;
exports.parseText = parseText;<commit_msg>Supports special fields<commit_after>'use strict';

var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();

Object.defineProperty(exports, "__esModule", {
    value: true
});
exports.parseText = exports.parseFile = exports.parseStream = exports.GCodeParser = undefined;

var _lodash = require('lodash');

var _lodash2 = _interopRequireDefault(_lodash);

var _fs = require('fs');

var _fs2 = _interopRequireDefault(_fs);

var _stream = require('stream');

var _stream2 = _interopRequireDefault(_stream);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

var streamify = function streamify(text) {
    var s = new _stream2.default.Readable();
    s.push(text);
    s.push(null);
    return s;
};

var stripComments = function stripComments(s) {
    var re1 = /^\s+|\s+$/g; // Strip leading and trailing spaces
    var re2 = /\s*[#;].*$/g; // Strip everything after # or ; to the end of the line, including preceding spaces
    return s.replace(re1, '').replace(re2, '');
};

var removeSpaces = function removeSpaces(s) {
    return s.replace(/\s+/g, '');
};

var GCodeParser = (function (_Transform) {
    _inherits(GCodeParser, _Transform);

    function GCodeParser(options) {
        _classCallCheck(this, GCodeParser);

        var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(GCodeParser).call(this, _lodash2.default.extend({}, options, { objectMode: true })));

        _this.options = options || {};
        return _this;
    }

    _createClass(GCodeParser, [{
        key: '_transform',
        value: function _transform(chunk, encoding, next) {
            var _this2 = this;

            // decode binary chunks as UTF-8
            encoding = encoding || 'utf8';

            if (Buffer.isBuffer(chunk)) {
                if (encoding === 'buffer') {
                    encoding = 'utf8';
                }
                chunk = chunk.toString(encoding);
            }

            var lines = chunk.split(/\r\n|\r|\n/g);
            _lodash2.default.each(lines, function (line) {
                line = _lodash2.default.trim(stripComments(line));
                if (line.length === 0) {
                    return;
                }

                var n = undefined;
                var checksum = undefined;
                var words = [];
                var list = removeSpaces(line).match(/([a-zA-Z][0-9\+\-\.]*)|(\*[0-9]+)/igm) || [];

                _lodash2.default.each(list, function (word) {
                    var letter = word[0].toUpperCase();
                    var argument = word.substr(1);

                    argument = _lodash2.default.isNaN(parseFloat(argument)) ? argument : Number(argument);

                    //
                    // Special fields
                    //

                    {
                        // N: Line number
                        if (letter === 'N' && _lodash2.default.isUndefined(n)) {
                            // Line (block) number in program
                            n = Number(argument);
                            return;
                        }
                    }

                    {
                        // *: Checksum
                        if (letter === '*' && _lodash2.default.isUndefined(checksum)) {
                            checksum = Number(argument);
                            return;
                        }
                    }

                    words.push([letter, argument]);
                });

                var obj = {};
                obj.line = line;
                obj.words = words;
                typeof n !== 'undefined' && (obj.N = n); // N: Line number
                typeof checksum !== 'undefined' && (obj.checksum = checksum); // *: Checksum

                _this2.push(obj);
            });

            next();
        }
    }, {
        key: '_flush',
        value: function _flush(done) {
            done();
        }
    }]);

    return GCodeParser;
})(_stream.Transform);

var parseStream = function parseStream(stream, callback) {
    callback = callback || function (err) {};

    try {
        (function () {
            var results = [];
            stream.pipe(new GCodeParser()).on('data', function (data) {
                results.push(data);
            }).on('end', function () {
                callback(null, results);
            }).on('error', callback);
        })();
    } catch (err) {
        callback(err);
        return;
    }

    return stream;
};

var parseFile = function parseFile(file, callback) {
    file = file || '';
    var s = _fs2.default.createReadStream(file, { encoding: 'utf8' });
    s.on('error', callback);
    return parseStream(s, callback);
};

var parseText = function parseText(text, callback) {
    var s = streamify(text);
    return parseStream(s, callback);
};

exports.GCodeParser = GCodeParser;
exports.parseStream = parseStream;
exports.parseFile = parseFile;
exports.parseText = parseText;<|endoftext|>


<commit_before>var ECO = ECO || {};

ECO.endpoints = {
  search: 'https://dev-ecoengine.berkeley.edu/api/search/',
  observations: 'https://dev-ecoengine.berkeley.edu/api/observations/',
  photos: 'https://dev-ecoengine.berkeley.edu/api/photos/',
  sensors: 'https://dev-ecoengine.berkeley.edu/api/sensors/?page_size=5000&format=geojson',
  layers: 'https://dev-ecoengine.berkeley.edu/api/layers/',
  rasters: '/static/js/stamen/rstore.json',
  reserves: 'https://dev-ecoengine.berkeley.edu/api/layers/reserves/features/?page_size=500',
  jepson: 'https://dev-ecoengine.berkeley.edu/api/layers/jepson-regions/features/?page_size=500'
};

ECO.basemaps = {
  'Light': {
    'url': 'http://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png',
    'attribution': 'Map tiles by CartoDB, under CC BY 3.0. Data by OpenStreetMap, under ODbL.'
  },
  'Dark': {
    'url': 'http://{s}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}.png',
    'attribution': 'Map tiles by CartoDB, under CC BY 3.0. Data by OpenStreetMap, under ODbL.'
  },
  'OpenStreetMap': {
    'url': 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
    'attribution': '© OpenStreetMap contributors'
  },
  'Stamen Terrain': {
    'url': 'http://{s}.tile.stamen.com/terrain-background/{z}/{x}/{y}.jpg',
    'attribution': 'Map tiles by Stamen Design, under CC BY 3.0. Data by OpenStreetMap, under CC BY SA.'
  }
};

ECO.advancedSearch = [
  {
    'section': 'Unique Identifier (Observations)',
    'fields': [
      {
        'field': 'catalog_number__exact',
        'type': 'text'
      },
      {
        'field': 'collection_code',
        'type': 'text'
      },
      {
        'field': 'institution_code',
        'type': 'text'
      }
    ]
  },
  {
    'section': 'Higher Geography',
    'fields': [
      {
        'field': 'country',
        'type': 'text'
      },
      {
        'field': 'state_province',
        'type': 'text'
      },
      {
        'field': 'county',
        'type': 'text'
      },
      {
        'field': 'locality',
        'type': 'text'
      },
    ]
  },
  /*
  {
    'section': 'Time',
    'fields': [
      {
        'field': 'begin_date',
        'type': 'text',
        'placeholder': '1920-01-01'
      },
      {
        'field': 'end_date',
        'type': 'text',
        'placeholder': '2010-11-25'
      }
    ]
  },
  */
  {
    'section': 'Geologic Strata',
    'fields': [
      {
        'field': 'earliest_period_or_lowest_system',
        'type': 'text'
      },
      {
        'field': 'latest_period_or_highest_system',
        'type': 'text'
      },
      {
        'field': 'maximum_depth_in_meters',
        'type': 'text'
      },
      {
        'field': 'minimum_depth_in_meters',
        'type': 'text'
      }
    ]
  },
  {
    'section': 'Taxonomy',
    'fields': [
      {
        'field': 'kingdom',
        'type': 'text'
      },
      {
        'field': 'phylum',
        'type': 'text'
      },
      {
        'field': 'clss',
        'type': 'text'
      },
      {
        'field': 'order',
        'type': 'text'
      },
      {
        'field': 'family',
        'type': 'text'
      },
      {
        'field': 'genus',
        'type': 'text'
      },
      {
        'field': 'specific_epithet',
        'type': 'text'
      },
      {
        'field': 'infraspecific_epithet',
        'alias': 'subspecies',
        'type': 'text'
      },
      {
        'field': 'scientific_name',
        'type': 'text'
      }
    ]
  },
  /*
  {
    'section': 'Metadata',
    'fields': [
      {
        'field': 'authors',
        'field': 'photographer',
        'type': 'text'
      }
    ]
  }
  */
];
<commit_msg>raster fix<commit_after>var ECO = ECO || {};

ECO.endpoints = {
  search: 'https://dev-ecoengine.berkeley.edu/api/search/',
  observations: 'https://dev-ecoengine.berkeley.edu/api/observations/',
  photos: 'https://dev-ecoengine.berkeley.edu/api/photos/',
  sensors: 'https://dev-ecoengine.berkeley.edu/api/sensors/?page_size=5000&format=geojson',
  layers: 'https://dev-ecoengine.berkeley.edu/api/layers/',
  rasters: '..//static/js/stamen/rstore.json',
  reserves: 'https://dev-ecoengine.berkeley.edu/api/layers/reserves/features/?page_size=500',
  jepson: 'https://dev-ecoengine.berkeley.edu/api/layers/jepson-regions/features/?page_size=500'
};

ECO.basemaps = {
  'Light': {
    'url': 'http://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png',
    'attribution': 'Map tiles by CartoDB, under CC BY 3.0. Data by OpenStreetMap, under ODbL.'
  },
  'Dark': {
    'url': 'http://{s}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}.png',
    'attribution': 'Map tiles by CartoDB, under CC BY 3.0. Data by OpenStreetMap, under ODbL.'
  },
  'OpenStreetMap': {
    'url': 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
    'attribution': '© OpenStreetMap contributors'
  },
  'Stamen Terrain': {
    'url': 'http://{s}.tile.stamen.com/terrain-background/{z}/{x}/{y}.jpg',
    'attribution': 'Map tiles by Stamen Design, under CC BY 3.0. Data by OpenStreetMap, under CC BY SA.'
  }
};

ECO.advancedSearch = [
  {
    'section': 'Unique Identifier (Observations)',
    'fields': [
      {
        'field': 'catalog_number__exact',
        'type': 'text'
      },
      {
        'field': 'collection_code',
        'type': 'text'
      },
      {
        'field': 'institution_code',
        'type': 'text'
      }
    ]
  },
  {
    'section': 'Higher Geography',
    'fields': [
      {
        'field': 'country',
        'type': 'text'
      },
      {
        'field': 'state_province',
        'type': 'text'
      },
      {
        'field': 'county',
        'type': 'text'
      },
      {
        'field': 'locality',
        'type': 'text'
      },
    ]
  },
  /*
  {
    'section': 'Time',
    'fields': [
      {
        'field': 'begin_date',
        'type': 'text',
        'placeholder': '1920-01-01'
      },
      {
        'field': 'end_date',
        'type': 'text',
        'placeholder': '2010-11-25'
      }
    ]
  },
  */
  {
    'section': 'Geologic Strata',
    'fields': [
      {
        'field': 'earliest_period_or_lowest_system',
        'type': 'text'
      },
      {
        'field': 'latest_period_or_highest_system',
        'type': 'text'
      },
      {
        'field': 'maximum_depth_in_meters',
        'type': 'text'
      },
      {
        'field': 'minimum_depth_in_meters',
        'type': 'text'
      }
    ]
  },
  {
    'section': 'Taxonomy',
    'fields': [
      {
        'field': 'kingdom',
        'type': 'text'
      },
      {
        'field': 'phylum',
        'type': 'text'
      },
      {
        'field': 'clss',
        'type': 'text'
      },
      {
        'field': 'order',
        'type': 'text'
      },
      {
        'field': 'family',
        'type': 'text'
      },
      {
        'field': 'genus',
        'type': 'text'
      },
      {
        'field': 'specific_epithet',
        'type': 'text'
      },
      {
        'field': 'infraspecific_epithet',
        'alias': 'subspecies',
        'type': 'text'
      },
      {
        'field': 'scientific_name',
        'type': 'text'
      }
    ]
  },
  /*
  {
    'section': 'Metadata',
    'fields': [
      {
        'field': 'authors',
        'field': 'photographer',
        'type': 'text'
      }
    ]
  }
  */
];
<|endoftext|>


<commit_before>import "@fullcalendar/core/main.css"
import dayGridPlugin from "@fullcalendar/daygrid"
import "@fullcalendar/daygrid/main.css"
import FullCalendar from "@fullcalendar/react"
import BarChart from "components/BarChart"
import LikertScale from "components/graphs/LikertScale"
import Pie from "components/graphs/Pie"
import Leaflet from "components/Leaflet"
import _escape from "lodash/escape"
import _isEmpty from "lodash/isEmpty"
import _uniqueId from "lodash/uniqueId"
import { Location } from "models"
import { AssessmentPeriodPropType, PeriodPropType } from "periodUtils"
import PropTypes from "prop-types"
import React, { useMemo, useRef, useState } from "react"
import { Button, Collapse, Table } from "react-bootstrap"
import utils from "utils"

const DATE_FORMAT = "YYYY-MM-DD"

const aggregationWidgetPropTypes = {
  values: PropTypes.oneOfType([
    PropTypes.object,
    PropTypes.arrayOf(
      PropTypes.oneOfType([
        PropTypes.string,
        PropTypes.number,
        PropTypes.array,
        PropTypes.object
      ])
    )
  ]),
  fieldConfig: PropTypes.object,
  fieldName: PropTypes.string,
  vertical: PropTypes.bool,
  period: PropTypes.oneOfType([AssessmentPeriodPropType, PeriodPropType]),
  whenUnspecified: PropTypes.oneOfType([PropTypes.string, PropTypes.object])
}

export const PieWidget = ({
  values,
  entitiesCount,
  legend,
  showLegend = true,
  ...otherWidgetProps
}) => {
  return (
    <>
      <Pie
        width={70}
        height={70}
        data={values}
        label={entitiesCount}
        segmentFill={entity => legend[entity.data.key]?.color}
        segmentLabel={d => d.data.value}
      />
      {showLegend && (
        <>

          {Object.map(legend, (key, choice) => (
            <React.Fragment key={key}>

                {choice.label}{" "}

            </React.Fragment>
          ))}
        </>
      )}
    </>
  )
}
PieWidget.propTypes = {
  entitiesCount: PropTypes.number,
  legend: PropTypes.object,
  showLegend: PropTypes.bool,
  ...aggregationWidgetPropTypes
}

export const LikertScaleAndPieWidget = ({ values, ...otherWidgetProps }) => {
  const { likertScaleValues, pieValues } = values
  return (

        <PieWidget {...pieValues} {...otherWidgetProps} showLegend={false} />

      {!_isEmpty(likertScaleValues) && (

          <LikertScale
            {...likertScaleValues}
            {...otherWidgetProps}
            whenUnspecified=""
          />

      )}

  )
}
LikertScaleAndPieWidget.propTypes = aggregationWidgetPropTypes

export const ReportsByTaskWidget = ({ values, ...otherWidgetProps }) => (

    <BarChart
      chartId={_uniqueId("ReportsByTaskWidget")}
      data={values}
      xProp="task.uuid"
      yProp="reportsCount"
      xLabel="task.shortName"
      tooltip={d => `

${d.task.shortName}

${d.reportsCount}

    `}
    />

)
ReportsByTaskWidget.propTypes = aggregationWidgetPropTypes

export const CalendarWidget = ({
  values,
  fieldConfig,
  fieldName,
  period,
  whenUnspecified,
  ...otherWidgetProps
}) => {
  const calendarComponentRef = useRef(null)
  const events = Object.entries(Object.without(values, null)).map(
    ([key, value]) => {
      return {
        title: `${value} events`,
        start: key,
        end: key
      }
    }
  )
  if (_isEmpty(events)) {
    return whenUnspecified
  }
  return (
    <FullCalendar
      plugins={[dayGridPlugin]}
      header={{
        left: "prev,next",
        center: "title",
        right: ""
      }}
      defaultView="dayGridMonth"
      defaultDate={period.start.format(DATE_FORMAT)}
      allDayDefault
      eventTimeFormat={{
        hour: "2-digit",
        minute: "2-digit",
        meridiem: false,
        omitZeroMinute: false,
        hour12: false
      }}
      slotLabelFormat={{
        hour: "2-digit",
        minute: "2-digit",
        meridiem: false,
        omitZeroMinute: false,
        hour12: false
      }}
      height="auto" // assume a natural height, no scrollbars will be used
      aspectRatio={3} // ratio of width-to-height
      ref={calendarComponentRef}
      events={events}
      eventOverlap
      eventLimit
    />
  )
}
CalendarWidget.propTypes = aggregationWidgetPropTypes

export const DefaultAggWidget = ({
  values,
  whenUnspecified,
  ...otherWidgetProps
}) => {
  const [showValues, setShowValues] = useState(false)
  const filteredValues = values.filter(value => !utils.isNullOrUndefined(value))
  if (_isEmpty(filteredValues)) {
    return whenUnspecified
  }
  return (

      <Button
        className="toggle-section-button"
        style={{ marginBottom: "1rem" }}
        onClick={toggleShowValues}
        id="toggleShowValues"
      >
        {showValues ? "Hide" : "Show"} {filteredValues.length} values
      </Button>
      <Collapse in={showValues}>

            {filteredValues.map(val => {
              const keyValue = _uniqueId("value_")
              return (

                  {val}

              )
            })}

      </Collapse>

  )
  function toggleShowValues() {
    setShowValues(!showValues)
  }
}
DefaultAggWidget.propTypes = aggregationWidgetPropTypes

export const ReportsMapWidget = ({
  values,
  mapId,
  width,
  height,
  whenUnspecified,
  ...otherWidgetProps
}) => {
  const markers = useMemo(() => {
    if (!values.length) {
      return []
    }
    const markerArray = []
    values.forEach(report => {
      if (Location.hasCoordinates(report.location)) {
        let label = _escape(report.intent || "<undefined>") // escape HTML in intent!
        label += `<br/>@ <b>${_escape(report.location.name)}</b>` // escape HTML in locationName!
        markerArray.push({
          id: report.uuid,
          lat: report.location.lat,
          lng: report.location.lng,
          name: label
        })
      }
    })
    return markerArray
  }, [values])
  if (_isEmpty(markers)) {
    return whenUnspecified
  }
  return (

      <Leaflet
        markers={markers}
        width={width}
        height={height}
        mapId={mapId}
        marginBottom={0}
      />

  )
}
ReportsMapWidget.propTypes = {
  ...aggregationWidgetPropTypes,
  mapId: PropTypes.string,
  width: PropTypes.number,
  height: PropTypes.number
}
ReportsMapWidget.defaultProps = {
  values: []
}
<commit_msg>NCI-Agency/anet#2954: Remove prev/next from aggregation calendar widget<commit_after>import "@fullcalendar/core/main.css"
import dayGridPlugin from "@fullcalendar/daygrid"
import "@fullcalendar/daygrid/main.css"
import FullCalendar from "@fullcalendar/react"
import BarChart from "components/BarChart"
import LikertScale from "components/graphs/LikertScale"
import Pie from "components/graphs/Pie"
import Leaflet from "components/Leaflet"
import _escape from "lodash/escape"
import _isEmpty from "lodash/isEmpty"
import _uniqueId from "lodash/uniqueId"
import { Location } from "models"
import { AssessmentPeriodPropType, PeriodPropType } from "periodUtils"
import PropTypes from "prop-types"
import React, { useMemo, useRef, useState } from "react"
import { Button, Collapse, Table } from "react-bootstrap"
import utils from "utils"

const DATE_FORMAT = "YYYY-MM-DD"

const aggregationWidgetPropTypes = {
  values: PropTypes.oneOfType([
    PropTypes.object,
    PropTypes.arrayOf(
      PropTypes.oneOfType([
        PropTypes.string,
        PropTypes.number,
        PropTypes.array,
        PropTypes.object
      ])
    )
  ]),
  fieldConfig: PropTypes.object,
  fieldName: PropTypes.string,
  vertical: PropTypes.bool,
  period: PropTypes.oneOfType([AssessmentPeriodPropType, PeriodPropType]),
  whenUnspecified: PropTypes.oneOfType([PropTypes.string, PropTypes.object])
}

export const PieWidget = ({
  values,
  entitiesCount,
  legend,
  showLegend = true,
  ...otherWidgetProps
}) => {
  return (
    <>
      <Pie
        width={70}
        height={70}
        data={values}
        label={entitiesCount}
        segmentFill={entity => legend[entity.data.key]?.color}
        segmentLabel={d => d.data.value}
      />
      {showLegend && (
        <>

          {Object.map(legend, (key, choice) => (
            <React.Fragment key={key}>

                {choice.label}{" "}

            </React.Fragment>
          ))}
        </>
      )}
    </>
  )
}
PieWidget.propTypes = {
  entitiesCount: PropTypes.number,
  legend: PropTypes.object,
  showLegend: PropTypes.bool,
  ...aggregationWidgetPropTypes
}

export const LikertScaleAndPieWidget = ({ values, ...otherWidgetProps }) => {
  const { likertScaleValues, pieValues } = values
  return (

        <PieWidget {...pieValues} {...otherWidgetProps} showLegend={false} />

      {!_isEmpty(likertScaleValues) && (

          <LikertScale
            {...likertScaleValues}
            {...otherWidgetProps}
            whenUnspecified=""
          />

      )}

  )
}
LikertScaleAndPieWidget.propTypes = aggregationWidgetPropTypes

export const ReportsByTaskWidget = ({ values, ...otherWidgetProps }) => (

    <BarChart
      chartId={_uniqueId("ReportsByTaskWidget")}
      data={values}
      xProp="task.uuid"
      yProp="reportsCount"
      xLabel="task.shortName"
      tooltip={d => `

${d.task.shortName}

${d.reportsCount}

    `}
    />

)
ReportsByTaskWidget.propTypes = aggregationWidgetPropTypes

export const CalendarWidget = ({
  values,
  fieldConfig,
  fieldName,
  period,
  whenUnspecified,
  hasPrevNext = false,
  ...otherWidgetProps
}) => {
  const calendarComponentRef = useRef(null)
  const events = Object.entries(Object.without(values, null)).map(
    ([key, value]) => {
      return {
        title: `${value} events`,
        start: key,
        end: key
      }
    }
  )
  if (_isEmpty(events)) {
    return whenUnspecified
  }
  return (
    <FullCalendar
      plugins={[dayGridPlugin]}
      header={{
        left: hasPrevNext ? "prev,next" : "",
        center: "title",
        right: ""
      }}
      defaultView="dayGridMonth"
      defaultDate={period.start.format(DATE_FORMAT)}
      allDayDefault
      eventTimeFormat={{
        hour: "2-digit",
        minute: "2-digit",
        meridiem: false,
        omitZeroMinute: false,
        hour12: false
      }}
      slotLabelFormat={{
        hour: "2-digit",
        minute: "2-digit",
        meridiem: false,
        omitZeroMinute: false,
        hour12: false
      }}
      height="auto" // assume a natural height, no scrollbars will be used
      aspectRatio={3} // ratio of width-to-height
      ref={calendarComponentRef}
      events={events}
      eventOverlap
      eventLimit
    />
  )
}
CalendarWidget.propTypes = {
  hasPrevNext: PropTypes.bool,
  ...aggregationWidgetPropTypes
}

export const DefaultAggWidget = ({
  values,
  whenUnspecified,
  ...otherWidgetProps
}) => {
  const [showValues, setShowValues] = useState(false)
  const filteredValues = values.filter(value => !utils.isNullOrUndefined(value))
  if (_isEmpty(filteredValues)) {
    return whenUnspecified
  }
  return (

      <Button
        className="toggle-section-button"
        style={{ marginBottom: "1rem" }}
        onClick={toggleShowValues}
        id="toggleShowValues"
      >
        {showValues ? "Hide" : "Show"} {filteredValues.length} values
      </Button>
      <Collapse in={showValues}>

            {filteredValues.map(val => {
              const keyValue = _uniqueId("value_")
              return (

                  {val}

              )
            })}

      </Collapse>

  )
  function toggleShowValues() {
    setShowValues(!showValues)
  }
}
DefaultAggWidget.propTypes = aggregationWidgetPropTypes

export const ReportsMapWidget = ({
  values,
  mapId,
  width,
  height,
  whenUnspecified,
  ...otherWidgetProps
}) => {
  const markers = useMemo(() => {
    if (!values.length) {
      return []
    }
    const markerArray = []
    values.forEach(report => {
      if (Location.hasCoordinates(report.location)) {
        let label = _escape(report.intent || "<undefined>") // escape HTML in intent!
        label += `<br/>@ <b>${_escape(report.location.name)}</b>` // escape HTML in locationName!
        markerArray.push({
          id: report.uuid,
          lat: report.location.lat,
          lng: report.location.lng,
          name: label
        })
      }
    })
    return markerArray
  }, [values])
  if (_isEmpty(markers)) {
    return whenUnspecified
  }
  return (

      <Leaflet
        markers={markers}
        width={width}
        height={height}
        mapId={mapId}
        marginBottom={0}
      />

  )
}
ReportsMapWidget.propTypes = {
  ...aggregationWidgetPropTypes,
  mapId: PropTypes.string,
  width: PropTypes.number,
  height: PropTypes.number
}
ReportsMapWidget.defaultProps = {
  values: []
}
<|endoftext|>


<commit_before>/**
 * .reel Unit Tests
 */
(function($){

  module('Computation', { teardown: function teardown(){
    $('.jquery-reel').trigger('teardown');
  }});

  asyncTest( '`fractionChange` accepts and normalizes any real fraction passed', function(){
    expect(10);
    var
      selector= '#image',
      $reel= $(selector).reel(),
      entries= {
        '3': 0,
        '-2.1': 0.9,
        '-3.7': 0.3,
        '1.8': 0.8,
        '3.4': 0.4,
        '3.5': 0.5,
        '-0.3': 0.7,
        '1.23456': 0.2346,
        '-1.23456': 0.7654,
        '-1.2': 0.8
      }
    $reel.one('loaded', function(){
      $.each(entries, function(ix,it){
        $reel.trigger('fractionChange', Number(ix));
        equal( $reel.data('fraction').toFixed(4), it, 'Passed '+ix);
      });
      start();
    });
  });

  asyncTest( '`rowChange` accepts and normalizes any real row fraction passed', function(){
    expect(7);
    var
      selector= '#image',
      $reel= $(selector).reel({ rows: 3 }),
      entries= {
        '4': 1,
        '-2.1': 0,
        '1.8': 0.4,
        '0.4': 0,
        '-0.3': 0,
        '1.23456': 0.1173,
        '-1.23456': 0
      }
    $reel.one('loaded', function(){
      $.each(entries, function(ix,it){
        $reel.trigger('rowChange', Number(ix));
        equal( $reel.data('row').toFixed(4), it, 'Fraction '+ix);
      });
      start();
    });
  });

  asyncTest( 'Positive direction/spped is not detected as reversed', function(){
    expect(1);
    var
      selector= '#image',
      $reel= $(selector).reel({ speed: 1 })

    equal( $reel.data('backwards'), false, 'Not reversed at positive speed');
    start();
  });

  asyncTest( 'Negative direction/spped is detected as reversed', function(){
    expect(1);
    var
      selector= '#image',
      $reel= $(selector).reel({ speed: -1 })

    equal( $reel.data('backwards'), true, 'Reversed at negative speeds');
    start();
  });

  test( 'Default `$.reel.math.spread`', function(){
    expect(11);
    var
      probes= {
        10: {
          options: {
            images: [1,2,3,4,5,6,7,8,9,10],
            frames: 10,
            frame: 1
          },
          ordered: [1,6,4,9,2,7,5,10,3,8]
        },
        12: {
          options: {
            images: [1,2,3,4,5,6,7,8,9,10,11,12],
            frames: 12,
            frame: 1
          },
          ordered: [1,7,4,10,3,9,6,12,2,8,5,11]
        },
        15: {
          options: {
            images: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15],
            frames: 15,
            frame: 1
          },
          ordered: [1,9,5,13,3,11,7,15,2,10,6,14,4,12,8]
        },
        18: {
          options: {
            images: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18],
            frames: 18,
            frame: 1
          },
          ordered: [1,10,6,15,3,12,8,17,2,11,7,16,4,13,9,18,5,14]
        },
        24: {
          options: {
            images: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24],
            frames: 24,
            frame: 1
          },
          ordered: [1,13, 7,19, 4,16,10,22, 3,15,9,21,6,18,12,24, 2,14,8,20,5,17,11,23]
        },
        36: {
          options: {
            images: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36],
            frames: 36,
            frame: 1
          },
          ordered: [1,19, 10,28, 6,24,15,33, 3,21,12,30,8,26,17,35, 2,20,11,29,7,25,16,34,4,22,13,31,9,27,18,36, 5,23,14,32]
        },
        48: {
          options: {
            images: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48],
            frames: 48,
            frame: 1
          },
          ordered: [1,25, 13,37, 7,31,19,43, 4,28,16,40,10,34,22,46, 3,27,15,39,9,33,21,45,6,30,18,42,12,36,24,48, 2,26,14,38,8,32,20,44,5,29,17,41,11,35,23,47]
        },

        // Atypicals with different starting points
        17: {
          options: {
            images: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17],
            frames: 17,
            frame: 7
          },
          ordered: [7,16, 11,3, 9,1,13,5, 8,17,12,4,10,2,14,6, 15]
        },
        23: {
          options: {
            images: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23],
            frames: 23,
            frame: 11
          },
          ordered: [11,23, 17,6, 14,3,20,9, 12,1,18,7,15,4,21,10, 13,2,19,8,16,5,22]
        },
        27: {
          options: {
            images: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27],
            frames: 27,
            frame: 27
          },
          ordered: [27,14, 7,21, 3,17,10,24, 2,16,9,23,5,19,12,26, 1,15,8,22,4,18,11,25,6,20,13]
        }
      }

    ok( typeof $.reel.math.spread == 'function', '`$.reel.math.spread` available');

    $.each(probes, function(frames, def){
      var
        $reel= $('#image').reel(def.options),
        opt= $.extend({}, $.reel.def, def.options),
        get= function(name){ return $reel.data(name) }
      deepEqual( $.reel.math.spread(def.options.images, opt, get), def.ordered, frames+' frames starting at frame '+def.start);
    });

  });

})(jQuery);
<commit_msg>In order to accomodate multi-row tests, the test has been tweaked also. Also the tested function has been run twice before - fixed. The fix introduced different way of receiving the result by using instance's `.data("images")` instead of calling the function to get the result directly - this however holds whole paths as strings, so adjusting the expected values to be strings instead of numbers for the `deepEqual` comparison. #10<commit_after>/**
 * .reel Unit Tests
 */
(function($){

  module('Computation', { teardown: function teardown(){
    $('.jquery-reel').trigger('teardown');
  }});

  asyncTest( '`fractionChange` accepts and normalizes any real fraction passed', function(){
    expect(10);
    var
      selector= '#image',
      $reel= $(selector).reel(),
      entries= {
        '3': 0,
        '-2.1': 0.9,
        '-3.7': 0.3,
        '1.8': 0.8,
        '3.4': 0.4,
        '3.5': 0.5,
        '-0.3': 0.7,
        '1.23456': 0.2346,
        '-1.23456': 0.7654,
        '-1.2': 0.8
      }
    $reel.one('loaded', function(){
      $.each(entries, function(ix,it){
        $reel.trigger('fractionChange', Number(ix));
        equal( $reel.data('fraction').toFixed(4), it, 'Passed '+ix);
      });
      start();
    });
  });

  asyncTest( '`rowChange` accepts and normalizes any real row fraction passed', function(){
    expect(7);
    var
      selector= '#image',
      $reel= $(selector).reel({ rows: 3 }),
      entries= {
        '4': 1,
        '-2.1': 0,
        '1.8': 0.4,
        '0.4': 0,
        '-0.3': 0,
        '1.23456': 0.1173,
        '-1.23456': 0
      }
    $reel.one('loaded', function(){
      $.each(entries, function(ix,it){
        $reel.trigger('rowChange', Number(ix));
        equal( $reel.data('row').toFixed(4), it, 'Fraction '+ix);
      });
      start();
    });
  });

  asyncTest( 'Positive direction/spped is not detected as reversed', function(){
    expect(1);
    var
      selector= '#image',
      $reel= $(selector).reel({ speed: 1 })

    equal( $reel.data('backwards'), false, 'Not reversed at positive speed');
    start();
  });

  asyncTest( 'Negative direction/spped is detected as reversed', function(){
    expect(1);
    var
      selector= '#image',
      $reel= $(selector).reel({ speed: -1 })

    equal( $reel.data('backwards'), true, 'Reversed at negative speeds');
    start();
  });

  test( 'Default `$.reel.math.spread`', function(){
    expect(11);
    var
      probes= {
        10: {
          options: {
            images: [1,2,3,4,5,6,7,8,9,10],
            frames: 10,
            frame: 1
          },
          ordered: '1,6,4,9,2,7,5,10,3,8'.split(/, ?/)
        },
        12: {
          options: {
            images: [1,2,3,4,5,6,7,8,9,10,11,12],
            frames: 12,
            frame: 1
          },
          ordered: '1,7,4,10,3,9,6,12,2,8,5,11'.split(/, ?/)
        },
        15: {
          options: {
            images: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15],
            frames: 15,
            frame: 1
          },
          ordered: '1,9,5,13,3,11,7,15,2,10,6,14,4,12,8'.split(/, ?/)
        },
        18: {
          options: {
            images: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18],
            frames: 18,
            frame: 1
          },
          ordered: '1,10,6,15,3,12,8,17,2,11,7,16,4,13,9,18,5,14'.split(/, ?/)
        },
        24: {
          options: {
            images: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24],
            frames: 24,
            frame: 1
          },
          ordered: '1,13, 7,19, 4,16,10,22, 3,15,9,21,6,18,12,24, 2,14,8,20,5,17,11,23'.split(/, ?/)
        },
        36: {
          options: {
            images: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36],
            frames: 36,
            frame: 1
          },
          ordered: '1,19, 10,28, 6,24,15,33, 3,21,12,30,8,26,17,35, 2,20,11,29,7,25,16,34,4,22,13,31,9,27,18,36, 5,23,14,32'.split(/, ?/)
        },
        48: {
          options: {
            images: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48],
            frames: 48,
            frame: 1
          },
          ordered: '1,25, 13,37, 7,31,19,43, 4,28,16,40,10,34,22,46, 3,27,15,39,9,33,21,45,6,30,18,42,12,36,24,48, 2,26,14,38,8,32,20,44,5,29,17,41,11,35,23,47'.split(/, ?/)
        },

        // Atypicals with different starting points
        17: {
          options: {
            images: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17],
            frames: 17,
            frame: 7
          },
          ordered: '7,16, 11,3, 9,1,13,5, 8,17,12,4,10,2,14,6, 15'.split(/, ?/)
        },
        23: {
          options: {
            images: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23],
            frames: 23,
            frame: 11
          },
          ordered: '11,23, 17,6, 14,3,20,9, 12,1,18,7,15,4,21,10, 13,2,19,8,16,5,22'.split(/, ?/)
        },
        27: {
          options: {
            images: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27],
            frames: 27,
            frame: 27
          },
          ordered: '27,14, 7,21, 3,17,10,24, 2,16,9,23,5,19,12,26, 1,15,8,22,4,18,11,25,6,20,13'.split(/, ?/)
        }
      }

    ok( typeof $.reel.math.spread == 'function', '`$.reel.math.spread` available');

    $.each(probes, function(ix, def){
      var
        $reel= $('#image').reel(def.options)
      deepEqual( $reel.data('images'), def.ordered, ix+' frames starting at frame '+def.options.frame);
    });

  });

})(jQuery);
<|endoftext|>


<commit_before>import React, { Component } from "react";
import PropTypes from "prop-types";

class Links extends Component {
  render() {
    const { scale, values, children } = this.props;
    const links = [];

    for (let i = 0; i < values.length + 1; i++) {
      const s = values[i - 1];
      const t = values[i];

      links.push({
        key: `${s ? s.key : "$"}-${t ? t.key : "$"}`,
        source: s || null,
        target: t || null
      });
    }

    const renderedChildren = children({ links, scale, values });
    return renderedChildren && React.Children.only(renderedChildren);
  }
}

Links.propTypes = {
  scale: PropTypes.func,
  values: PropTypes.array,
  children: PropTypes.func
};

export default Links;
<commit_msg>fix linting<commit_after>import React, { Component } from 'react'
import PropTypes from 'prop-types'

class Links extends Component {
  render() {
    const { scale, values, children } = this.props
    const links = []

    for (let i = 0; i < values.length + 1; i++) {
      const s = values[i - 1]
      const t = values[i]

      links.push({
        key: `${s ? s.key : '$'}-${t ? t.key : '$'}`,
        source: s || null,
        target: t || null,
      })
    }

    const renderedChildren = children({ links, scale, values })
    return renderedChildren && React.Children.only(renderedChildren)
  }
}

Links.propTypes = {
  scale: PropTypes.func,
  values: PropTypes.array,
  children: PropTypes.func,
}

export default Links
<|endoftext|>


<commit_before>// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

'use strict';

/**
 * Watches for changes in the tracked directory, including local metadata
 * changes.
 *
 * @param {MetadataCache} metadataCache Instance of MetadataCache.
 * @extends {cr.EventTarget}
 * @constructor
 */
function FileWatcher(metadataCache) {
  this.queue_ = new AsyncUtil.Queue();
  this.metadataCache_ = metadataCache;
  this.watchedDirectoryEntry_ = null;

  this.onDirectoryChangedBound_ = this.onDirectoryChanged_.bind(this);
  chrome.fileBrowserPrivate.onDirectoryChanged.addListener(
      this.onDirectoryChangedBound_);

  this.filesystemMetadataObserverId_ = null;
  this.thumbnailMetadataObserverId_ = null;
  this.driveMetadataObserverId_ = null;
}

/**
 * FileWatcher extends cr.EventTarget.
 */
FileWatcher.prototype.__proto__ = cr.EventTarget.prototype;

/**
 * Stops watching (must be called before page unload).
 */
FileWatcher.prototype.dispose = function() {
  chrome.fileBrowserPrivate.onDirectoryChanged.removeListener(
      this.onDirectoryChangedBound_);
  if (this.watchedDirectoryEntry_)
    this.resetWatchedEntry_();
};

/**
 * Called when a file in the watched directory is changed.
 * @param {Event} event Change event.
 * @private
 */
FileWatcher.prototype.onDirectoryChanged_ = function(event) {
  if (event.directoryUrl == this.watchedDirectoryEntry_.toURL()) {
    var e = new cr.Event('watcher-directory-changed');
    this.dispatchEvent(e);
  }
};

/**
 * Called when general metadata in the watched directory has been changed.
 *
 * @param {Array.<string>} urls Array of urls.
 * @param {Object.<string, Object>} properties Map from entry URLs to metadata
 *     properties.
 * @private
 */
FileWatcher.prototype.onFilesystemMetadataChanged_ = function(
    urls, properties) {
  this.dispatchMetadataEvent_('filesystem', urls, properties);
};

/**
 * Called when thumbnail metadata in the watched directory has been changed.
 *
 * @param {Array.<string>} urls Array of urls.
 * @param {Object.<string, Object>} properties Map from entry URLs to metadata
 *     properties.
 * @private
 */
FileWatcher.prototype.onThumbnailMetadataChanged_ = function(
    urls, properties) {
  this.dispatchMetadataEvent_('thumbnail', urls, properties);
};

/**
 * Called when drive metadata in the watched directory has been changed.
 *
 * @param {Array.<string>} urls Array of urls.
 * @param {Object.<string, Object>} properties Map from entry URLs to metadata
 *     properties.
 * @private
 */
FileWatcher.prototype.onDriveMetadataChanged_ = function(
    urls, properties) {
  this.dispatchMetadataEvent_('drive', urls, properties);
};

/**
 * Dispatches an event about detected change in metadata within the tracked
 * directory.
 *
 * @param {string} type Type of the metadata change.
 * @param {Array.<string>} urls Array of urls.
 * @param {Object.<string, Object>} properties Map from entry URLs to metadata
 *     properties.
 * @private
 */
FileWatcher.prototype.dispatchMetadataEvent_ = function(
    type, urls, properties) {
  var e = new cr.Event('watcher-metadata-changed');
  e.metadataType = type;
  e.urls = urls;
  e.properties = properties;
  this.dispatchEvent(e);
};

/**
 * Changes the watched directory. In case of a fake entry, the watch is
 * just released, since there is no reason to track a fake directory.
 *
 * @param {!DirectoryEntry|!Object} entry Directory entry to be tracked, or the
 *     fake entry.
 * @param {function()} callback Completion callback.
 */
FileWatcher.prototype.changeWatchedDirectory = function(entry, callback) {
  if (entry && entry.toURL) {
    this.changeWatchedEntry_(
        entry,
        callback,
        function() {
          console.error(
             'Unable to change the watched directory to: ' + entry.toURL());
          callback();
        });
  } else {
    this.resetWatchedEntry_(
        callback,
        function() {
          console.error('Unable to reset the watched directory.');
          callback();
        });
  }
};

/**
 * Resets the watched entry to the passed directory.
 *
 * @param {function()} onSuccess Success callback.
 * @param {function()} onError Error callback.
 * @private
 */
FileWatcher.prototype.resetWatchedEntry_ = function(onSuccess, onError) {
  // Run the tasks in the queue to avoid races.
  this.queue_.run(function(callback) {
    // Release the watched directory.
    if (this.watchedDirectoryEntry_) {
      chrome.fileBrowserPrivate.removeFileWatch(
          this.watchedDirectoryEntry_.toURL(),
          function(result) {
            this.watchedDirectoryEntry_ = null;
            if (result)
              onSuccess();
            else
              onError();
            callback();
          });
      this.metadataCache_.removeObserver(this.filesystemMetadataObserverId_);
      this.metadataCache_.removeObserver(this.thumbnailMetadataObserverId_);
      this.metadataCache_.removeObserver(this.driveMetadataObserverId_);
    } else {
      onSuccess();
      callback();
    }
  }.bind(this));
};

/**
 * Sets the watched entry to the passed directory.
 *
 * @param {!DirectoryEntry} entry Directory to be watched.
 * @param {function()} onSuccess Success callback.
 * @param {function()} onError Error callback.
 * @private
 */
FileWatcher.prototype.changeWatchedEntry_ = function(
    entry, onSuccess, onError) {
  var setEntryClosure = function() {
    // Run the tasks in the queue to avoid races.
    this.queue_.run(function(callback) {
      chrome.fileBrowserPrivate.addFileWatch(
          entry.toURL(),
          function(result) {
            if (!result) {
              this.watchedDirectoryEntry_ = null;
              onError();
            } else {
              this.watchedDirectoryEntry_ = entry;
              onSuccess();
            }
            callback();
          }.bind(this));
      this.filesystemMetadataObserverId_ = this.metadataCache_.addObserver(
        entry,
        MetadataCache.CHILDREN,
        'filesystem',
        this.onFilesystemMetadataChanged_.bind(this));
      this.thumbnailMetadataObserverId_ = this.metadataCache_.addObserver(
        entry,
        MetadataCache.CHILDREN,
        'thumbnail',
        this.onThumbnailMetadataChanged_.bind(this));
      this.driveMetadataObserverId_ = this.metadataCache_.addObserver(
        entry,
        MetadataCache.CHILDREN,
        'drive',
        this.onDriveMetadataChanged_.bind(this));
    }.bind(this));
  }.bind(this);

  // Reset the watched directory first, then set the new watched directory.
  this.resetWatchedEntry_(setEntryClosure, onError);
};

/**
 * @return {DirectoryEntry} Current watched directory entry.
 */
FileWatcher.prototype.getWatchedDirectoryEntry = function() {
  return this.watchedDirectoryEntry_;
};
<commit_msg>Fix console error log when closing Chrome OS save file dialog.<commit_after>// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

'use strict';

/**
 * Watches for changes in the tracked directory, including local metadata
 * changes.
 *
 * @param {MetadataCache} metadataCache Instance of MetadataCache.
 * @extends {cr.EventTarget}
 * @constructor
 */
function FileWatcher(metadataCache) {
  this.queue_ = new AsyncUtil.Queue();
  this.metadataCache_ = metadataCache;
  this.watchedDirectoryEntry_ = null;

  this.onDirectoryChangedBound_ = this.onDirectoryChanged_.bind(this);
  chrome.fileBrowserPrivate.onDirectoryChanged.addListener(
      this.onDirectoryChangedBound_);

  this.filesystemMetadataObserverId_ = null;
  this.thumbnailMetadataObserverId_ = null;
  this.driveMetadataObserverId_ = null;
}

/**
 * FileWatcher extends cr.EventTarget.
 */
FileWatcher.prototype.__proto__ = cr.EventTarget.prototype;

/**
 * Stops watching (must be called before page unload).
 */
FileWatcher.prototype.dispose = function() {
  chrome.fileBrowserPrivate.onDirectoryChanged.removeListener(
      this.onDirectoryChangedBound_);
  if (this.watchedDirectoryEntry_)
    this.resetWatchedEntry_(function() {}, function() {});
};

/**
 * Called when a file in the watched directory is changed.
 * @param {Event} event Change event.
 * @private
 */
FileWatcher.prototype.onDirectoryChanged_ = function(event) {
  if (event.directoryUrl == this.watchedDirectoryEntry_.toURL()) {
    var e = new cr.Event('watcher-directory-changed');
    this.dispatchEvent(e);
  }
};

/**
 * Called when general metadata in the watched directory has been changed.
 *
 * @param {Array.<string>} urls Array of urls.
 * @param {Object.<string, Object>} properties Map from entry URLs to metadata
 *     properties.
 * @private
 */
FileWatcher.prototype.onFilesystemMetadataChanged_ = function(
    urls, properties) {
  this.dispatchMetadataEvent_('filesystem', urls, properties);
};

/**
 * Called when thumbnail metadata in the watched directory has been changed.
 *
 * @param {Array.<string>} urls Array of urls.
 * @param {Object.<string, Object>} properties Map from entry URLs to metadata
 *     properties.
 * @private
 */
FileWatcher.prototype.onThumbnailMetadataChanged_ = function(
    urls, properties) {
  this.dispatchMetadataEvent_('thumbnail', urls, properties);
};

/**
 * Called when drive metadata in the watched directory has been changed.
 *
 * @param {Array.<string>} urls Array of urls.
 * @param {Object.<string, Object>} properties Map from entry URLs to metadata
 *     properties.
 * @private
 */
FileWatcher.prototype.onDriveMetadataChanged_ = function(
    urls, properties) {
  this.dispatchMetadataEvent_('drive', urls, properties);
};

/**
 * Dispatches an event about detected change in metadata within the tracked
 * directory.
 *
 * @param {string} type Type of the metadata change.
 * @param {Array.<string>} urls Array of urls.
 * @param {Object.<string, Object>} properties Map from entry URLs to metadata
 *     properties.
 * @private
 */
FileWatcher.prototype.dispatchMetadataEvent_ = function(
    type, urls, properties) {
  var e = new cr.Event('watcher-metadata-changed');
  e.metadataType = type;
  e.urls = urls;
  e.properties = properties;
  this.dispatchEvent(e);
};

/**
 * Changes the watched directory. In case of a fake entry, the watch is
 * just released, since there is no reason to track a fake directory.
 *
 * @param {!DirectoryEntry|!Object} entry Directory entry to be tracked, or the
 *     fake entry.
 * @param {function()} callback Completion callback.
 */
FileWatcher.prototype.changeWatchedDirectory = function(entry, callback) {
  if (entry && entry.toURL) {
    this.changeWatchedEntry_(
        entry,
        callback,
        function() {
          console.error(
             'Unable to change the watched directory to: ' + entry.toURL());
          callback();
        });
  } else {
    this.resetWatchedEntry_(
        callback,
        function() {
          console.error('Unable to reset the watched directory.');
          callback();
        });
  }
};

/**
 * Resets the watched entry to the passed directory.
 *
 * @param {function()} onSuccess Success callback.
 * @param {function()} onError Error callback.
 * @private
 */
FileWatcher.prototype.resetWatchedEntry_ = function(onSuccess, onError) {
  // Run the tasks in the queue to avoid races.
  this.queue_.run(function(callback) {
    // Release the watched directory.
    if (this.watchedDirectoryEntry_) {
      chrome.fileBrowserPrivate.removeFileWatch(
          this.watchedDirectoryEntry_.toURL(),
          function(result) {
            this.watchedDirectoryEntry_ = null;
            if (result)
              onSuccess();
            else
              onError();
            callback();
          });
      this.metadataCache_.removeObserver(this.filesystemMetadataObserverId_);
      this.metadataCache_.removeObserver(this.thumbnailMetadataObserverId_);
      this.metadataCache_.removeObserver(this.driveMetadataObserverId_);
    } else {
      onSuccess();
      callback();
    }
  }.bind(this));
};

/**
 * Sets the watched entry to the passed directory.
 *
 * @param {!DirectoryEntry} entry Directory to be watched.
 * @param {function()} onSuccess Success callback.
 * @param {function()} onError Error callback.
 * @private
 */
FileWatcher.prototype.changeWatchedEntry_ = function(
    entry, onSuccess, onError) {
  var setEntryClosure = function() {
    // Run the tasks in the queue to avoid races.
    this.queue_.run(function(callback) {
      chrome.fileBrowserPrivate.addFileWatch(
          entry.toURL(),
          function(result) {
            if (!result) {
              this.watchedDirectoryEntry_ = null;
              onError();
            } else {
              this.watchedDirectoryEntry_ = entry;
              onSuccess();
            }
            callback();
          }.bind(this));
      this.filesystemMetadataObserverId_ = this.metadataCache_.addObserver(
        entry,
        MetadataCache.CHILDREN,
        'filesystem',
        this.onFilesystemMetadataChanged_.bind(this));
      this.thumbnailMetadataObserverId_ = this.metadataCache_.addObserver(
        entry,
        MetadataCache.CHILDREN,
        'thumbnail',
        this.onThumbnailMetadataChanged_.bind(this));
      this.driveMetadataObserverId_ = this.metadataCache_.addObserver(
        entry,
        MetadataCache.CHILDREN,
        'drive',
        this.onDriveMetadataChanged_.bind(this));
    }.bind(this));
  }.bind(this);

  // Reset the watched directory first, then set the new watched directory.
  this.resetWatchedEntry_(setEntryClosure, onError);
};

/**
 * @return {DirectoryEntry} Current watched directory entry.
 */
FileWatcher.prototype.getWatchedDirectoryEntry = function() {
  return this.watchedDirectoryEntry_;
};
<|endoftext|>