<commit_before>var WXMLConverter = (function() {
  var xmlDoc = null;
  var wordpressData = {
    authors: {},
    categories: {},
    posts: {},
    tags: {},
    attachements: {},
    pages: {},
  };

  var onConverterUpdated = function() {

  };

  var parseWXML = function(data, callback) {
    this.onConverterUpdated({ event: 'parsingXML', class: 'active', running: true});

    // Post meta sometimes contain invalid XML, we wont need it so destroy it, not a great regex but it works
    data = data.replace(/<wp:postmeta\>((?!<\/wp:postmeta>)[\s\S])*<\/wp:postmeta>/g, '');

    // Wordpress XML will sometimes contain utf characters that aren't valid XML character
    // This regex is used to remove most of them. We do an inclusive regex instead of an exclusive regex, because javascript
    // has no standard way to handle UTF code points past 0xFFFF.... so this isn't perfect, but it will work for more cases than the alternative
    data = data.replace(/[\u0001-\u0008\u000B-\u000C\u000E-\u001F\uD800-\uDFFF\uFFFE-\uFFFF]/g, '');

    // DOM Parser doesn't exist on older IE, but our CMS doesn't support that anyways so W/e
    parser=new DOMParser();
    xmlDoc=parser.parseFromString(data,"text/xml");

    // TODO, CHECK FOR PARSE ERROR (Look for Parse Error XML Doc)

    var jsonObj = xmlToJson(xmlDoc);

    // TODO, VERIFY WORDPRESS XML VERSION IS 12, IF HIGHER/LOWER GIVE WARNING, PROBABLY WONT WORK

    var channel = jsonObj.rss.channel;

    // Most of these fields are from test data, and correlating with this reverse enginered description
    // http://devtidbits.com/2011/03/16/the-wordpress-extended-rss-wxr-exportimport-xml-document-format-decoded-and-explained/
    wordpressData.title = convertEmpty(getNodeValue(channel['title']));
    wordpressData.link = convertEmpty(getNodeValue(channel['link']));
    wordpressData.pubDate = convertEmpty(getNodeValue(channel['pubDate']));
    wordpressData.description = convertEmpty(getNodeValue(channel['description']));
    wordpressData.language = convertEmpty(getNodeValue(channel['language']));
    wordpressData.image = convertEmpty(getNodeValue(channel['image']));

    for(var key in channel['wp:author']) {
      if(!channel['wp:author'].hasOwnProperty(key)) {
        continue;
      }

      var author = channel['wp:author'][key];
      var newAuthor = {};

      for(var okey in author) {
        if(!author.hasOwnProperty(okey)) {
          continue;
        }

        newAuthor[okey.replace('wp:', '')] = getNodeValue(author[okey]);
      }

      var fixedAuthor = {};

      fixedAuthor.display_name = convertEmpty(newAuthor.author_display_name);
      fixedAuthor.email = convertEmpty(newAuthor.author_email);
      fixedAuthor.first_name = convertEmpty(newAuthor.author_first_name);
      fixedAuthor.last_name = convertEmpty(newAuthor.author_last_name);
      fixedAuthor.login = convertEmpty(newAuthor.author_login);

      // Using the login name will be easier for looking up relations later
      // Need to make sure login is always a valid JS key though
      wordpressData.authors[fixedAuthor.login] = fixedAuthor;
    }

    for(var key in channel['wp:category']) {
        if(!channel['wp:category'].hasOwnProperty(key)) {
          continue;
        }

      var category = channel['wp:category'][key];
      var newCategory = {};

      for(var okey in category) {
        if(!category.hasOwnProperty(okey)) {
          continue;
        }

        newCategory[okey.replace('wp:', '')] = getNodeValue(category[okey]);
      }

      var fixedCategory = {};

      fixedCategory.name = convertEmpty(newCategory.cat_name);
      fixedCategory.parent = convertEmpty(newCategory.category_parent);

      // Nice name will be easier to lookup relations later
      wordpressData.categories[newCategory.category_nicename] = fixedCategory;
    }

    for(var key in channel['wp:tag']) {
      if(!channel['wp:tag'].hasOwnProperty(key)) {
        continue;
      }

      var tag = channel['wp:tag'][key];
      var newTag = {};

      for(var okey in tag) {
        if(!tag.hasOwnProperty(okey)) {
          continue;
        }

        newTag[okey.replace('wp:', '')] = getNodeValue(tag[okey]);
      }

      var fixedTag = {};
      fixedTag.slug = convertEmpty(newTag.tag_slug);
      fixedTag.name = convertEmpty(newTag.tag_name);

      wordpressData.tags[fixedTag.slug] = fixedTag;
    }

    for(var key in channel['item']) {
      if(!channel['item'].hasOwnProperty(key)) {
        continue;
      }

      var items = channel['item'][key];
      var newItem = {};

      var categoryAndTags = {};

      for(var okey in items) {
        if(!items.hasOwnProperty(okey)) {
          continue;
        }

        if(okey === 'category') {
          categoryAndTags = getCategoryValue(items[okey]);
        } else {
          newItem[okey.replace('wp:', '').replace('dc:', '')] = getNodeValue(items[okey]);
        }
      }

      delete newItem['#text'];

      var newPost = {};

      newPost.title = convertEmpty(newItem.title);
      newPost.pubDate = convertEmpty(newItem.pubDate);
      newPost.creator = convertEmpty(newItem.creator); // == Author login
      newPost.description = convertEmpty(newItem.description); // Should be blank

      newPost.content = convertEmpty(newItem['content:encoded']); // Content of post
      newPost.caption = convertEmpty(newItem['excerpt:encoded']); // Apparently a caption of a file

      newPost.post_date = convertEmpty(newItem.post_date);
      newPost.post_date_gmt = convertEmpty(newItem.post_date_gmt);

      newPost.status = convertEmpty(newItem.status); // Can be 'publish', 'draft', 'pending', 'private', 'trash', ... 'inherit?'

      newPost.parent = convertEmpty(newItem.post_parent); // You can have nested posts, assume inherit = parent post
      newPost.menu_order = convertEmpty(newItem.menu_order); // Apparently the order in which to show up as a child

      newPost.attachment_url = convertEmpty(newItem.attachment_url);

      newPost.categories= categoryAndTags.categories; // Object or single item? Hard to tell
      newPost.tags = categoryAndTags.tags;

      newPost.sticky = convertEmpty(newItem.is_sticky);

      // Maybe parse out comments, but since we dont have commenting without a JS library on webhook, not sure if needed

      // For convienence later swap them into different keys
      // Post ID is used as the key to trace the parent relations between attachements and parent posts
      if(newItem.post_type === "attachment") {
        wordpressData.attachements[newItem.post_id] = newPost;
      } else if (newItem.post_type === "page") {
        wordpressData.pages[newItem.post_id] = newPost;
      } else {
        wordpressData.posts[newItem.post_id] = newPost;
      }
    }

    this.onConverterUpdated({ event: 'parsingXML', class: 'complete', running: false});

    callback(wordpressData);
  }

  // The getNodeValue function will sometimes return an empty object for various reasons (parsing, special cases),
  // this is the equivilant to an empty field really, so we just convert it to null
  var convertEmpty = function(val) {
    return $.isEmptyObject(val) ? null : val;
  };

  var getCategoryValue = function(node) {
    if(!node) {
      return null;
    }

    var extractInfo = function(n) {
      if(!n['@attributes']) {
        return { domain: 'category', nicename: convertEmpty(getNodeValue(n)), val: convertEmpty(getNodeValue(n))};
      }
      var domain = n['@attributes']['domain'];
      var nicename = n['@attributes']['nicename'];

      return { domain: domain, nicename: nicename, val: convertEmpty(getNodeValue(n)) };
    };

    var categories = {};
    var tags = {};
    var extracted = null;
    if(node instanceof Array) {

      node.forEach(function(item) {
        extracted = extractInfo(item);

        if(extracted.domain === 'category') {
          categories[extracted.nicename] = extracted.val;
        } else if (extracted.domain === 'post_tag') {
          tags[extracted.nicename] = extracted.val;
        }

      });

    } else {
      extracted = extractInfo(node);

      if(extracted.domain === 'category') {
        categories[extracted.nicename] = extracted.val;
      } else if (extracted.domain === 'post_tag') {
        tags[extracted.nicename] = extracted.val;
      }
    }

    return { categories: categories, tags: tags };
  };

  // Grab the node value from the JSON objects parsed from XML
  var getNodeValue = function(node) {
    if(!node) {
      return null;
    }

    // Sometimes the node is an array of nodes, parse each array value
    if(node instanceof Array) {
      var fixedArray = [];
      node.forEach(function(item) {
        fixedArray.push(getNodeValue(item));
      });

      return fixedArray;
    }

    // The xmlToJson function seperates the cdata and text values into different areas, seperate them
    if (typeof node === 'object' && '#cdata-section' in node) return node['#cdata-section'];
    if (typeof node === 'object' && '#text' in node) return node['#text'];

    // If it didnt work just throw it back, its most likely a simple data type
    return node;
  };

  // A function to convert XML to JSON, any conversion wont be 100% standard or accurate (due to limitations), but this is good
  // enough for Wordpress XML (need more test data to reach a good verification)
  xmlToJson = function(xml) {
    var obj = {};
    if (xml.nodeType == 1) {
        if (xml.attributes.length > 0) {
            obj["@attributes"] = {};
            for (var j = 0; j < xml.attributes.length; j++) {
                var attribute = xml.attributes.item(j);
                obj["@attributes"][attribute.nodeName] = attribute.nodeValue;
            }
        }
    } else if (xml.nodeType == 3) {
        obj = xml.nodeValue;
    } else if (xml.nodeType == 4) {
        obj = xml.nodeValue;
    }
    if (xml.hasChildNodes()) {
        for (var i = 0; i < xml.childNodes.length; i++) {
            var item = xml.childNodes.item(i);
            var nodeName = item.nodeName;

            if (typeof (obj[nodeName]) == "undefined") {
                obj[nodeName] = xmlToJson(item);
            } else {
                if (typeof (obj[nodeName].push) == "undefined") {
                    var old = obj[nodeName];
                    obj[nodeName] = [];
                    obj[nodeName].push(old);
                }
                obj[nodeName].push(xmlToJson(item));
            }
        }
    }
    return obj;
  }

  return {
    convert: parseWXML,
    onConverterUpdated: onConverterUpdated
  }
})();<commit_msg>fix singular case<commit_after>var WXMLConverter = (function() {
  var xmlDoc = null;
  var wordpressData = {
    authors: {},
    categories: {},
    posts: {},
    tags: {},
    attachements: {},
    pages: {},
  };

  var onConverterUpdated = function() {

  };

  var parseWXML = function(data, callback) {
    this.onConverterUpdated({ event: 'parsingXML', class: 'active', running: true});

    // Post meta sometimes contain invalid XML, we wont need it so destroy it, not a great regex but it works
    data = data.replace(/<wp:postmeta\>((?!<\/wp:postmeta>)[\s\S])*<\/wp:postmeta>/g, '');

    // Wordpress XML will sometimes contain utf characters that aren't valid XML character
    // This regex is used to remove most of them. We do an inclusive regex instead of an exclusive regex, because javascript
    // has no standard way to handle UTF code points past 0xFFFF.... so this isn't perfect, but it will work for more cases than the alternative
    data = data.replace(/[\u0001-\u0008\u000B-\u000C\u000E-\u001F\uD800-\uDFFF\uFFFE-\uFFFF]/g, '');

    // DOM Parser doesn't exist on older IE, but our CMS doesn't support that anyways so W/e
    parser=new DOMParser();
    xmlDoc=parser.parseFromString(data,"text/xml");

    // TODO, CHECK FOR PARSE ERROR (Look for Parse Error XML Doc)

    var jsonObj = xmlToJson(xmlDoc);

    // TODO, VERIFY WORDPRESS XML VERSION IS 12, IF HIGHER/LOWER GIVE WARNING, PROBABLY WONT WORK

    var channel = jsonObj.rss.channel;

    // Most of these fields are from test data, and correlating with this reverse enginered description
    // http://devtidbits.com/2011/03/16/the-wordpress-extended-rss-wxr-exportimport-xml-document-format-decoded-and-explained/
    wordpressData.title = convertEmpty(getNodeValue(channel['title']));
    wordpressData.link = convertEmpty(getNodeValue(channel['link']));
    wordpressData.pubDate = convertEmpty(getNodeValue(channel['pubDate']));
    wordpressData.description = convertEmpty(getNodeValue(channel['description']));
    wordpressData.language = convertEmpty(getNodeValue(channel['language']));
    wordpressData.image = convertEmpty(getNodeValue(channel['image']));

    var parseAuthor = function(author) {
      var newAuthor = {};

      for(var okey in author) {
        if(!author.hasOwnProperty(okey)) {
          continue;
        }

        newAuthor[okey.replace('wp:', '')] = getNodeValue(author[okey]);
      }

      var fixedAuthor = {};

      fixedAuthor.display_name = convertEmpty(newAuthor.author_display_name);
      fixedAuthor.email = convertEmpty(newAuthor.author_email);
      fixedAuthor.first_name = convertEmpty(newAuthor.author_first_name);
      fixedAuthor.last_name = convertEmpty(newAuthor.author_last_name);
      fixedAuthor.login = convertEmpty(newAuthor.author_login);

      // Using the login name will be easier for looking up relations later
      // Need to make sure login is always a valid JS key though
      wordpressData.authors[fixedAuthor.login] = fixedAuthor;
    }

    if(Array.isArray(channel['wp:author'])) {
      for(var key in channel['wp:author']) {
        if(!channel['wp:author'].hasOwnProperty(key)) {
          continue;
        }

        parseAuthor(channel['wp:author'][key]);
      }
    } else if (channel['wp:author']) {
        parseAuthor(channel['wp:author']);
    }

    var parseCategory = function(category) {
      var newCategory = {};

      for(var okey in category) {
        if(!category.hasOwnProperty(okey)) {
          continue;
        }

        newCategory[okey.replace('wp:', '')] = getNodeValue(category[okey]);
      }

      var fixedCategory = {};

      fixedCategory.name = convertEmpty(newCategory.cat_name);
      fixedCategory.parent = convertEmpty(newCategory.category_parent);

      // Nice name will be easier to lookup relations later
      wordpressData.categories[newCategory.category_nicename] = fixedCategory;
    }

    if(Array.isArray(channel['wp:author'])) {
      for(var key in channel['wp:category']) {
          if(!channel['wp:category'].hasOwnProperty(key)) {
            continue;
          }

        parseCategory(channel['wp:category'][key]);
      }
    } else if (channel['wp:author']) {
        parseCategory(channel['wp:category']);
    }

    var parseTag = function(tag) {
      var newTag = {};

      for(var okey in tag) {
        if(!tag.hasOwnProperty(okey)) {
          continue;
        }

        newTag[okey.replace('wp:', '')] = getNodeValue(tag[okey]);
      }

      var fixedTag = {};
      fixedTag.slug = convertEmpty(newTag.tag_slug);
      fixedTag.name = convertEmpty(newTag.tag_name);

      wordpressData.tags[fixedTag.slug] = fixedTag;
    }

    if(Array.isArray(channel['wp:tag'])) {
      for(var key in channel['wp:tag']) {
        if(!channel['wp:tag'].hasOwnProperty(key)) {
          continue;
        }

        parseTag(channel['wp:tag'][key]);
      }
    } else if (channel['wp:tag']) {
        parseTag(channel['wp:tag']);
    }

    for(var key in channel['item']) {
      if(!channel['item'].hasOwnProperty(key)) {
        continue;
      }

      var items = channel['item'][key];
      var newItem = {};

      var categoryAndTags = {};

      for(var okey in items) {
        if(!items.hasOwnProperty(okey)) {
          continue;
        }

        if(okey === 'category') {
          categoryAndTags = getCategoryValue(items[okey]);
        } else {
          newItem[okey.replace('wp:', '').replace('dc:', '')] = getNodeValue(items[okey]);
        }
      }

      delete newItem['#text'];

      var newPost = {};

      newPost.title = convertEmpty(newItem.title);
      newPost.pubDate = convertEmpty(newItem.pubDate);
      newPost.creator = convertEmpty(newItem.creator); // == Author login
      newPost.description = convertEmpty(newItem.description); // Should be blank

      newPost.content = convertEmpty(newItem['content:encoded']); // Content of post
      newPost.caption = convertEmpty(newItem['excerpt:encoded']); // Apparently a caption of a file

      newPost.post_date = convertEmpty(newItem.post_date);
      newPost.post_date_gmt = convertEmpty(newItem.post_date_gmt);

      newPost.status = convertEmpty(newItem.status); // Can be 'publish', 'draft', 'pending', 'private', 'trash', ... 'inherit?'

      newPost.parent = convertEmpty(newItem.post_parent); // You can have nested posts, assume inherit = parent post
      newPost.menu_order = convertEmpty(newItem.menu_order); // Apparently the order in which to show up as a child

      newPost.attachment_url = convertEmpty(newItem.attachment_url);

      newPost.categories= categoryAndTags.categories; // Object or single item? Hard to tell
      newPost.tags = categoryAndTags.tags;

      newPost.sticky = convertEmpty(newItem.is_sticky);

      // Maybe parse out comments, but since we dont have commenting without a JS library on webhook, not sure if needed

      // For convienence later swap them into different keys
      // Post ID is used as the key to trace the parent relations between attachements and parent posts
      if(newItem.post_type === "attachment") {
        wordpressData.attachements[newItem.post_id] = newPost;
      } else if (newItem.post_type === "page") {
        wordpressData.pages[newItem.post_id] = newPost;
      } else {
        wordpressData.posts[newItem.post_id] = newPost;
      }
    }

    this.onConverterUpdated({ event: 'parsingXML', class: 'complete', running: false});

    callback(wordpressData);
  }

  // The getNodeValue function will sometimes return an empty object for various reasons (parsing, special cases),
  // this is the equivilant to an empty field really, so we just convert it to null
  var convertEmpty = function(val) {
    return $.isEmptyObject(val) ? null : val;
  };

  var getCategoryValue = function(node) {
    if(!node) {
      return null;
    }

    var extractInfo = function(n) {
      if(!n['@attributes']) {
        return { domain: 'category', nicename: convertEmpty(getNodeValue(n)), val: convertEmpty(getNodeValue(n))};
      }
      var domain = n['@attributes']['domain'];
      var nicename = n['@attributes']['nicename'];

      return { domain: domain, nicename: nicename, val: convertEmpty(getNodeValue(n)) };
    };

    var categories = {};
    var tags = {};
    var extracted = null;
    if(node instanceof Array) {

      node.forEach(function(item) {
        extracted = extractInfo(item);

        if(extracted.domain === 'category') {
          categories[extracted.nicename] = extracted.val;
        } else if (extracted.domain === 'post_tag') {
          tags[extracted.nicename] = extracted.val;
        }

      });

    } else {
      extracted = extractInfo(node);

      if(extracted.domain === 'category') {
        categories[extracted.nicename] = extracted.val;
      } else if (extracted.domain === 'post_tag') {
        tags[extracted.nicename] = extracted.val;
      }
    }

    return { categories: categories, tags: tags };
  };

  // Grab the node value from the JSON objects parsed from XML
  var getNodeValue = function(node) {
    if(!node) {
      return null;
    }

    // Sometimes the node is an array of nodes, parse each array value
    if(node instanceof Array) {
      var fixedArray = [];
      node.forEach(function(item) {
        fixedArray.push(getNodeValue(item));
      });

      return fixedArray;
    }

    // The xmlToJson function seperates the cdata and text values into different areas, seperate them
    if (typeof node === 'object' && '#cdata-section' in node) return node['#cdata-section'];
    if (typeof node === 'object' && '#text' in node) return node['#text'];

    // If it didnt work just throw it back, its most likely a simple data type
    return node;
  };

  // A function to convert XML to JSON, any conversion wont be 100% standard or accurate (due to limitations), but this is good
  // enough for Wordpress XML (need more test data to reach a good verification)
  xmlToJson = function(xml) {
    var obj = {};
    if (xml.nodeType == 1) {
        if (xml.attributes.length > 0) {
            obj["@attributes"] = {};
            for (var j = 0; j < xml.attributes.length; j++) {
                var attribute = xml.attributes.item(j);
                obj["@attributes"][attribute.nodeName] = attribute.nodeValue;
            }
        }
    } else if (xml.nodeType == 3) {
        obj = xml.nodeValue;
    } else if (xml.nodeType == 4) {
        obj = xml.nodeValue;
    }
    if (xml.hasChildNodes()) {
        for (var i = 0; i < xml.childNodes.length; i++) {
            var item = xml.childNodes.item(i);
            var nodeName = item.nodeName;

            if (typeof (obj[nodeName]) == "undefined") {
                obj[nodeName] = xmlToJson(item);
            } else {
                if (typeof (obj[nodeName].push) == "undefined") {
                    var old = obj[nodeName];
                    obj[nodeName] = [];
                    obj[nodeName].push(old);
                }
                obj[nodeName].push(xmlToJson(item));
            }
        }
    }
    return obj;
  }

  return {
    convert: parseWXML,
    onConverterUpdated: onConverterUpdated
  }
})();<|endoftext|>


<commit_before>/**
 * Copyright (c) 2017-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

const React = require('react');

class Footer extends React.Component {
    docUrl(doc, language) {
        const baseUrl = this.props.config.baseUrl;
        // return `${baseUrl}docs/${language ? `${language}/` : ''}${doc}`;
        return `${baseUrl}docs/${doc}`;
    }

    pageUrl(doc, language) {
        const baseUrl = this.props.config.baseUrl;
        // return baseUrl + (language ? `${language}/` : '') + doc;
        return baseUrl + doc;
    }

    render() {
        return (

                        {this.props.config.footerIcon && (

                        )}

Docs

                            Guide

                            Examples

                            Reference

Community

                        {/**/}
                        {/*User Showcase*/}
                        {/**/}

                            Stack Overflow

                        {/*Project Chat*/}

                            Twitter

                            Facebook

More

                        Apify Cloud
                        Docusaurus
                        GitHub

                {/**/}
                    {/*<img*/}
                        {/*src={`${this.props.config.baseUrl}img/docusaurus.svg`}*/}
                        {/*alt="Docusaurus"*/}
                        {/*width="80"*/}
                        {/*height="80"*/}
                    {/*/>*/}
                {/**/}

{this.props.config.copyright}

        );
    }
}

module.exports = Footer;
<commit_msg>Fix docs footer [skip ci]<commit_after>/**
 * Copyright (c) 2017-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

const React = require('react');

class Footer extends React.Component {
    docUrl(doc, language) {
        const baseUrl = this.props.config.baseUrl;
        // return `${baseUrl}docs/${language ? `${language}/` : ''}${doc}`;
        return `${baseUrl}docs/${doc}`;
    }

    pageUrl(doc, language) {
        const baseUrl = this.props.config.baseUrl;
        // return baseUrl + (language ? `${language}/` : '') + doc;
        return baseUrl + doc;
    }

    render() {
        return (

                        {this.props.config.footerIcon && (

                        )}

Docs

                            Guide

                            Examples

                            API Reference

Community

                        {/**/}
                        {/*User Showcase*/}
                        {/**/}

                            Stack Overflow

                        {/*Project Chat*/}

                            Twitter

                            Facebook

More

                        Apify Cloud
                        Docusaurus
                        GitHub

                {/**/}
                    {/*<img*/}
                        {/*src={`${this.props.config.baseUrl}img/docusaurus.svg`}*/}
                        {/*alt="Docusaurus"*/}
                        {/*width="80"*/}
                        {/*height="80"*/}
                    {/*/>*/}
                {/**/}

{this.props.config.copyright}

        );
    }
}

module.exports = Footer;
<|endoftext|>


<commit_before>require.config({
    shim: {
        "splunkjs/mvc/d3chart/d3/d3.v2": {
            deps: [],
            exports: "d3"
        },
        "testapp/contrib/cal-heatmap/cal-heatmap": {
            deps: ["splunkjs/mvc/d3chart/d3/d3.v2"],
            exports: "cal"
        }
    }
});

// calheat!
// shows a cool looking heatmap based on different time signatures
// requires a timechart search. it dynamically guesses how to set up the
// way to show the time, but you can define any settings you want in the html
// docs: http://kamisama.github.io/cal-heatmap

define(function(require, exports, module) {

    var _ = require('underscore');
    var d3 = require("splunkjs/mvc/d3chart/d3/d3.v2");
    var cal = require("testapp/contrib/cal-heatmap/cal-heatmap");
    var SimpleSplunkView = require("splunkjs/mvc/simplesplunkview");

    require("css!testapp/contrib/cal-heatmap/cal-heatmap.css");

    var calHeat = SimpleSplunkView.extend({

        className: "splunk-toolkit-cal-heatmap",

        options: {
            managerid: "search1",   // your MANAGER ID
            data: "preview",  // Results type

            options: {} // the default for custom heatmap options.
        },

        output_mode: "json",

        initialize: function() {
            _.extend(this.options, {
                formatName: _.identity,
                formatTitle: function(d) {
                    return (d.source.name + ' -> ' + d.target.name +
                            ': ' + d.value);
                }
            });
            SimpleSplunkView.prototype.initialize.apply(this, arguments);

            this.settings.enablePush("value");

            // whenever domain or subdomain are changed, we will re-render.
            this.settings.on("change:domain", this._onDataChanged, this);
            this.settings.on("change:subdomain", this._onDataChanged, this);
        },

        createView: function() {
            // for (var i=0; i<this.settings.get("maxSeries"); i++)
            //     this.$el.html("<button id='"+this.id+"-previous' class='btn' style='margin: 5px;'> Previous </button> <button id='"+this.id+"-next' class='btn' style='margin: 5px;'> Next </button>");
            return true;
        },

        // making the data look how we want it to for updateView to do its job
        formatData: function(data) {
            var maxSeries = this.settings.get('maxSeries')+1;
            var myfields = this.resultsModel.data().fields
            myfields = _.first(myfields, maxSeries+1);
            for (var i=0; i<myfields.length; i++) {
                myfields[i] = _.pick(myfields[i], 'name');
                myfields[i] = _.values(myfields[i]);
            }
            myfields = _.without(_.flatten(myfields), "_time");
            var myresults = this.resultsModel.data().results

            var domain = 'hour';
            var subdomain = 'min';

            if (data && data[0] != null) {
                if (parseInt(data[0]._span) > 60) {
                    domain = 'day';
                    subdomain = 'hour';
                }
                var formattedData = [];
                for(var i = 0; i < maxSeries; i++) {
                    formattedData.push({});
                }

                for(var i = 0; i < myresults.length; i++) {
                    var time = new Date(myresults[i]._time)
                    time = time.valueOf() / 1000
                    for(var j = 0; j < maxSeries; j++) {
                        var name = myfields[j];
                        var curObject = formattedData[j];
                        curObject[time] = myresults[i][name]
                    }
                }
                return {
                    timestamps: formattedData,
                    start: new Date(data[0]._time),
                    domain: domain,
                    subdomain: subdomain
                };
            }

            return null;
        },

        updateView: function(viz, data) {
            var that = this;
            userOptions = this.settings.get('options')
            var maxSeries = 3; //this.settings.get('maxSeries');
            var i = 0;

            this.$el.html('');
            console.log(data);
            // default options here.
            for (var i=0; i<maxSeries; i++) {
                $("
 <button id='previous-"+i+"' class='btn' style='margin: 5px;'> Previous </button> <button id='next-"+i+"' class='btn' style='margin: 5px;'> Next </button>
")
                    .appendTo(this.el)[0];
                options = _.extend({
                    itemSelector: $("
").appendTo(this.el)[0],
                    previousSelector: "#previous-"+i,
                    nextSelector: "#next-"+i,
                    data: data.timestamps[i],
                    domain: data.domain,
                    subdomain: data.subdomain,
                    start: data.start,
                    range: 4,
                    cellSize: 16,
                    cellPadding: 3,
                    domainGutter: 10,
                    highlight: ['now', new Date()],
                    legendMargin: [0, 0, 20, 0],
                    legendCellSize: 14,
                    onClick: function(date, value) {
                        that.settings.set("value", date.valueOf());
                    },
                }, userOptions)
                var cal = new CalHeatMap();

                cal.init(options); // create the calendar using either default or user defined options
            }
        }
    });
    return calHeat;
});<commit_msg>d3 directory change<commit_after>require.config({
    shim: {
        "testapp/contrib/d3chart/d3/d3.v2": {
            deps: [],
            exports: "d3"
        },
        "testapp/contrib/cal-heatmap/cal-heatmap": {
            deps: ["testapp/contrib/d3chart/d3/d3.v2"],
            exports: "cal"
        }
    }
});

// calheat!
// shows a cool looking heatmap based on different time signatures
// requires a timechart search. it dynamically guesses how to set up the
// way to show the time, but you can define any settings you want in the html
// docs: http://kamisama.github.io/cal-heatmap

define(function(require, exports, module) {

    var _ = require('underscore');
    var d3 = require("testapp/contrib/d3chart/d3/d3.v2");
    var cal = require("testapp/contrib/cal-heatmap/cal-heatmap");
    var SimpleSplunkView = require("splunkjs/mvc/simplesplunkview");

    require("css!testapp/contrib/cal-heatmap/cal-heatmap.css");

    var calHeat = SimpleSplunkView.extend({

        className: "splunk-toolkit-cal-heatmap",

        options: {
            managerid: "search1",   // your MANAGER ID
            data: "preview",  // Results type

            options: {} // the default for custom heatmap options.
        },

        output_mode: "json",

        initialize: function() {
            _.extend(this.options, {
                formatName: _.identity,
                formatTitle: function(d) {
                    return (d.source.name + ' -> ' + d.target.name +
                            ': ' + d.value);
                }
            });
            SimpleSplunkView.prototype.initialize.apply(this, arguments);

            this.settings.enablePush("value");

            // whenever domain or subdomain are changed, we will re-render.
            this.settings.on("change:domain", this._onDataChanged, this);
            this.settings.on("change:subdomain", this._onDataChanged, this);
        },

        createView: function() {
            // for (var i=0; i<this.settings.get("maxSeries"); i++)
            //     this.$el.html("<button id='"+this.id+"-previous' class='btn' style='margin: 5px;'> Previous </button> <button id='"+this.id+"-next' class='btn' style='margin: 5px;'> Next </button>");
            return true;
        },

        // making the data look how we want it to for updateView to do its job
        formatData: function(data) {
            var maxSeries = this.settings.get('maxSeries')+1;
            var myfields = this.resultsModel.data().fields
            myfields = _.first(myfields, maxSeries+1);
            for (var i=0; i<myfields.length; i++) {
                myfields[i] = _.pick(myfields[i], 'name');
                myfields[i] = _.values(myfields[i]);
            }
            myfields = _.without(_.flatten(myfields), "_time");
            var myresults = this.resultsModel.data().results

            var domain = 'hour';
            var subdomain = 'min';

            if (data && data[0] != null) {
                if (parseInt(data[0]._span) > 60) {
                    domain = 'day';
                    subdomain = 'hour';
                }
                var formattedData = [];
                for(var i = 0; i < maxSeries; i++) {
                    formattedData.push({});
                }

                for(var i = 0; i < myresults.length; i++) {
                    var time = new Date(myresults[i]._time)
                    time = time.valueOf() / 1000
                    for(var j = 0; j < maxSeries; j++) {
                        var name = myfields[j];
                        var curObject = formattedData[j];
                        curObject[time] = myresults[i][name]
                    }
                }
                return {
                    timestamps: formattedData,
                    start: new Date(data[0]._time),
                    domain: domain,
                    subdomain: subdomain
                };
            }

            return null;
        },

        updateView: function(viz, data) {
            var that = this;
            userOptions = this.settings.get('options')
            var maxSeries = 3; //this.settings.get('maxSeries');
            var i = 0;

            this.$el.html('');
            console.log(data);
            // default options here.
            for (var i=0; i<maxSeries; i++) {
                $("
 <button id='previous-"+i+"' class='btn' style='margin: 5px;'> Previous </button> <button id='next-"+i+"' class='btn' style='margin: 5px;'> Next </button>
")
                    .appendTo(this.el)[0];
                options = _.extend({
                    itemSelector: $("
").appendTo(this.el)[0],
                    previousSelector: "#previous-"+i,
                    nextSelector: "#next-"+i,
                    data: data.timestamps[i],
                    domain: data.domain,
                    subdomain: data.subdomain,
                    start: data.start,
                    range: 4,
                    cellSize: 16,
                    cellPadding: 3,
                    domainGutter: 10,
                    highlight: ['now', new Date()],
                    legendMargin: [0, 0, 20, 0],
                    legendCellSize: 14,
                    onClick: function(date, value) {
                        that.settings.set("value", date.valueOf());
                    },
                }, userOptions)
                var cal = new CalHeatMap();

                cal.init(options); // create the calendar using either default or user defined options
            }
        }
    });
    return calHeat;
});<|endoftext|>


<commit_before>import rangy from 'rangy'

import * as content from '../src/content'
import Cursor from '../src/cursor'
import Keyboard from '../src/keyboard'
import Editable from '../src/core'
import Selection from '../src/selection'
const {key} = Keyboard

describe('Dispatcher', function () {
  let editable, event, elem

  // create a Cursor object and set the selection to it
  function createCursor (range) {
    const cursor = new Cursor(elem, range)
    cursor.setSelection()
    return cursor
  }

  function createRangeAtEnd (node) {
    const range = rangy.createRange()
    range.selectNodeContents(node)
    range.collapse(false)
    return range
  }

  function createRangeAtBeginning (node) {
    const range = rangy.createRange()
    range.selectNodeContents(node)
    range.collapse(true)
    return range
  }

  function createSelection (range) {
    const selection = new Selection(elem, range)
    selection.setSelection()
    return selection
  }

  function createFullRange (node) {
    const range = rangy.createRange()
    range.selectNodeContents(node)
    return range
  }

  // register one listener per test
  function on (eventName, func) {
    // off() // make sure the last listener is unregistered
    const obj = {calls: 0}
    function proxy () {
      obj.calls += 1
      func.apply(this, arguments)
    }
    editable.on(eventName, proxy)
    return obj
  }

  describe('for editable', function () {

    beforeEach(function () {
      elem = document.createElement('div')
      elem.setAttribute('contenteditable', true)
      document.body.appendChild(elem)
      editable = new Editable()
      editable.add(elem)
      elem.focus()
    })

    afterEach(function () {
      elem.remove()
      editable.unload()
    })

    describe('on focus', function () {
      it('should trigger the focus event', function () {
        elem.blur()
        const focus = on('focus', function (element) {
          expect(element).toEqual(elem)
        })
        elem.focus()
        expect(focus.calls).toBe(1)
      })

      it('should contain an empty textnode', function () {
        elem.blur()
        expect(elem.textContent).toEqual('')
        elem.focus()
        expect(elem.textContent).toEqual('\u0000')
      })

      it('should not add an empty text node if there is content', function () {
        elem.blur()
        elem.appendChild(document.createTextNode('Hello'))
        elem.focus()
        expect(elem.textContent).toEqual('Hello')
      })

      it('removes the empty text node again on blur', function () {
        elem.focus()
        expect(elem.textContent).toEqual('\u0000')
        elem.blur()
        expect(elem.textContent).toEqual('')
      })
    })

    describe('on enter', function () {

      beforeEach(function () {
        event = new Event('keydown')
        event.keyCode = key.enter
      })

      it('fires insert "after" if cursor is at the end', function () {
        //
foo\

        elem.innerHTML = 'foo'
        createCursor(createRangeAtEnd(elem))

        const insert = on('insert', (element, direction, cursor) => {
          expect(element).toEqual(elem)
          expect(direction).toEqual('after')
          expect(cursor.isCursor).toEqual(true)
        })

        elem.dispatchEvent(event)
        expect(insert.calls).toEqual(1)
      })

      it('fires insert "before" if cursor is at the beginning', function () {
        //
|foo

        elem.innerHTML = 'foo'
        const range = rangy.createRange()
        range.selectNodeContents(elem)
        range.collapse(true)
        createCursor(range)

        const insert = on('insert', (element, direction, cursor) => {
          expect(element).toEqual(elem)
          expect(direction).toEqual('before')
          expect(cursor.isCursor).toEqual(true)
        })

        elem.dispatchEvent(event)
        expect(insert.calls).toEqual(1)
      })

      it('fires merge if cursor is in the middle', function () {
        //
fo|o

        elem.innerHTML = 'foo'
        const range = rangy.createRange()
        range.setStart(elem.firstChild, 2)
        range.setEnd(elem.firstChild, 2)
        createCursor(range)

        const insert = on('split', (element, before, after, cursor) => {
          expect(element).toEqual(elem)
          expect(content.getInnerHtmlOfFragment(before)).toEqual('fo')
          expect(content.getInnerHtmlOfFragment(after)).toEqual('o')
          expect(cursor.isCursor).toEqual(true)
        })

        elem.dispatchEvent(event)
        expect(insert.calls).toEqual(1)
      })
    })

    describe('on backspace', function () {

      beforeEach(function () {
        event = new Event('keydown')
        event.keyCode = key.backspace
      })

      it('fires "merge" if cursor is at the beginning', function (done) {
        elem.innerHTML = 'foo'
        createCursor(createRangeAtBeginning(elem))

        on('merge', (element) => {
          expect(element).toEqual(elem)
          done()
        })

        elem.dispatchEvent(event)
      })

      it('fires "change" if cursor is not at the beginning', (done) => {
        elem.innerHTML = 'foo'
        createCursor(createRangeAtEnd(elem))

        on('change', (element) => {
          expect(element).toEqual(elem)
          done()
        })

        elem.dispatchEvent(event)
      })
    })

    describe('on delete', function () {

      beforeEach(function () {
        event = new Event('keydown')
        event.keyCode = key['delete']
      })

      it('fires "merge" if cursor is at the end', (done) => {
        elem.innerHTML = 'foo'
        createCursor(createRangeAtEnd(elem))

        on('merge', (element) => {
          expect(element).toEqual(elem)
          done()
        })

        elem.dispatchEvent(event)
      })

      it('fires "change" if cursor is at the beginning', (done) => {
        elem.innerHTML = 'foo'
        createCursor(createRangeAtBeginning(elem))
        on('change', done)
        elem.dispatchEvent(event)
      })
    })

    describe('on keydown', function () {

      beforeEach(function () {
        event = new Event('keydown')
      })

      it('fires change when a character is pressed', (done) => {
        event.keyCode = 'e'.charCodeAt(0)
        on('change', done)
        elem.dispatchEvent(event)
      })
    })

    describe('on newline', function () {

      beforeEach(function () {
        event = new Event('keydown')
        event.shiftKey = true
        event.keyCode = 13
      })

      it('fires newline when shift + enter is pressed', (done) => {
        on('newline', done)
        elem.dispatchEvent(event)
      })
    })

    describe('on bold', function () {

      beforeEach(function () {
        event = new Event('keydown')
        event.ctrlKey = true
        event.keyCode = key.b
      })

      it('fires toggleBold when ctrl + b is pressed', (done) => {
        elem.innerHTML = 'foo'
        const elemSelection = createSelection(createFullRange(elem))

        on('toggleBold', (selection) => {
          expect(selection).toEqual(elemSelection)
          done()
        })

        elem.dispatchEvent(event)
      })
    })

    describe('on italic', function () {

      beforeEach(function () {
        event = new Event('keydown')
        event.ctrlKey = true
        event.keyCode = key.i
      })

      it('fires toggleEmphasis when ctrl + i is pressed', (done) => {
        elem.innerHTML = 'foo'
        const elemSelection = createSelection(createFullRange(elem))

        on('toggleEmphasis', (selection) => {
          expect(selection).toEqual(elemSelection)
          done()
        })

        elem.dispatchEvent(event)
      })
    })
  })
})
<commit_msg>chore: Write tests for the newline behavior<commit_after>import rangy from 'rangy'

import * as content from '../src/content'
import Cursor from '../src/cursor'
import Keyboard from '../src/keyboard'
import Editable from '../src/core'
import Selection from '../src/selection'
const {key} = Keyboard

describe('Dispatcher', function () {
  let editable, elem

  // create a Cursor object and set the selection to it
  function createCursor (range) {
    const cursor = new Cursor(elem, range)
    cursor.setSelection()
    return cursor
  }

  function createRangeAtEnd (node) {
    const range = rangy.createRange()
    range.selectNodeContents(node)
    range.collapse(false)
    return range
  }

  function createRangeAtBeginning (node) {
    const range = rangy.createRange()
    range.selectNodeContents(node)
    range.collapse(true)
    return range
  }

  function createSelection (range) {
    const selection = new Selection(elem, range)
    selection.setSelection()
    return selection
  }

  function createFullRange (node) {
    const range = rangy.createRange()
    range.selectNodeContents(node)
    return range
  }

  // register one listener per test
  function on (eventName, func) {
    // off() // make sure the last listener is unregistered
    const obj = {calls: 0}
    function proxy () {
      obj.calls += 1
      func.apply(this, arguments)
    }
    editable.on(eventName, proxy)
    return obj
  }

  describe('for editable', function () {

    beforeEach(function () {
      elem = document.createElement('div')
      elem.setAttribute('contenteditable', true)
      document.body.appendChild(elem)
      editable = new Editable()
      editable.add(elem)
      elem.focus()
    })

    afterEach(function () {
      elem.remove()
      editable.unload()
    })

    describe('on focus', function () {
      it('should trigger the focus event', function () {
        elem.blur()
        const focus = on('focus', function (element) {
          expect(element).toEqual(elem)
        })
        elem.focus()
        expect(focus.calls).toBe(1)
      })

      it('should contain an empty textnode', function () {
        elem.blur()
        expect(elem.textContent).toEqual('')
        elem.focus()
        expect(elem.textContent).toEqual('\u0000')
      })

      it('should not add an empty text node if there is content', function () {
        elem.blur()
        elem.appendChild(document.createTextNode('Hello'))
        elem.focus()
        expect(elem.textContent).toEqual('Hello')
      })

      it('removes the empty text node again on blur', function () {
        elem.focus()
        expect(elem.textContent).toEqual('\u0000')
        elem.blur()
        expect(elem.textContent).toEqual('')
      })
    })

    describe('on enter', function () {

      it('fires insert "after" if cursor is at the end', function () {
        //
foo\

        elem.innerHTML = 'foo'
        createCursor(createRangeAtEnd(elem))

        const insert = on('insert', (element, direction, cursor) => {
          expect(element).toEqual(elem)
          expect(direction).toEqual('after')
          expect(cursor.isCursor).toEqual(true)
        })

        const evt = new KeyboardEvent('keydown', {keyCode: key.enter})
        elem.dispatchEvent(evt)
        expect(insert.calls).toEqual(1)
      })

      it('fires insert "before" if cursor is at the beginning', function () {
        //
|foo

        elem.innerHTML = 'foo'
        const range = rangy.createRange()
        range.selectNodeContents(elem)
        range.collapse(true)
        createCursor(range)

        const insert = on('insert', (element, direction, cursor) => {
          expect(element).toEqual(elem)
          expect(direction).toEqual('before')
          expect(cursor.isCursor).toEqual(true)
        })

        const evt = new KeyboardEvent('keydown', {keyCode: key.enter})
        elem.dispatchEvent(evt)
        expect(insert.calls).toEqual(1)
      })

      it('fires merge if cursor is in the middle', function () {
        //
fo|o

        elem.innerHTML = 'foo'
        const range = rangy.createRange()
        range.setStart(elem.firstChild, 2)
        range.setEnd(elem.firstChild, 2)
        createCursor(range)

        const insert = on('split', (element, before, after, cursor) => {
          expect(element).toEqual(elem)
          expect(content.getInnerHtmlOfFragment(before)).toEqual('fo')
          expect(content.getInnerHtmlOfFragment(after)).toEqual('o')
          expect(cursor.isCursor).toEqual(true)
        })

        const evt = new KeyboardEvent('keydown', {keyCode: key.enter})
        elem.dispatchEvent(evt)
        expect(insert.calls).toEqual(1)
      })
    })

    describe('on backspace', function () {

      it('fires "merge" if cursor is at the beginning', function (done) {
        elem.innerHTML = 'foo'
        createCursor(createRangeAtBeginning(elem))

        on('merge', (element) => {
          expect(element).toEqual(elem)
          done()
        })

        elem.dispatchEvent(new KeyboardEvent('keydown', {keyCode: key.backspace}))
      })

      it('fires "change" if cursor is not at the beginning', (done) => {
        elem.innerHTML = 'foo'
        createCursor(createRangeAtEnd(elem))

        on('change', (element) => {
          expect(element).toEqual(elem)
          done()
        })

        elem.dispatchEvent(new KeyboardEvent('keydown', {keyCode: key.backspace}))
      })
    })

    describe('on delete', function () {

      it('fires "merge" if cursor is at the end', (done) => {
        elem.innerHTML = 'foo'
        createCursor(createRangeAtEnd(elem))

        on('merge', (element) => {
          expect(element).toEqual(elem)
          done()
        })

        elem.dispatchEvent(new KeyboardEvent('keydown', {keyCode: key.delete}))
      })

      it('fires "change" if cursor is at the beginning', (done) => {
        elem.innerHTML = 'foo'
        createCursor(createRangeAtBeginning(elem))
        on('change', done)
        elem.dispatchEvent(new KeyboardEvent('keydown', {keyCode: key.delete}))
      })
    })

    describe('on keydown', function () {

      it('fires change when a character is pressed', (done) => {
        const evt = new KeyboardEvent('keydown', {keyCode: 'e'.charCodeAt(0)})
        on('change', done)
        elem.dispatchEvent(evt)
      })
    })

    fdescribe('on newline', function () {

      function typeKeys (element, chars) {
        const selection = window.getSelection()
        const range = selection.getRangeAt(0)
        range.selectNodeContents(element)
        range.collapse(false)
        range.insertNode(document.createTextNode(chars))
        range.selectNodeContents(element)
        range.collapse(false)
      }

      function shiftReturn (element) {
        element.dispatchEvent(new KeyboardEvent('keydown', {
          shiftKey: true,
          keyCode: 13
        }))
      }

      it('fires newline when shift + enter is pressed', (done) => {
        on('newline', done)
        shiftReturn(elem)
        expect(elem.innerHTML).toEqual('
\u0000')
      })

      it('creates a nested br element with a data-editable="unwrap" attribute', () => {
        typeKeys(elem, 'foobar')
        shiftReturn(elem)
        expect(elem.innerHTML).toEqual(
          `\u0000` +
          `foobar` +
          `<span data-editable="unwrap">` +
            `<br><span data-editable="remove" contenteditable="false">\u0000</span>` +
          `</span>`
        )
      })

      it('removes the nested br element when adding a newline afterwards', () => {
        typeKeys(elem, 'foobar')
        shiftReturn(elem)
        shiftReturn(elem)
        expect(elem.innerHTML).toEqual(
          `\u0000` +
          `foobar` +
          // this is the nested br element that got unwrapped
          `<br>` +
          // This is the new nested newline of the second shift + return
          `<span data-editable="unwrap">` +
            `<br><span data-editable="remove" contenteditable="false">\u0000</span>` +
          `</span>`
        )
      })
    })

    describe('on bold', function () {

      it('fires toggleBold when ctrl + b is pressed', (done) => {
        elem.innerHTML = 'foo'
        const elemSelection = createSelection(createFullRange(elem))

        on('toggleBold', (selection) => {
          expect(selection).toEqual(elemSelection)
          done()
        })

        const evt = new KeyboardEvent('keydown', {ctrlKey: true, keyCode: key.b})
        elem.dispatchEvent(evt)
      })
    })

    describe('on italic', function () {

      it('fires toggleEmphasis when ctrl + i is pressed', (done) => {
        elem.innerHTML = 'foo'
        const elemSelection = createSelection(createFullRange(elem))

        on('toggleEmphasis', (selection) => {
          expect(selection).toEqual(elemSelection)
          done()
        })

        const evt = new KeyboardEvent('keydown', {ctrlKey: true, keyCode: key.i})
        elem.dispatchEvent(evt)
      })
    })
  })
})
<|endoftext|>


<commit_before>(function(bespoke) {

  bespoke.plugins.oridomi = function(deck, options) {
    var oridomi_options = {
      speed:           700,   // folding duration in ms
      ripple:          0,      // backwards ripple effect when animating
      shadingIntesity: 1,    // lessen the shading effect
      perspective:     1000,    // smaller values exaggerate 3D distortion
      maxAngle:        90,     // keep the user's folds within a range of -40 to 40 degrees
      shading:         'hard', // change the shading type,
      touchEnabled:    false
    };

    // override default values with incoming options
    if(options.hasOwnProperty('oridomi_options')) {
      for(var option in options.oridomi_options) {
        oridomi_options[option] = options.oridomi_options[option];
      }
    }
    var slide_count = 0;
		var oridomi_slides = deck.slides.map(function(slide) {
      var cloned_slide = slide.cloneNode(true);
      var oridomi_container = document.createElement('div');
      var oridomi;
      oridomi_container.classList.add('oridomi_container');
      oridomi_container.appendChild(cloned_slide);
      slide.innerHTML = "";
      slide.appendChild(oridomi_container);

      oridomi = new OriDomi(oridomi_container, oridomi_options);
      oridomi.setSpeed(0);
      if(slide_count > 0) {
        oridomi.accordion(100);
        oridomi.setSpeed(oridomi_options.speed);
      }
      slide_count++;
      return oridomi;
		}, oridomi_options);

    deck.on('activate', function(event) {
      var current_slide_folder = oridomi_slides[event.index];
      current_slide_folder.reset();
    });

    deck.on('next', function(event) {
      if(event.index < deck.slides.length-1) {
        var current_slide_folder = oridomi_slides[event.index];
        current_slide_folder.foldUp(4, function(event) {
        });
      }
    });

    deck.on('prev', function(event) {
      if(event.index != 0) {
        var current_slide_folder = oridomi_slides[event.index];
        current_slide_folder.foldUp(2, function(event) {
        });
      }
    });
  };
}(bespoke));
<commit_msg>Fixes first time transitions<commit_after>(function(bespoke) {

  bespoke.plugins.oridomi = function(deck, options) {
    var oridomi_options = {
      speed:           700,   // folding duration in ms
      ripple:          0,      // backwards ripple effect when animating
      shadingIntesity: 1,    // lessen the shading effect
      perspective:     1000,    // smaller values exaggerate 3D distortion
      maxAngle:        90,     // keep the user's folds within a range of -40 to 40 degrees
      shading:         'hard', // change the shading type,
      touchEnabled:    false
    };

    // override default values with incoming options
    if(options.hasOwnProperty('oridomi_options')) {
      for(var option in options.oridomi_options) {
        oridomi_options[option] = options.oridomi_options[option];
      }
    }
    var slide_count = 0;
		var oridomi_slides = deck.slides.map(function(slide) {
      var cloned_slide = slide.cloneNode(true);
      var oridomi_container = document.createElement('div');
      var oridomi;
      oridomi_container.classList.add('oridomi_container');
      oridomi_container.appendChild(cloned_slide);
      slide.innerHTML = "";
      slide.appendChild(oridomi_container);

      oridomi = new OriDomi(oridomi_container, oridomi_options);
      oridomi.setSpeed(0);
      if(slide_count > 0) {
        oridomi.foldUp(2);
        oridomi.setSpeed(oridomi_options.speed);
      }
      slide_count++;
      return oridomi;
		}, oridomi_options);

    deck.on('activate', function(event) {
      var current_slide_folder = oridomi_slides[event.index];
      current_slide_folder.reset();
    });

    deck.on('next', function(event) {
      if(event.index < deck.slides.length-1) {
        var current_slide_folder = oridomi_slides[event.index];
        current_slide_folder.foldUp(4, function(event) {
        });
      }
    });

    deck.on('prev', function(event) {
      if(event.index != 0) {
        var current_slide_folder = oridomi_slides[event.index];
        current_slide_folder.foldUp(2, function(event) {
        });
      }
    });
  };
}(bespoke));
<|endoftext|>


<commit_before>
var skiff = require('./lib/skiff'), // this must be required first
  rollbar = skiff.rollbar,
  sails = skiff.sails,
  moment = require('moment'),
  Changes = require('./lib/community/changes'),
  Digest = require('./lib/community/digest');

require('moment-timezone');

var sendDailyDigests = function() {
  sails.log.info('Sending daily digests');

  var today = now.clone().startOf('day'),
    yesterday = today.clone().subtract(1, 'day');

  Changes.changedCommunities(yesterday, today)
  .then(function(communityIds) {
    return Community.query(function(qb) {
      qb.whereIn('id', communityIds);
    }).fetchAll();
  })
  .then(function(communities) {
    return Promise.map(communities, function(community) {
      var dg = new Digest(community, yesterday, today);
      dg.fetchData().then(dg.queueEmails.bind(dg));
    });
  });

};

var intervals = {

  daily: function() {
    sails.log.info('noop!');
  },

  hourly: function() {
    var now = moment.tz('America/Los_Angeles');

    switch (now.hour()) {
      case 12:
        sendDailyDigests();
        break;
    }
  },

  every10minutes: function() {
    sails.log.info('noop!');
  }

}

skiff.lift({
  start: function(argv) {
    sails.log.info('running ' + argv.interval + ' job');
    intervals[argv.interval]();
    skiff.lower();
  }
});
<commit_msg>fix bug from refactoring<commit_after>
var skiff = require('./lib/skiff'), // this must be required first
  rollbar = skiff.rollbar,
  sails = skiff.sails,
  moment = require('moment'),
  Changes = require('./lib/community/changes'),
  Digest = require('./lib/community/digest');

require('moment-timezone');

var sendDailyDigests = function() {
  sails.log.info('Sending daily digests');

  var today = moment.tz('America/Los_Angeles').clone().startOf('day'),
    yesterday = today.clone().subtract(1, 'day');

  Changes.changedCommunities(yesterday, today)
  .then(function(communityIds) {
    return Community.query(function(qb) {
      qb.whereIn('id', communityIds);
    }).fetchAll();
  })
  .then(function(communities) {
    return Promise.map(communities, function(community) {
      var dg = new Digest(community, yesterday, today);
      dg.fetchData().then(dg.queueEmails.bind(dg));
    });
  });

};

var intervals = {

  daily: function() {
    sails.log.info('noop!');
  },

  hourly: function() {
    var now = moment.tz('America/Los_Angeles');

    switch (now.hour()) {
      case 12:
        sendDailyDigests();
        break;
    }
  },

  every10minutes: function() {
    sails.log.info('noop!');
  }

}

skiff.lift({
  start: function(argv) {
    sails.log.info('running ' + argv.interval + ' job');
    intervals[argv.interval]();
    skiff.lower();
  }
});
<|endoftext|>


<commit_before>define(['sprd/entity/DesignConfiguration', "sprd/util/ProductUtil", "js/core/Bindable", 'pimp/data/PimpImageService', "sprd/entity/Size", 'sprd/data/ImageUploadService', "flow", 'sprd/util/UnitUtil'], function (DesignConfiguration, ProductUtil, Bindable, PimpImageService, Size, ImageUploadService, flow, UnitUtil) {

    return DesignConfiguration.inherit('sprd.model.SpecialTextConfiguration', {

        defaults: {
            text: null,
            font: null,
            _size: Size,
            aspectRatio: 1,
            previewImageUrl: null,
            _allowScale: true,
            loading: false,
            align: null,
            initialized: false
        },

        type: "specialText",

        inject: {
            pimpImageService: PimpImageService
        },

        ctor: function () {
            this.$designCache = {};
            this.callBase();
        },

        /***
         * saves assets asynchronously
         * @param callback
         */
        save: function (callback) {

            var self = this,
                cacheId = [self.$.text, self.$.align, self.get("font.id")].join("#");

            flow()
                .seq("design", function (cb) {

                    if (self.$designCache.hasOwnProperty(cacheId)) {
                        cb(null, self.$designCache[cacheId]);
                    } else {
                        // create a full font size image
                        self.$.pimpImageService.generateDesign({
                            text: self.$.text,
                            font: self.$.font
                        }, cb);
                    }

                })
                .seq(function () {

                    var design = this.vars.design;

                    self.$designCache[cacheId] = design;
                    self.set("design", design);
                })
                .exec(callback);
        },

        _commitChangedAttributes: function ($) {
            this.callBase();

            if (!this.$.initialized) {
                return;
            }

            if (this._hasSome($, ["pimpImageService", "text", "font"])) {
                var self = this;
                var oldSize = this.$._size;
                this.fetchImage(function () {
                    self.$.offset.set('x', self.$.offset.$.x + 0.5 * self.$.scale.x * (oldSize.$.width - self.$._size.$.width));
                });
            }
        },

        fetchImage: function (callback) {
            var self = this,
                text = this.$.text,
                font = this.$.font,
                pimpImageService = this.$.pimpImageService;

            if (pimpImageService && text && font) {
                this.set('loading', true);
                pimpImageService.generateImage({
                    text: text,
                    size: "M",
                    font: font
                }, function (err, data) {
                    if (!err) {

                        var width = (parseInt(data.width) || 1) * 4,
                            height = (parseInt(data.height) || 1) * 4;

                        var size = UnitUtil.convertSizeToMm(new Size({width: width, height: height, unit: "px"}), self.$.printType.$.dpi);

                        self.set({
                            "previewImageUrl": (data || {}).src,
                            "_size": size
                        });
                    } else {
                        self.set('previewImageUrl', null);
                    }

                    self.set('loading', false);
                    callback && callback(err);
                });
            }
        },

        init: function (callback) {

            this.synchronizeFunctionCall(function (callback) {

                var self = this;

                flow()
                    .seq(function (cb) {
                        DesignConfiguration.prototype.init.call(self, cb);
                    })
                    .seq(function () {
                        var printType = self.$.printType,
                            design = self.$.design;

                        if (design) {

                            var split = design.$.name.split(";");
                            self.set({
                                font: {
                                    $: {
                                        id: split[1]
                                    }
                                },
                                align: split
                            }, {
                                silent: true
                            });

                            if (design.$.size && printType && printType.$.dpi) {
                                var dpi = printType.$.dpi;
                                self.set("_size", UnitUtil.convertSizeToMm(design.$.size, dpi), {
                                    silent: true
                                });
                            }
                        }
                    })
                    .seq(function (cb) {
                        self.fetchImage(function () {
                            cb();
                        });
                    })
                    .exec(function (err) {
                        self.set("initialized", true);
                        callback(err);
                    });

            }, "init", callback, this);

        },

        height: function (scale) {
            return this.callBase(scale);
        }.onChange("_size"),

        width: function (scale) {
            return this.callBase(scale);
        }.onChange("_size"),

        size: function () {
            return this.$._size;
        }.onChange("_size"),

        getPossiblePrintTypes: function (appearance) {
            var ret = [],
                printArea = this.$.printArea,
                design = this.$.design;

            if (printArea && appearance && design) {
                ret = ProductUtil.getPossiblePrintTypesForSpecialText(printArea, appearance.$.id);
            }

            return ret;
        }

            .
            onChange("printArea"),

        getSizeForPrintType: function (printType) {
            if (printType && printType.$.dpi) {
                var dpi = printType.$.dpi;
                return UnitUtil.convertSizeToMm(this.$._size, dpi);
            }

            return Size.empty;
        },

        isAllowedOnPrintArea: function (printArea) {
            return printArea && printArea.get("restrictions.designAllowed") == true &&
                printArea.get("restrictions.textAllowed") == true;
        },

        getPossiblePrintTypesForPrintArea: function (printArea, appearanceId) {
            return ProductUtil.getPossiblePrintTypesForSpecialText(printArea, appearanceId);
        },

        minimumScale: function () {
            // TODO:
            return this.callBase();
        }
    });
});<commit_msg>use commissions for SpecialTextConfiguration<commit_after>define(['sprd/entity/DesignConfiguration', "sprd/util/ProductUtil", "js/core/Bindable", 'pimp/data/PimpImageService', "sprd/entity/Size", 'sprd/data/ImageUploadService', "flow", 'sprd/util/UnitUtil', 'pimp/data/PimpDataSourceClass', 'js/data/Collection', 'pimp/model/Commission'], function (DesignConfiguration, ProductUtil, Bindable, PimpImageService, Size, ImageUploadService, flow, UnitUtil, PimpDataSourceClass, Collection, Commission) {

    return DesignConfiguration.inherit('sprd.model.SpecialTextConfiguration', {

        defaults: {
            text: null,
            font: null,
            _size: Size,
            aspectRatio: 1,
            previewImageUrl: null,
            _allowScale: true,
            loading: false,
            align: null,
            initialized: false,
            commission: null
        },

        type: "specialText",

        inject: {
            pimpImageService: PimpImageService,
            pimpDataSource: PimpDataSourceClass,
            context: "context"
        },

        _postConstruct: function() {
            this.callBase();
            this.fetchCommissions();
        },

        ctor: function () {
            this.$designCache = {};
            this.callBase();
        },

        /***
         * saves assets asynchronously
         * @param callback
         */
        save: function (callback) {

            var self = this,
                cacheId = [self.$.text, self.$.align, self.get("font.id")].join("#");

            flow()
                .seq("design", function (cb) {

                    if (self.$designCache.hasOwnProperty(cacheId)) {
                        cb(null, self.$designCache[cacheId]);
                    } else {
                        // create a full font size image
                        self.$.pimpImageService.generateDesign({
                            text: self.$.text,
                            font: self.$.font
                        }, cb);
                    }

                })
                .seq(function () {

                    var design = this.vars.design;

                    self.$designCache[cacheId] = design;
                    self.set("design", design);
                })
                .exec(callback);
        },

        _commitChangedAttributes: function ($) {
            this.callBase();

            if (!this.$.initialized) {
                return;
            }

            if (this._hasSome($, ["pimpImageService", "text", "font"])) {
                var self = this;
                var oldSize = this.$._size;
                this.fetchImage(function () {
                    self.$.offset.set('x', self.$.offset.$.x + 0.5 * self.$.scale.x * (oldSize.$.width - self.$._size.$.width));
                });
            }
        },

        fetchImage: function (callback) {
            var self = this,
                text = this.$.text,
                font = this.$.font,
                pimpImageService = this.$.pimpImageService;

            if (pimpImageService && text && font) {
                this.set('loading', true);
                pimpImageService.generateImage({
                    text: text,
                    size: "M",
                    font: font
                }, function (err, data) {
                    if (!err) {

                        var width = (parseInt(data.width) || 1) * 4,
                            height = (parseInt(data.height) || 1) * 4;

                        var size = UnitUtil.convertSizeToMm(new Size({width: width, height: height, unit: "px"}), self.$.printType.$.dpi);

                        self.set({
                            "previewImageUrl": (data || {}).src,
                            "_size": size
                        });
                    } else {
                        self.set('previewImageUrl', null);
                    }

                    self.set('loading', false);
                    callback && callback(err);
                });
            }
        },

        init: function (callback) {

            this.synchronizeFunctionCall(function (callback) {

                var self = this;

                flow()
                    .seq(function (cb) {
                        DesignConfiguration.prototype.init.call(self, cb);
                    })
                    .seq(function () {
                        var printType = self.$.printType,
                            design = self.$.design;

                        if (design) {

                            var split = design.$.name.split(";");
                            self.set({
                                font: {
                                    $: {
                                        id: split[1]
                                    }
                                },
                                align: split
                            }, {
                                silent: true
                            });

                            if (design.$.size && printType && printType.$.dpi) {
                                var dpi = printType.$.dpi;
                                self.set("_size", UnitUtil.convertSizeToMm(design.$.size, dpi), {
                                    silent: true
                                });
                            }
                        }
                    })
                    .seq(function (cb) {
                        self.fetchImage(function () {
                            cb();
                        });
                    })
                    .exec(function (err) {
                        self.set("initialized", true);
                        callback(err);
                    });

            }, "init", callback, this);

        },

        price: function() {
            var price = this.callBase(),
                _designCommission = this.get("design.price") || this.get("commission.price");

            if (_designCommission) {
                price.add(_designCommission);
            } else {
                this.fetchCommissions();
            }

            return price;
        }.onChange("_printTypePrice", "commission"),

        fetchCommissions: function() {

            var self = this,
                contextCurrency = this.get("context.currency.id");
            this.synchronizeFunctionCall(function(callback) {

                this.$.pimpDataSource.createCollection(Collection.of(Commission)).fetch(null, function (err, collection) {
                    var commission;
                    if (!err) {
                        commission = collection.find(function (commission) {
                            return commission.get("price.currency.id") === contextCurrency;
                        });
                    }

                    self.set("commission", commission);
                    self.trigger("priceChanged");

                    callback(err, commission);
                });

            }, "commissions", null, this);

        },

        height: function (scale) {
            return this.callBase(scale);
        }.onChange("_size"),

        width: function (scale) {
            return this.callBase(scale);
        }.onChange("_size"),

        size: function () {
            return this.$._size;
        }.onChange("_size"),

        getPossiblePrintTypes: function (appearance) {
            var ret = [],
                printArea = this.$.printArea,
                design = this.$.design;

            if (printArea && appearance && design) {
                ret = ProductUtil.getPossiblePrintTypesForSpecialText(printArea, appearance.$.id);
            }

            return ret;
        }.onChange("printArea"),

        getSizeForPrintType: function (printType) {
            if (printType && printType.$.dpi) {
                var dpi = printType.$.dpi;
                return UnitUtil.convertSizeToMm(this.$._size, dpi);
            }

            return Size.empty;
        },

        isAllowedOnPrintArea: function (printArea) {
            return printArea && printArea.get("restrictions.designAllowed") == true &&
                printArea.get("restrictions.textAllowed") == true;
        },

        getPossiblePrintTypesForPrintArea: function (printArea, appearanceId) {
            return ProductUtil.getPossiblePrintTypesForSpecialText(printArea, appearanceId);
        },

        minimumScale: function () {
            // TODO:
            return this.callBase();
        }
    });
});<|endoftext|>


<commit_before>/**
 * @module ol/renderer/canvas/VectorImageLayer
 */
import CanvasImageLayerRenderer from './ImageLayer.js';
import CanvasVectorLayerRenderer from './VectorLayer.js';
import EventType from '../../events/EventType.js';
import ImageCanvas from '../../ImageCanvas.js';
import ImageState from '../../ImageState.js';
import RBush from 'rbush';
import ViewHint from '../../ViewHint.js';
import {apply, compose, create} from '../../transform.js';
import {assign} from '../../obj.js';
import {getHeight, getWidth, isEmpty, scaleFromCenter} from '../../extent.js';

/**
 * @classdesc
 * Canvas renderer for image layers.
 * @api
 */
class CanvasVectorImageLayerRenderer extends CanvasImageLayerRenderer {
  /**
   * @param {import("../../layer/VectorImage.js").default} layer Vector image layer.
   */
  constructor(layer) {
    super(layer);

    /**
     * @private
     * @type {import("./VectorLayer.js").default}
     */
    this.vectorRenderer_ = new CanvasVectorLayerRenderer(layer);

    /**
     * @private
     * @type {number}
     */
    this.layerImageRatio_ = layer.getImageRatio();

    /**
     * @private
     * @type {import("../../transform.js").Transform}
     */
    this.coordinateToVectorPixelTransform_ = create();

    /**
     * @private
     * @type {import("../../transform.js").Transform}
     */
    this.renderedPixelToCoordinateTransform_ = null;
  }

  /**
   * Clean up.
   */
  disposeInternal() {
    this.vectorRenderer_.dispose();
    super.disposeInternal();
  }

  /**
   * Asynchronous layer level hit detection.
   * @param {import("../../pixel.js").Pixel} pixel Pixel.
   * @return {Promise<Array<import("../../Feature").default>>} Promise that resolves with an array of features.
   */
  getFeatures(pixel) {
    if (!this.vectorRenderer_) {
      return new Promise((resolve) => resolve([]));
    }
    const vectorPixel = apply(
      this.coordinateToVectorPixelTransform_,
      apply(this.renderedPixelToCoordinateTransform_, pixel.slice())
    );
    return this.vectorRenderer_.getFeatures(vectorPixel);
  }

  /**
   * Perform action necessary to get the layer rendered after new fonts have loaded
   */
  handleFontsChanged() {
    this.vectorRenderer_.handleFontsChanged();
  }

  /**
   * Determine whether render should be called.
   * @param {import("../../PluggableMap.js").FrameState} frameState Frame state.
   * @return {boolean} Layer is ready to be rendered.
   */
  prepareFrame(frameState) {
    const pixelRatio = frameState.pixelRatio;
    const viewState = frameState.viewState;
    const viewResolution = viewState.resolution;

    const hints = frameState.viewHints;
    const vectorRenderer = this.vectorRenderer_;
    let renderedExtent = frameState.extent;
    if (this.layerImageRatio_ !== 1) {
      renderedExtent = renderedExtent.slice(0);
      scaleFromCenter(renderedExtent, this.layerImageRatio_);
    }
    const width = getWidth(renderedExtent) / viewResolution;
    const height = getHeight(renderedExtent) / viewResolution;

    if (
      !hints[ViewHint.ANIMATING] &&
      !hints[ViewHint.INTERACTING] &&
      !isEmpty(renderedExtent)
    ) {
      vectorRenderer.useContainer(null, null, 1);
      const context = vectorRenderer.context;
      const imageFrameState =
        /** @type {import("../../PluggableMap.js").FrameState} */ (
          assign({}, frameState, {
            declutterTree: new RBush(9),
            extent: renderedExtent,
            size: [width, height],
            viewState: /** @type {import("../../View.js").State} */ (
              assign({}, frameState.viewState, {
                rotation: 0,
              })
            ),
          })
        );
      const image = new ImageCanvas(
        renderedExtent,
        viewResolution,
        pixelRatio,
        context.canvas,
        function (callback) {
          if (
            vectorRenderer.prepareFrame(imageFrameState) &&
            vectorRenderer.replayGroupChanged
          ) {
            vectorRenderer.clipping = false;
            vectorRenderer.renderFrame(imageFrameState, null);
            vectorRenderer.renderDeclutter(imageFrameState);
            callback();
          }
        }
      );

      image.addEventListener(
        EventType.CHANGE,
        function () {
          if (image.getState() === ImageState.LOADED) {
            this.image_ = image;
            const imageResolution = image.getResolution();
            const imagePixelRatio = image.getPixelRatio();
            const renderedResolution =
              (imageResolution * pixelRatio) / imagePixelRatio;
            this.renderedResolution = renderedResolution;
            this.coordinateToVectorPixelTransform_ = compose(
              this.coordinateToVectorPixelTransform_,
              width / 2,
              height / 2,
              1 / renderedResolution,
              -1 / renderedResolution,
              0,
              -viewState.center[0],
              -viewState.center[1]
            );
          }
        }.bind(this)
      );
      image.load();
    }

    if (this.image_) {
      this.renderedPixelToCoordinateTransform_ =
        frameState.pixelToCoordinateTransform.slice();
    }

    return !!this.image_;
  }

  /**
   */
  preRender() {}

  /**
   */
  postRender() {}

  /**
   */
  renderDeclutter() {}

  /**
   * @param {import("../../coordinate.js").Coordinate} coordinate Coordinate.
   * @param {import("../../PluggableMap.js").FrameState} frameState Frame state.
   * @param {number} hitTolerance Hit tolerance in pixels.
   * @param {import("../vector.js").FeatureCallback<T>} callback Feature callback.
   * @param {Array<import("../Map.js").HitMatch<T>>} matches The hit detected matches with tolerance.
   * @return {T|undefined} Callback result.
   * @template T
   */
  forEachFeatureAtCoordinate(
    coordinate,
    frameState,
    hitTolerance,
    callback,
    matches
  ) {
    if (this.vectorRenderer_) {
      return this.vectorRenderer_.forEachFeatureAtCoordinate(
        coordinate,
        frameState,
        hitTolerance,
        callback,
        matches
      );
    } else {
      return super.forEachFeatureAtCoordinate(
        coordinate,
        frameState,
        hitTolerance,
        callback,
        matches
      );
    }
  }
}

export default CanvasVectorImageLayerRenderer;
<commit_msg>Fix rendering VectorImage with no features in view extent<commit_after>/**
 * @module ol/renderer/canvas/VectorImageLayer
 */
import CanvasImageLayerRenderer from './ImageLayer.js';
import CanvasVectorLayerRenderer from './VectorLayer.js';
import EventType from '../../events/EventType.js';
import ImageCanvas from '../../ImageCanvas.js';
import ImageState from '../../ImageState.js';
import RBush from 'rbush';
import ViewHint from '../../ViewHint.js';
import {apply, compose, create} from '../../transform.js';
import {assign} from '../../obj.js';
import {getHeight, getWidth, isEmpty, scaleFromCenter} from '../../extent.js';

/**
 * @classdesc
 * Canvas renderer for image layers.
 * @api
 */
class CanvasVectorImageLayerRenderer extends CanvasImageLayerRenderer {
  /**
   * @param {import("../../layer/VectorImage.js").default} layer Vector image layer.
   */
  constructor(layer) {
    super(layer);

    /**
     * @private
     * @type {import("./VectorLayer.js").default}
     */
    this.vectorRenderer_ = new CanvasVectorLayerRenderer(layer);

    /**
     * @private
     * @type {number}
     */
    this.layerImageRatio_ = layer.getImageRatio();

    /**
     * @private
     * @type {import("../../transform.js").Transform}
     */
    this.coordinateToVectorPixelTransform_ = create();

    /**
     * @private
     * @type {import("../../transform.js").Transform}
     */
    this.renderedPixelToCoordinateTransform_ = null;
  }

  /**
   * Clean up.
   */
  disposeInternal() {
    this.vectorRenderer_.dispose();
    super.disposeInternal();
  }

  /**
   * Asynchronous layer level hit detection.
   * @param {import("../../pixel.js").Pixel} pixel Pixel.
   * @return {Promise<Array<import("../../Feature").default>>} Promise that resolves with an array of features.
   */
  getFeatures(pixel) {
    if (!this.vectorRenderer_) {
      return new Promise((resolve) => resolve([]));
    }
    const vectorPixel = apply(
      this.coordinateToVectorPixelTransform_,
      apply(this.renderedPixelToCoordinateTransform_, pixel.slice())
    );
    return this.vectorRenderer_.getFeatures(vectorPixel);
  }

  /**
   * Perform action necessary to get the layer rendered after new fonts have loaded
   */
  handleFontsChanged() {
    this.vectorRenderer_.handleFontsChanged();
  }

  /**
   * Determine whether render should be called.
   * @param {import("../../PluggableMap.js").FrameState} frameState Frame state.
   * @return {boolean} Layer is ready to be rendered.
   */
  prepareFrame(frameState) {
    const pixelRatio = frameState.pixelRatio;
    const viewState = frameState.viewState;
    const viewResolution = viewState.resolution;

    const hints = frameState.viewHints;
    const vectorRenderer = this.vectorRenderer_;
    let renderedExtent = frameState.extent;
    if (this.layerImageRatio_ !== 1) {
      renderedExtent = renderedExtent.slice(0);
      scaleFromCenter(renderedExtent, this.layerImageRatio_);
    }
    const width = getWidth(renderedExtent) / viewResolution;
    const height = getHeight(renderedExtent) / viewResolution;

    if (
      !hints[ViewHint.ANIMATING] &&
      !hints[ViewHint.INTERACTING] &&
      !isEmpty(renderedExtent)
    ) {
      vectorRenderer.useContainer(null, null, 1);
      const context = vectorRenderer.context;
      const imageFrameState =
        /** @type {import("../../PluggableMap.js").FrameState} */ (
          assign({}, frameState, {
            declutterTree: new RBush(9),
            extent: renderedExtent,
            size: [width, height],
            viewState: /** @type {import("../../View.js").State} */ (
              assign({}, frameState.viewState, {
                rotation: 0,
              })
            ),
          })
        );
      let emptyImage = true;
      const image = new ImageCanvas(
        renderedExtent,
        viewResolution,
        pixelRatio,
        context.canvas,
        function (callback) {
          if (
            vectorRenderer.prepareFrame(imageFrameState) &&
            vectorRenderer.replayGroupChanged
          ) {
            vectorRenderer.clipping = false;
            if (vectorRenderer.renderFrame(imageFrameState, null)) {
              vectorRenderer.renderDeclutter(imageFrameState);
              emptyImage = false;
            }
            callback();
          }
        }
      );

      image.addEventListener(
        EventType.CHANGE,
        function () {
          if (image.getState() !== ImageState.LOADED) {
            return;
          }
          this.image_ = emptyImage ? null : image;
          const imageResolution = image.getResolution();
          const imagePixelRatio = image.getPixelRatio();
          const renderedResolution =
            (imageResolution * pixelRatio) / imagePixelRatio;
          this.renderedResolution = renderedResolution;
          this.coordinateToVectorPixelTransform_ = compose(
            this.coordinateToVectorPixelTransform_,
            width / 2,
            height / 2,
            1 / renderedResolution,
            -1 / renderedResolution,
            0,
            -viewState.center[0],
            -viewState.center[1]
          );
        }.bind(this)
      );
      image.load();
    }

    if (this.image_) {
      this.renderedPixelToCoordinateTransform_ =
        frameState.pixelToCoordinateTransform.slice();
    }

    return !!this.image_;
  }

  /**
   */
  preRender() {}

  /**
   */
  postRender() {}

  /**
   */
  renderDeclutter() {}

  /**
   * @param {import("../../coordinate.js").Coordinate} coordinate Coordinate.
   * @param {import("../../PluggableMap.js").FrameState} frameState Frame state.
   * @param {number} hitTolerance Hit tolerance in pixels.
   * @param {import("../vector.js").FeatureCallback<T>} callback Feature callback.
   * @param {Array<import("../Map.js").HitMatch<T>>} matches The hit detected matches with tolerance.
   * @return {T|undefined} Callback result.
   * @template T
   */
  forEachFeatureAtCoordinate(
    coordinate,
    frameState,
    hitTolerance,
    callback,
    matches
  ) {
    if (this.vectorRenderer_) {
      return this.vectorRenderer_.forEachFeatureAtCoordinate(
        coordinate,
        frameState,
        hitTolerance,
        callback,
        matches
      );
    } else {
      return super.forEachFeatureAtCoordinate(
        coordinate,
        frameState,
        hitTolerance,
        callback,
        matches
      );
    }
  }
}

export default CanvasVectorImageLayerRenderer;
<|endoftext|>