<commit_before>/**
 * Copyright 2014 Solinea, Inc.
 *
 * Licensed under the Solinea Software License Agreement (goldstone),
 * Version 1.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *     http://www.solinea.com/goldstone/LICENSE.pdf
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Author: Alex Jacobs
 */

var NodeReportView = Backbone.View.extend({

    defaults: {},

    initialize: function(options) {
        this.options = options || {};
        this.defaults = _.clone(this.defaults);
        this.el = options.el;
        this.node_uuid = options.node_uuid;
        this.defaults.globalLookback = null;
        this.defaults.globalRefresh = null;

        var ns = this.defaults;
        var self = this;

        this.render();
        this.initializeChartButtons();
        this.getGlobalLookbackRefresh();
        this.renderCharts();
        this.setGlobalLookbackRefreshTriggers();
        this.scheduleInterval();
    },

    clearScheduledInterval: function() {
        var ns = this.defaults;
        clearInterval(ns.scheduleInterval);
    },

    scheduleInterval: function() {
        var self = this;
        var ns = this.defaults;

        var intervalDelay = ns.globalRefresh * 1000;

        if (intervalDelay < 0) {
            return true;
        }

        ns.scheduleInterval = setInterval(function() {
            self.triggerChange();
        }, intervalDelay);
    },

    getGlobalLookbackRefresh: function() {
        this.defaults.globalLookback = $('#global-lookback-range').val();
        this.defaults.globalRefresh = $('#global-refresh-range').val();
    },

    triggerChange: function() {
        this.cpuUsageView.trigger('selectorChanged');
        this.memoryUsageView.trigger('selectorChanged');
        this.networkUsageView.trigger('selectorChanged');
        this.eventsReport.trigger('selectorChanged');
    },

    setGlobalLookbackRefreshTriggers: function() {
        var self = this;
        // wire up listeners between global selectors and charts
        // change listeners for global selectors
        $('#global-lookback-range').on('change', function() {
            self.getGlobalLookbackRefresh();
            self.triggerChange();
            self.clearScheduledInterval();
            self.scheduleInterval();
        });
        $('#global-refresh-range').on('change', function() {
            self.getGlobalLookbackRefresh();
            self.clearScheduledInterval();
            self.scheduleInterval();
        });
    },

    initializeChartButtons: function() {
        $("#reportsReport").hide();
        $("#eventsReport").hide();
        $("button#headerBar").click(function() {
            $("button#headerBar.active").toggleClass("active");
            $(this).toggleClass("active");
            var selectedButton = ($(this).context.innerHTML.toLowerCase());
            _.each($("button#headerBar"), function(item) {
                $("#node-report-panel").find('#' + item.innerHTML + 'Report').hide();
            });
            $("#node-report-panel").find('#' + selectedButton + 'Report').show();
        });
    },

    render: function() {
        this.$el.html(this.template());
        return this;
    },

    renderCharts: function() {

        var ns = this.defaults;

        new ChartHeaderView({
            el: '#service-status-title-bar',
            chartTitle: 'Service Status Report',
            infoText: 'serviceStatus',
            columns: 12
        });
        new ChartHeaderView({
            el: '#utilization-title-bar',
            chartTitle: 'Utilization',
            infoText: 'utilization',
            columns: 12
        });
        new ChartHeaderView({
            el: '#hypervisor-title-bar',
            chartTitle: 'Hypervisor',
            infoText: 'hypervisor',
            columns: 12
        });

        // construct api calls from url component
        // between the last '/' and the following '.'
        var loc = location.pathname;
        locEnd = loc.slice(loc.lastIndexOf('/') + 1);
        var hostName = locEnd.slice(0, locEnd.indexOf('.'));

        //----------------------------
        // instantiate charts via
        // backbone collection / views

        //---------------------------
        // instantiate Service status chart
        this.serviceStatusChart = new ServiceStatusCollection({
            nodeName: hostName
        });

        this.serviceStatusChartView = new ServiceStatusView({
            collection: this.serviceStatusChart,
            el: '#node-report-main #node-report-r2',
            width: $('#node-report-main #node-report-r2').width(),
            globalLookback: ns.globalLookback
        });

        //---------------------------
        // instantiate CPU Usage chart
        this.cpuUsageChart = new UtilizationCpuCollection({
            nodeName: hostName,
            globalLookback: ns.globalLookback
        });

        this.cpuUsageView = new UtilizationCpuView({
            collection: this.cpuUsageChart,
            el: '#node-report-r3 #node-report-panel #cpu-usage',
            width: $('#node-report-r3 #node-report-panel #cpu-usage').width()
        });

        //---------------------------
        // instantiate Memory Usage chart
        this.memoryUsageChart = new UtilizationMemCollection({
            nodeName: hostName,
            globalLookback: ns.globalLookback
        });

        this.memoryUsageView = new UtilizationMemView({
            collection: this.memoryUsageChart,
            el: '#node-report-r3 #node-report-panel #memory-usage',
            width: $('#node-report-r3 #node-report-panel #memory-usage').width()
        });

        //---------------------------
        // instantiate Network Usage chart

        this.networkUsageChart = new UtilizationNetCollection({
            nodeName: hostName,
            globalLookback: ns.globalLookback
        });

        this.networkUsageView = new UtilizationNetView({
            collection: this.networkUsageChart,
            el: '#node-report-r3 #node-report-panel #network-usage',
            width: $('#node-report-r3 #node-report-panel #network-usage').width()
        });

        //---------------------------
        // instantiate Libvirt core/vm chart
        this.hypervisorCoreChart = new HypervisorCollection({
            url: "/glance/api_perf?start=111&end=112&interval=3600s&render=false",
            globalLookback: ns.globalLookback
        });

        this.hypervisorCoreView = new HypervisorView({
            collection: this.hypervisorCoreChart,
            el: '#node-report-r4 #node-report-panel #cores-usage',
            width: $('#node-report-r4 #node-report-panel #cores-usage').width(),
            axisLabel: "Cores"
        });

        //---------------------------
        // instantiate Libvirt mem/vm  chart
        this.hypervisorMemoryChart = new HypervisorCollection({
            url: "/glance/api_perf?start=111&end=112&interval=3600s&render=false",
            globalLookback: ns.globalLookback
        });
        this.hypervisorMemoryView = new HypervisorView({
            collection: this.hypervisorMemoryChart,
            el: '#node-report-r4 #node-report-panel #memory-usage',
            width: $('#node-report-r4 #node-report-panel #memory-usage').width(),
            axisLabel: "GB"
        });

        //---------------------------
        // instantiate Libvirt top 10 CPU consumer VMs chart
        this.hypervisorVmCpuChart = new HypervisorVmCpuCollection({
            url: "/glance/api_perf?start=111&end=112&interval=3600s&render=false",
            globalLookback: ns.globalLookback
        });

        this.hypervisorVmCpuView = new HypervisorVmCpuView({
            collection: this.hypervisorVmCpuChart,
            el: '#node-report-r4 #node-report-panel #vm-cpu-usage',
            width: $('#node-report-r4 #node-report-panel #vm-cpu-usage').width()
        });

        //---------------------------
        // instantiate Reports tab data

        this.reportsReport = new ReportsReportView({
            el: '#node-report-panel #reportsReport',
            width: $('#node-report-panel #reportsReport').width(),
            nodeName: hostName,
            globalLookback: ns.globalLookback
        });

        //---------------------------
        // instantiate Events tab data

        this.eventsReport = new EventsReportView({
            el: '#node-report-panel #eventsReport',
            width: $('#node-report-panel #eventsReport').width(),
            nodeName: hostName,
            globalLookback: ns.globalLookback
        });
    },

    template: _.template('' +
        '
' +
        '
' +
        '
<%= this.node_uuid %>
' +
        '
' +
        '
' +
        '
' +

        '' +
        '
' +
        '<button type="button" id="headerBar" class="servicesButton active btn ' + 'btn-default">Services</button>' +
        '<button type="button" id="headerBar" class="reportsButton btn btn-' + 'default">Reports</button>' +
        '<button type="button" id="headerBar" class="eventsButton btn btn-' + 'default">Events</button>

' +
        '
' +

        '
' +
        '
' +
        '
' +

        '' +
        '

' +
        '
' +
        '
' +
        '
' +
        '
' +
        '
' +
        '
' +

        '' +
        '

' +
        '
' +
        '
' +
        '
' +
        '
CPU Usage
' +
        '
' +
        '
' +
        '
Memory Usage
' +
        '
' +
        '
' +
        '
Network Usage
' +
        '
' +
        '
' +
        '
' +
        '
' +
        '
' +
        '
' +
        '
' +

        '' +
        '

' +
        '
' +
        '
' +
        '
' +
        'Cores' +
        '
' +
        '
' +
        'Memory' +
        '
' +
        '
' +
        'Per VM CPU Usage' +
        '
' +
        '
' +
        '
' +
        '
' +
        '
' +
        '
' +
        '

' +
        '

' +
        '
' +
        '
' +
        '
'
    )

});
<commit_msg>Fixes formatting of button group to ensure rounded corners on both end-buttons.<commit_after>/**
 * Copyright 2014 Solinea, Inc.
 *
 * Licensed under the Solinea Software License Agreement (goldstone),
 * Version 1.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *     http://www.solinea.com/goldstone/LICENSE.pdf
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Author: Alex Jacobs
 */

var NodeReportView = Backbone.View.extend({

    defaults: {},

    initialize: function(options) {
        this.options = options || {};
        this.defaults = _.clone(this.defaults);
        this.el = options.el;
        this.node_uuid = options.node_uuid;
        this.defaults.globalLookback = null;
        this.defaults.globalRefresh = null;

        var ns = this.defaults;
        var self = this;

        this.render();
        this.initializeChartButtons();
        this.getGlobalLookbackRefresh();
        this.renderCharts();
        this.setGlobalLookbackRefreshTriggers();
        this.scheduleInterval();
    },

    clearScheduledInterval: function() {
        var ns = this.defaults;
        clearInterval(ns.scheduleInterval);
    },

    scheduleInterval: function() {
        var self = this;
        var ns = this.defaults;

        var intervalDelay = ns.globalRefresh * 1000;

        if (intervalDelay < 0) {
            return true;
        }

        ns.scheduleInterval = setInterval(function() {
            self.triggerChange();
        }, intervalDelay);
    },

    getGlobalLookbackRefresh: function() {
        this.defaults.globalLookback = $('#global-lookback-range').val();
        this.defaults.globalRefresh = $('#global-refresh-range').val();
    },

    triggerChange: function() {
        this.cpuUsageView.trigger('selectorChanged');
        this.memoryUsageView.trigger('selectorChanged');
        this.networkUsageView.trigger('selectorChanged');
        this.eventsReport.trigger('selectorChanged');
    },

    setGlobalLookbackRefreshTriggers: function() {
        var self = this;
        // wire up listeners between global selectors and charts
        // change listeners for global selectors
        $('#global-lookback-range').on('change', function() {
            self.getGlobalLookbackRefresh();
            self.triggerChange();
            self.clearScheduledInterval();
            self.scheduleInterval();
        });
        $('#global-refresh-range').on('change', function() {
            self.getGlobalLookbackRefresh();
            self.clearScheduledInterval();
            self.scheduleInterval();
        });
    },

    initializeChartButtons: function() {
        $("#reportsReport").hide();
        $("#eventsReport").hide();
        $("button#headerBar").click(function() {
            $("button#headerBar.active").toggleClass("active");
            $(this).toggleClass("active");
            var selectedButton = ($(this).context.innerHTML.toLowerCase());
            _.each($("button#headerBar"), function(item) {
                $("#node-report-panel").find('#' + item.innerHTML + 'Report').hide();
            });
            $("#node-report-panel").find('#' + selectedButton + 'Report').show();
        });
    },

    render: function() {
        this.$el.html(this.template());
        return this;
    },

    renderCharts: function() {

        var ns = this.defaults;

        new ChartHeaderView({
            el: '#service-status-title-bar',
            chartTitle: 'Service Status Report',
            infoText: 'serviceStatus',
            columns: 12
        });
        new ChartHeaderView({
            el: '#utilization-title-bar',
            chartTitle: 'Utilization',
            infoText: 'utilization',
            columns: 12
        });
        new ChartHeaderView({
            el: '#hypervisor-title-bar',
            chartTitle: 'Hypervisor',
            infoText: 'hypervisor',
            columns: 12
        });

        // construct api calls from url component
        // between the last '/' and the following '.'
        var loc = location.pathname;
        locEnd = loc.slice(loc.lastIndexOf('/') + 1);
        var hostName = locEnd.slice(0, locEnd.indexOf('.'));

        //----------------------------
        // instantiate charts via
        // backbone collection / views

        //---------------------------
        // instantiate Service status chart
        this.serviceStatusChart = new ServiceStatusCollection({
            nodeName: hostName
        });

        this.serviceStatusChartView = new ServiceStatusView({
            collection: this.serviceStatusChart,
            el: '#node-report-main #node-report-r2',
            width: $('#node-report-main #node-report-r2').width(),
            globalLookback: ns.globalLookback
        });

        //---------------------------
        // instantiate CPU Usage chart
        this.cpuUsageChart = new UtilizationCpuCollection({
            nodeName: hostName,
            globalLookback: ns.globalLookback
        });

        this.cpuUsageView = new UtilizationCpuView({
            collection: this.cpuUsageChart,
            el: '#node-report-r3 #node-report-panel #cpu-usage',
            width: $('#node-report-r3 #node-report-panel #cpu-usage').width()
        });

        //---------------------------
        // instantiate Memory Usage chart
        this.memoryUsageChart = new UtilizationMemCollection({
            nodeName: hostName,
            globalLookback: ns.globalLookback
        });

        this.memoryUsageView = new UtilizationMemView({
            collection: this.memoryUsageChart,
            el: '#node-report-r3 #node-report-panel #memory-usage',
            width: $('#node-report-r3 #node-report-panel #memory-usage').width()
        });

        //---------------------------
        // instantiate Network Usage chart

        this.networkUsageChart = new UtilizationNetCollection({
            nodeName: hostName,
            globalLookback: ns.globalLookback
        });

        this.networkUsageView = new UtilizationNetView({
            collection: this.networkUsageChart,
            el: '#node-report-r3 #node-report-panel #network-usage',
            width: $('#node-report-r3 #node-report-panel #network-usage').width()
        });

        //---------------------------
        // instantiate Libvirt core/vm chart
        this.hypervisorCoreChart = new HypervisorCollection({
            url: "/glance/api_perf?start=111&end=112&interval=3600s&render=false",
            globalLookback: ns.globalLookback
        });

        this.hypervisorCoreView = new HypervisorView({
            collection: this.hypervisorCoreChart,
            el: '#node-report-r4 #node-report-panel #cores-usage',
            width: $('#node-report-r4 #node-report-panel #cores-usage').width(),
            axisLabel: "Cores"
        });

        //---------------------------
        // instantiate Libvirt mem/vm  chart
        this.hypervisorMemoryChart = new HypervisorCollection({
            url: "/glance/api_perf?start=111&end=112&interval=3600s&render=false",
            globalLookback: ns.globalLookback
        });
        this.hypervisorMemoryView = new HypervisorView({
            collection: this.hypervisorMemoryChart,
            el: '#node-report-r4 #node-report-panel #memory-usage',
            width: $('#node-report-r4 #node-report-panel #memory-usage').width(),
            axisLabel: "GB"
        });

        //---------------------------
        // instantiate Libvirt top 10 CPU consumer VMs chart
        this.hypervisorVmCpuChart = new HypervisorVmCpuCollection({
            url: "/glance/api_perf?start=111&end=112&interval=3600s&render=false",
            globalLookback: ns.globalLookback
        });

        this.hypervisorVmCpuView = new HypervisorVmCpuView({
            collection: this.hypervisorVmCpuChart,
            el: '#node-report-r4 #node-report-panel #vm-cpu-usage',
            width: $('#node-report-r4 #node-report-panel #vm-cpu-usage').width()
        });

        //---------------------------
        // instantiate Reports tab data

        this.reportsReport = new ReportsReportView({
            el: '#node-report-panel #reportsReport',
            width: $('#node-report-panel #reportsReport').width(),
            nodeName: hostName,
            globalLookback: ns.globalLookback
        });

        //---------------------------
        // instantiate Events tab data

        this.eventsReport = new EventsReportView({
            el: '#node-report-panel #eventsReport',
            width: $('#node-report-panel #eventsReport').width(),
            nodeName: hostName,
            globalLookback: ns.globalLookback
        });
    },

    template: _.template('' +
        '
' +
        '
' +
        '
<%= this.node_uuid %>
' +
        '
' +
        '
' +
        '
' +

        '' +
        '
' +
        '<button type="button" id="headerBar" class="servicesButton active btn btn-default">Services</button>' +
        '<button type="button" id="headerBar" class="reportsButton btn btn-default">Reports</button>' +
        '<button type="button" id="headerBar" class="eventsButton btn btn-default">Events</button>' +
        '

' +

        '
' +
        '
' +
        '
' +

        '' +
        '

' +
        '
' +
        '
' +
        '
' +
        '
' +
        '
' +
        '
' +

        '' +
        '

' +
        '
' +
        '
' +
        '
' +
        '
CPU Usage
' +
        '
' +
        '
' +
        '
Memory Usage
' +
        '
' +
        '
' +
        '
Network Usage
' +
        '
' +
        '
' +
        '
' +
        '
' +
        '
' +
        '
' +
        '
' +

        '' +
        '

' +
        '
' +
        '
' +
        '
' +
        'Cores' +
        '
' +
        '
' +
        'Memory' +
        '
' +
        '
' +
        'Per VM CPU Usage' +
        '
' +
        '
' +
        '
' +
        '
' +
        '
' +
        '
' +
        '

' +
        '

' +
        '
' +
        '
' +
        '
'
    )

});
<|endoftext|>


<commit_before>const { ApolloServer } = require("apollo-server");

const { TruffleDB } = require("@truffle/db");
const Config = require("@truffle/config");

const port = 4444;

const config = Config.detect({
  workingDirectory: process.argv[2] || process.cwd()
});

const db = new TruffleDB(config);

const { schema, context } = db;

const server = new ApolloServer({
  tracing: true,
  schema,
  context
});

// This `listen` method launches a web-server.  Existing apps
// can utilize middleware options, which we'll discuss later.
server.listen({ port }).then(({ url }) => {
  console.log(`🚀  Server ready at ${url}`);
});
<commit_msg>Remove comment from server.js<commit_after>const { ApolloServer } = require("apollo-server");

const { TruffleDB } = require("@truffle/db");
const Config = require("@truffle/config");

const port = 4444;

const config = Config.detect({
  workingDirectory: process.argv[2] || process.cwd()
});

const db = new TruffleDB(config);

const { schema, context } = db;

const server = new ApolloServer({
  tracing: true,
  schema,
  context
});

server.listen({ port }).then(({ url }) => {
  console.log(`🚀  Server ready at ${url}`);
});
<|endoftext|>


<commit_before>import React from 'react';

import SPELLS from 'common/SPELLS';
import SpellIcon from 'common/SpellIcon';
import { formatPercentage } from 'common/format';
import SpellLink from 'common/SpellLink';
import Analyzer from 'parser/core/Analyzer';
import UptimeIcon from 'interface/icons/Uptime';
import StatisticBox from 'interface/others/StatisticBox';
import STATISTIC_ORDER from 'interface/others/STATISTIC_ORDER';
import { t } from '@lingui/macro';

import { ROLL_THE_BONES_BUFFS } from '../../constants';

class RollTheBonesBuffs extends Analyzer {
  /**
   * Percentage of the fight that Roll the Bones was active
   * In other words, at least one of the buffs was active
   */
  get totalPercentUptime() {
    return this.percentUptime(SPELLS.ROLL_THE_BONES.id);
  }

  get suggestionThresholds() {
    return {
      actual: this.totalPercentUptime,
      isLessThan: {
        minor: 0.95,
        average: 0.9,
        major: 0.8,
      },
      style: 'percentage',
    };
  }

  percentUptime(spellid) {
    return this.selectedCombatant.getBuffUptime(spellid) / this.owner.fightDuration;
  }

  suggestions(when) {
    when(this.suggestionThresholds).addSuggestion((suggest, actual, recommended) => suggest(<>Your <SpellLink id={SPELLS.ROLL_THE_BONES.id} /> uptime can be improved. Try to always have <SpellLink id={SPELLS.ROLL_THE_BONES.id} /> active, even with a lower value roll.</>)
      .icon(SPELLS.ROLL_THE_BONES.icon)
      .actual(t({
      id: "rogue.outlaw.suggestions.rollTheBones.uptime",
      message: `${formatPercentage(actual)}% Roll the Bones uptime`
    }))
      .recommended(`>${formatPercentage(recommended)}% is recommended`));
  }

  statistic() {
    return (
      <StatisticBox
        position={STATISTIC_ORDER.CORE()}
        icon={<SpellIcon id={SPELLS.ROLL_THE_BONES.id} />}
        value={(
          <>
            <UptimeIcon /> {formatPercentage(this.totalPercentUptime)}% uptime

          </>
        )}
        label={<SpellLink id={SPELLS.ROLL_THE_BONES.id} icon={false} />}
      >

              Buff
              Time (%)

            {ROLL_THE_BONES_BUFFS.map((e) => (

                <SpellLink id={e.id} />
                {`${formatPercentage(this.percentUptime(e.id))} %`}

            ))}

      </StatisticBox>
    );
  }
}

export default RollTheBonesBuffs;
<commit_msg>[Rogue] Fix Roll The Bones positioning to match other specs' positioning of WCL statistics<commit_after>import React from 'react';

import SPELLS from 'common/SPELLS';
import SpellIcon from 'common/SpellIcon';
import { formatPercentage } from 'common/format';
import SpellLink from 'common/SpellLink';
import Analyzer from 'parser/core/Analyzer';
import UptimeIcon from 'interface/icons/Uptime';
import StatisticBox from 'interface/others/StatisticBox';
import STATISTIC_ORDER from 'interface/others/STATISTIC_ORDER';
import { t } from '@lingui/macro';

import { ROLL_THE_BONES_BUFFS } from '../../constants';

class RollTheBonesBuffs extends Analyzer {
  /**
   * Percentage of the fight that Roll the Bones was active
   * In other words, at least one of the buffs was active
   */
  get totalPercentUptime() {
    return this.percentUptime(SPELLS.ROLL_THE_BONES.id);
  }

  get suggestionThresholds() {
    return {
      actual: this.totalPercentUptime,
      isLessThan: {
        minor: 0.95,
        average: 0.9,
        major: 0.8,
      },
      style: 'percentage',
    };
  }

  percentUptime(spellid) {
    return this.selectedCombatant.getBuffUptime(spellid) / this.owner.fightDuration;
  }

  suggestions(when) {
    when(this.suggestionThresholds).addSuggestion((suggest, actual, recommended) => suggest(<>Your <SpellLink id={SPELLS.ROLL_THE_BONES.id} /> uptime can be improved. Try to always have <SpellLink id={SPELLS.ROLL_THE_BONES.id} /> active, even with a lower value roll.</>)
      .icon(SPELLS.ROLL_THE_BONES.icon)
      .actual(t({
      id: "rogue.outlaw.suggestions.rollTheBones.uptime",
      message: `${formatPercentage(actual)}% Roll the Bones uptime`
    }))
      .recommended(`>${formatPercentage(recommended)}% is recommended`));
  }

  statistic() {
    return (
      <StatisticBox
        position={STATISTIC_ORDER.CORE(2)}
        icon={<SpellIcon id={SPELLS.ROLL_THE_BONES.id} />}
        value={(
          <>
            <UptimeIcon /> {formatPercentage(this.totalPercentUptime)}% uptime

          </>
        )}
        label={<SpellLink id={SPELLS.ROLL_THE_BONES.id} icon={false} />}
      >

              Buff
              Time (%)

            {ROLL_THE_BONES_BUFFS.map((e) => (

                <SpellLink id={e.id} />
                {`${formatPercentage(this.percentUptime(e.id))} %`}

            ))}

      </StatisticBox>
    );
  }
}

export default RollTheBonesBuffs;
<|endoftext|>


<commit_before>$( document ).ready(function() {
    var xhr;

    $( "button.serve, button.complete").on('click', function( event ) {
        event.preventDefault();
        event.stopPropagation();

        if(xhr && xhr.readyState != 4){
            xhr.abort();
        }

        var value = $(this).prev().val();
        var csrfmiddlewaretoken = $(this).prev().prev().val();
        var url_part = "";

        if ($(this).hasClass('serve')) {
            url_part = "serve/";
        } else {
            if ($(this).hasClass('complete')) {
                url_part = "complete/";
            }
        }

        xhr = $.ajax({
            type: "POST",
            url: "/booking/" + url_part,
            data: { "id": value, "csrfmiddlewaretoken": csrfmiddlewaretoken },
            dataType: "json",
            success: function(msg){
                $("div.alert").remove();
                $("div#greeting").after('
' + msg["request_status"] + '
');
                return false;
            },
            error: function(jqXHR, textStatus, errorThrown){
                console.log( "Error", jqXHR, textStatus, errorThrown);
            }
          });
    });
});
<commit_msg>Javascript-код приведен к стандарту (до некоторой степени) через jslint.<commit_after>$(document).ready(function () {
  'use strict';
  var xhr;

  $("button.serve, button.complete").on('click', function (event) {
    event.preventDefault();
    event.stopPropagation();

    if (xhr && xhr.readyState !== 4) {
      xhr.abort();
    }

    var value = $(this).prev().val(),
    csrfmiddlewaretoken = $(this).prev().prev().val(),
    url_part = "";

    if ($(this).hasClass('serve')) {
      url_part = "serve/";
    } else {
      if ($(this).hasClass('complete')) {
        url_part = "complete/";
      }
    }

    xhr = $.ajax({
      type: "POST",
      url: "/booking/" + url_part,
      data: { "id": value, "csrfmiddlewaretoken": csrfmiddlewaretoken },
      dataType: "json",
      success: function (msg) {
        $("div.alert").remove();
        $("div#greeting").after('
' + msg.request_status + '
');
        return false;
      },
      error: function (jqXHR, textStatus, errorThrown) {
        console.log("Error", jqXHR, textStatus, errorThrown);
      }
    });
  });
});
<|endoftext|>


<commit_before>describe("Metadata dialog", function() {

  var cartodb_layer, vis, user;

  beforeEach(function() {
    vis = new cdb.admin.Visualization({
      name:             "test_table",
      description:      "Table description",
      tags:             ["jam","testing"],
      privacy:          "PUBLIC",
      type:             "table"
    });

    cartodb_layer = new cdb.admin.CartoDBLayer({ table_name: 'test_table'});

    vis.map.layers.reset([
      new cdb.geo.MapLayer(),
      cartodb_layer
    ]);

    user = TestUtil.createUser();
    cartodb_layer.table.permission.owner = user;
    vis.permission.owner = user;

    view = new cdb.admin.MetadataDialog({
      vis: vis,
      user: user
    });
  });

  afterEach(function() {
    view.clean();
  });

  it("should render properly", function(done) {
    view.render();
    expect(view.$('input[name="name"]').val()).toBe('test_table');
    expect(view.$('textarea[name="description"]').val()).toBe('Table description');
    expect(view.$('input[name="source"]').val()).toBe('');
    expect(view.$('input[name="license"]').val()).toBe('');
    expect(view.$('ul li.tagit-choice').size()).toBe(2);
    expect(view.$('div.info.error').length).toBe(1);
    expect(view.$('div.owner').length).toBe(0);
    expect(view.$('div.foot input[type="submit"]').length).toBe(1);

    setTimeout(function() {
      expect(view.$('.jspContainer').length).toBe(1);
      done();
    },100)
  });

  it("should render owner block and disable all fields if table owner is different", function() {
    // Table
    var new_guy = new cdb.admin.User({ username: 'tests', id: 10 });
    cartodb_layer.table.permission.owner = new_guy;
    vis.permission.owner = new_guy;

    view.render();
    expect(view.$('div.owner').length).toBe(1);
    expect(view.$('input[name="name"]').is('[readonly]')).toBeTruthy();
    expect(view.$('textarea[name="description"]').is('[readonly]')).toBeTruthy();
    expect(view.$('input[name="source"]').is('[readonly]')).toBeTruthy();
    expect(view.$('input[name="license"]').is('[readonly]')).toBeTruthy();
    expect(view.$('ul.readonly').length).toBe(1);
    expect(view.$('div.foot input[type="submit"]').length).toBe(0);
  });

  it("should disable all fields if table has a query applied", function() {
    // Table
    var new_guy = new cdb.admin.User({ username: 'tests', id: 10 });
    cartodb_layer.table.permission.owner = new_guy;
    vis.permission.owner = new_guy;

    view.render();
    expect(view.$('div.owner').length).toBe(1);
    expect(view.$('input[name="name"]').is('[readonly]')).toBeTruthy();
    expect(view.$('textarea[name="description"]').is('[readonly]')).toBeTruthy();
    expect(view.$('input[name="source"]').is('[readonly]')).toBeTruthy();
    expect(view.$('input[name="license"]').is('[readonly]')).toBeTruthy();
    expect(view.$('ul.readonly').length).toBe(1);
    expect(view.$('div.foot input[type="submit"]').length).toBe(0);
  });

  it("should render owner block and disable all fields if vis owner is different", function() {
    // Vis
    var new_guy = new cdb.admin.User({ username: 'tests', id: 10 });
    cartodb_layer.table.permission.owner = new_guy;
    vis.set('type', 'derived');
    vis.permission.owner = new_guy;

    view.render();
    expect(view.$('div.owner').length).toBe(1);
    expect(view.$('input[name="name"]').is('[readonly]')).toBeTruthy();
    expect(view.$('textarea[name="description"]').is('[readonly]')).toBeTruthy();
    expect(view.$('input[name="source"]').is('[readonly]')).toBeTruthy();
    expect(view.$('input[name="license"]').is('[readonly]')).toBeTruthy();
    expect(view.$('ul.readonly').length).toBe(1);
    expect(view.$('div.foot input[type="submit"]').length).toBe(0);
  });

  it("should render owner block and disable all fields if vis owner is different", function() {
    // Vis
    var new_guy = new cdb.admin.User({ username: 'tests', id: 10 });
    cartodb_layer.table.permission.owner = new_guy;
    vis.set('type', 'derived');
    vis.permission.owner = new_guy;

    view.render();
    expect(view.$('div.owner').length).toBe(1);
    expect(view.$('input[name="name"]').is('[readonly]')).toBeTruthy();
    expect(view.$('textarea[name="description"]').is('[readonly]')).toBeTruthy();
    expect(view.$('input[name="source"]').is('[readonly]')).toBeTruthy();
    expect(view.$('input[name="license"]').is('[readonly]')).toBeTruthy();
    expect(view.$('ul.readonly').length).toBe(1);
    expect(view.$('div.foot input[type="submit"]').length).toBe(0);
  });

  it("should disable name field when table is synced", function() {
    cartodb_layer.table.synchronization.set('id', 'test');
    view.render();
    expect(view.$('input[name="name"]').is('[readonly]')).toBeTruthy();
    expect(view.$('textarea[name="description"]').is('[readonly]')).toBeFalsy();
    expect(view.$('input[name="source"]').is('[readonly]')).toBeFalsy();
    expect(view.$('input[name="license"]').is('[readonly]')).toBeFalsy();
    expect(view.$('ul.readonly').length).toBe(0);
    expect(view.$('div.foot input[type="submit"]').length).toBe(1);
  });

  it("should disable all fields when table has a query applied", function() {
    cartodb_layer.table.sqlView = {
      isReadOnly: function() { return true; }
    }
    view.render();
    expect(view.$('input[name="name"]').is('[readonly]')).toBeTruthy();
    expect(view.$('textarea[name="description"]').is('[readonly]')).toBeTruthy();
    expect(view.$('input[name="source"]').is('[readonly]')).toBeTruthy();
    expect(view.$('input[name="license"]').is('[readonly]')).toBeTruthy();
    expect(view.$('ul.readonly').length).toBe(1);
    expect(view.$('div.foot input[type="submit"]').length).toBe(0);
  });

  it("should show error info when name input is empty and don't send response signal", function() {
    var called = false;
    var new_view = new cdb.admin.MetadataDialog({
      vis: vis,
      user: user,
      onResponse: function(r) {
        called = true;
      }
    });

    new_view.render();
    new_view.$('input[name="name"]').val('');
    new_view._ok();

    expect(new_view.$('.info.error').hasClass('active')).toBeTruthy();
    expect(called).toBeFalsy();

    new_view.clean();
  });

  it("should return all form data serialized", function() {
    var o = {};
    var new_view = new cdb.admin.MetadataDialog({
      vis: vis,
      user: user,
      onResponse: function(r) {
        o = r
      }
    });

    new_view.render();

    new_view.$('input[name="name"]').val('name');
    new_view.$('textarea[name="description"]').val('description');
    new_view.$('input[name="source"]').val('source');
    new_view.$('input[name="license"]').val('license');

    new_view._saveModel();

    expect(o.name).toBe('name');
    expect(o.description).toBe('description');
    expect(o.source).toBe('source');
    expect(o.tags.length).toBe(2);
    expect(o.license).toBe('license');

    new_view.clean();
  });

  // it("should let the user change the visualization/table tags when the table is syncable", function(done) {
  //   this.vis.map.layers.last().table.synchronization.set('id', 'test');
  //   $(this.header.el).find('span.tags > a').click();

  //   var self = this;

  //   setTimeout(function() {
  //     expect(self.header.tags_dialog).toBeTruthy();
  //     done();
  //   }, 25);

  // })

  // it("should let the user change the visualization/table description when the table is syncable", function(done) {
  //   this.vis.map.layers.last().table.synchronization.set('id', 'test');
  //   $(this.header.el).find('.description p a').click();

  //   var self = this;

  //   setTimeout(function() {
  //     expect(self.header.description_dialog).toBeTruthy();
  //     done();
  //   }, 25);

  // });

  // it("shouldn't apply a disabled class to all editable fields when a query is not applied", function() {
  //   this.vis.map.layers.last().table.sqlView = '';
  //   // Simulate select new dataLayer
  //   this.header.setActiveLayer({
  //     model: this.vis.map.layers.last()
  //   });
  //   expect($(this.header.el).find('span.tags a').hasClass('disabled')).toBeFalsy();
  //   expect($(this.header.el).find('div.description a').length).toBe(1);
  //   expect($(this.header.el).find('h1 a').hasClass('disabled')).toBeFalsy();
  // });

  // it("shouldn't let user change the table description when the table is in sql view (no matter if table is synced)", function(done) {
  //   this.vis.map.layers.last().table.sqlView = {
  //     isReadOnly: function() { return true; }
  //   }
  //   this.vis.map.layers.last().table.synchronization.set('id', 'test');
  //   $(this.header.el).find('.description p a').click();

  //   var self = this;

  //   setTimeout(function() {
  //     expect(self.header.description_dialog).toBeFalsy();
  //     done();
  //   }, 25);

  // });

  // it("shouldn't let user change the table tags when the table is in sql view (no matter if table is synced)", function(done) {
  //   this.vis.map.layers.last().table.sqlView = {
  //     isReadOnly: function() { return true; }
  //   }
  //   this.vis.map.layers.last().table.synchronization.set('id', 'test');
  //   $(this.header.el).find('span.tags > a').click();

  //   var self = this;

  //   setTimeout(function() {
  //     expect(self.header.tags_dialog).toBeFalsy();
  //     done();
  //   }, 25);

  // });

  // it("should open description_dialog on click", function(done) {
  //   $(this.header.el).find('.description p a').click();

  //   var self = this;

  //   setTimeout(function() {
  //     expect(self.header.description_dialog).toBeTruthy();
  //     self.header.description_dialog.clean();
  //     done();
  //   }, 25);
  // });

  // it("should not open description_dialog on click when sql aplied", function() {
  //   this.vis.map.layers.last().table.sqlView = {
  //     isReadOnly: function() { return true; }
  //   }
  //   $(this.header.el).find('.description a').click();
  //   expect(this.header.description_dialog).toBeFalsy();
  // })

  // it("should open tags dialog on click", function(done) {
  //   $(this.header.el).find('.tags a').click();

  //   var self = this;

  //   setTimeout(function(){
  //     expect(self.header.tags_dialog).toBeTruthy();
  //     self.header.tags_dialog.clean();
  //     done();
  //   }, 25);

  // })

  // it("should not open tags dialog on click when sql aplied", function(done) {
  //   this.vis.map.layers.last().table.sqlView = {
  //     isReadOnly: function() { return true; }
  //   }
  //   $(this.header.el).find('.tags a').click();

  //   var self = this;

  //   setTimeout(function(){
  //     expect(self.header.tags_dialog).toBeFalsy();
  //     done();
  //   }, 25);

  // });

  // it("should add default description when no description", function() {
  //   this.vis.set('description', null);
  //   expect($(this.header.el).find('.description p a').text()).toEqual(this.header._TEXTS.description.normal)
  // });

  // it("should add table description ", function() {
  //   this.vis.set({'description': 'cachopada'});
  //   expect($(this.header.el).find('.description p a').html()).toEqual('cachopada')
  // })

  // it("shouldn't add a table description if it's empty", function() {
  //   this.vis.set({'description': '              '});
  //   expect($(this.header.el).find('.description p a').html()).toEqual('add a description...');
  // })

  // it("should add table description even when there's an sql", function() {
  //   this.vis.set({'description': 'cachopada'});
  //   this.vis.map.layers.last().table.sqlView = 'wadus';

  //   expect($(this.header.el).find('.description p').text()).toEqual('cachopada')
  // })

  // it("should add default tag button text when no tags", function() {
  //   this.vis.set("tags", null)
  //   expect($(this.header.el).find('.tags a').html()).toEqual(this.header._TEXTS.tags.add)
  // })

  // it("should not remove tag button text when sql applied", function() {
  //   this.vis.map.layers.last().table.sqlView = 'wadus';
  //   expect($(this.header.el).find('.tags a').html()).toBeTruthy();
  // })

  // it("should add tags", function() {
  //   this.vis.set({'tags': ['cachopo','frixuelu'] });
  //   expect($(this.header.el).find('.tags a').html()).toEqual('2 tags');
  // })

  // it("should change tags button when there are tags", function() {
  //   this.vis.set({'tags': ['cachopo','frixuelu'] });
  //   expect($(this.header.el).find('.tags a').html()).toEqual('2 tags')
  // })

  // it("should add the class empty when there are no tags", function() {
  //   this.vis.set({'tags': []});
  //   expect($(this.header.el).find('.tags').hasClass("empty")).toEqual(true);
  // })

  // it("should remove the class empty when there are no tags", function() {
  //   this.vis.set({'tags': [] });
  //   this.vis.set({'tags': ['PACHOPE'] });
  //   expect($(this.header.el).find('.tags').hasClass("empty")).toEqual(false);
  // })

  // it("should apply a disabled class to all editable fields when a query is applied", function() {
  //   this.vis.map.layers.last().table.sqlView = {
  //     isReadOnly: function() { return true; }
  //   }

  //   // Simulate select new dataLayer
  //   this.header.setActiveLayer({
  //     model: this.vis.map.layers.last()
  //   });
  //   expect($(this.header.el).find('span.tags a').hasClass('disabled')).toBeTruthy();
  //   expect($(this.header.el).find('div.description a').length).toBe(0);
  //   expect($(this.header.el).find('h1 a').hasClass('disabled')).toBeTruthy();
  // });

});
<commit_msg>removed old header specs from metadata dialog spec file<commit_after>describe("Metadata dialog", function() {

  var cartodb_layer, vis, user;

  beforeEach(function() {
    vis = new cdb.admin.Visualization({
      name:             "test_table",
      description:      "Table description",
      tags:             ["jam","testing"],
      privacy:          "PUBLIC",
      type:             "table"
    });

    cartodb_layer = new cdb.admin.CartoDBLayer({ table_name: 'test_table'});

    vis.map.layers.reset([
      new cdb.geo.MapLayer(),
      cartodb_layer
    ]);

    user = TestUtil.createUser();
    cartodb_layer.table.permission.owner = user;
    vis.permission.owner = user;

    view = new cdb.admin.MetadataDialog({
      vis: vis,
      user: user
    });
  });

  afterEach(function() {
    view.clean();
  });

  it("should render properly", function(done) {
    view.render();
    expect(view.$('input[name="name"]').val()).toBe('test_table');
    expect(view.$('textarea[name="description"]').val()).toBe('Table description');
    expect(view.$('input[name="source"]').val()).toBe('');
    expect(view.$('input[name="license"]').val()).toBe('');
    expect(view.$('ul li.tagit-choice').size()).toBe(2);
    expect(view.$('div.info.error').length).toBe(1);
    expect(view.$('div.owner').length).toBe(0);
    expect(view.$('div.foot input[type="submit"]').length).toBe(1);

    setTimeout(function() {
      expect(view.$('.jspContainer').length).toBe(1);
      done();
    },100)
  });

  it("should render owner block and disable all fields if table owner is different", function() {
    // Table
    var new_guy = new cdb.admin.User({ username: 'tests', id: 10 });
    cartodb_layer.table.permission.owner = new_guy;
    vis.permission.owner = new_guy;

    view.render();
    expect(view.$('div.owner').length).toBe(1);
    expect(view.$('input[name="name"]').is('[readonly]')).toBeTruthy();
    expect(view.$('textarea[name="description"]').is('[readonly]')).toBeTruthy();
    expect(view.$('input[name="source"]').is('[readonly]')).toBeTruthy();
    expect(view.$('input[name="license"]').is('[readonly]')).toBeTruthy();
    expect(view.$('ul.readonly').length).toBe(1);
    expect(view.$('div.foot input[type="submit"]').length).toBe(0);
  });

  it("should disable all fields if table has a query applied", function() {
    // Table
    var new_guy = new cdb.admin.User({ username: 'tests', id: 10 });
    cartodb_layer.table.permission.owner = new_guy;
    vis.permission.owner = new_guy;

    view.render();
    expect(view.$('div.owner').length).toBe(1);
    expect(view.$('input[name="name"]').is('[readonly]')).toBeTruthy();
    expect(view.$('textarea[name="description"]').is('[readonly]')).toBeTruthy();
    expect(view.$('input[name="source"]').is('[readonly]')).toBeTruthy();
    expect(view.$('input[name="license"]').is('[readonly]')).toBeTruthy();
    expect(view.$('ul.readonly').length).toBe(1);
    expect(view.$('div.foot input[type="submit"]').length).toBe(0);
  });

  it("should render owner block and disable all fields if vis owner is different", function() {
    // Vis
    var new_guy = new cdb.admin.User({ username: 'tests', id: 10 });
    cartodb_layer.table.permission.owner = new_guy;
    vis.set('type', 'derived');
    vis.permission.owner = new_guy;

    view.render();
    expect(view.$('div.owner').length).toBe(1);
    expect(view.$('input[name="name"]').is('[readonly]')).toBeTruthy();
    expect(view.$('textarea[name="description"]').is('[readonly]')).toBeTruthy();
    expect(view.$('input[name="source"]').is('[readonly]')).toBeTruthy();
    expect(view.$('input[name="license"]').is('[readonly]')).toBeTruthy();
    expect(view.$('ul.readonly').length).toBe(1);
    expect(view.$('div.foot input[type="submit"]').length).toBe(0);
  });

  it("should render owner block and disable all fields if vis owner is different", function() {
    // Vis
    var new_guy = new cdb.admin.User({ username: 'tests', id: 10 });
    cartodb_layer.table.permission.owner = new_guy;
    vis.set('type', 'derived');
    vis.permission.owner = new_guy;

    view.render();
    expect(view.$('div.owner').length).toBe(1);
    expect(view.$('input[name="name"]').is('[readonly]')).toBeTruthy();
    expect(view.$('textarea[name="description"]').is('[readonly]')).toBeTruthy();
    expect(view.$('input[name="source"]').is('[readonly]')).toBeTruthy();
    expect(view.$('input[name="license"]').is('[readonly]')).toBeTruthy();
    expect(view.$('ul.readonly').length).toBe(1);
    expect(view.$('div.foot input[type="submit"]').length).toBe(0);
  });

  it("should disable name field when table is synced", function() {
    cartodb_layer.table.synchronization.set('id', 'test');
    view.render();
    expect(view.$('input[name="name"]').is('[readonly]')).toBeTruthy();
    expect(view.$('textarea[name="description"]').is('[readonly]')).toBeFalsy();
    expect(view.$('input[name="source"]').is('[readonly]')).toBeFalsy();
    expect(view.$('input[name="license"]').is('[readonly]')).toBeFalsy();
    expect(view.$('ul.readonly').length).toBe(0);
    expect(view.$('div.foot input[type="submit"]').length).toBe(1);
  });

  it("should disable all fields when table has a query applied", function() {
    cartodb_layer.table.sqlView = {
      isReadOnly: function() { return true; }
    }
    view.render();
    expect(view.$('input[name="name"]').is('[readonly]')).toBeTruthy();
    expect(view.$('textarea[name="description"]').is('[readonly]')).toBeTruthy();
    expect(view.$('input[name="source"]').is('[readonly]')).toBeTruthy();
    expect(view.$('input[name="license"]').is('[readonly]')).toBeTruthy();
    expect(view.$('ul.readonly').length).toBe(1);
    expect(view.$('div.foot input[type="submit"]').length).toBe(0);
  });

  it("should show error info when name input is empty and don't send response signal", function() {
    var called = false;
    var new_view = new cdb.admin.MetadataDialog({
      vis: vis,
      user: user,
      onResponse: function(r) {
        called = true;
      }
    });

    new_view.render();
    new_view.$('input[name="name"]').val('');
    new_view._ok();

    expect(new_view.$('.info.error').hasClass('active')).toBeTruthy();
    expect(called).toBeFalsy();

    new_view.clean();
  });

  it("should return all form data serialized", function() {
    var o = {};
    var new_view = new cdb.admin.MetadataDialog({
      vis: vis,
      user: user,
      onResponse: function(r) {
        o = r
      }
    });

    new_view.render();

    new_view.$('input[name="name"]').val('name');
    new_view.$('textarea[name="description"]').val('description');
    new_view.$('input[name="source"]').val('source');
    new_view.$('input[name="license"]').val('license');

    new_view._saveModel();

    expect(o.name).toBe('name');
    expect(o.description).toBe('description');
    expect(o.source).toBe('source');
    expect(o.tags.length).toBe(2);
    expect(o.license).toBe('license');

    new_view.clean();
  });

});
<|endoftext|>


<commit_before>/**
 * @fileoverview Provides a drawn features service useful to share
 * information about the drawn features throughout the application.
 */

goog.provide('app.DrawnFeatures');

goog.require('app');
goog.require('ngeo.Location');
goog.require('ngeo.format.FeatureHash');
goog.require('ol.Collection');

/**
 * @constructor
 * @param {ngeo.Location} ngeoLocation Location service.
 * @param {app.Mymaps} appMymaps Mymaps service.
 * @ngInject
 */
app.DrawnFeatures = function(ngeoLocation, appMymaps) {

  /**
   * @type {app.Mymaps}
   * @private
   */
  this.appMymaps_ = appMymaps;

  /**
   * @type {ol.Collection}
   */
  this.features = new ol.Collection();

  /**
   * @type {ngeo.Location}
   * @private
   */
  this.ngeoLocation_ = ngeoLocation;

  /**
   * @const
   * @private
   */
  this.SHORT_PARAM_ = {
    'name' : 'n',
    'description': 'd',
    'color': 'c',
    'opacity': 'o',
    'stroke': 's',
    'linestyle': 'l',
    'shape': 's',
    'size': 't',
    'angle': 'a',
    'isLabel': 'i'
  };

  /**
   * @type {ngeo.format.FeatureHash}
   * @private
   */
  this.fhFormat_ = new ngeo.format.FeatureHash({
    encodeStyles: false,
    properties: (
        goog.bind(
        /**
         * @param {ol.Feature} feature Feature.
         * @return {Object.<string, (string|number)>} Properties to encode.
         */
        function(feature) {
          // Do not encode the __editable__ and __selected__ properties.
          var properties = feature.getProperties();
          delete properties['__editable__'];
          delete properties['__selected__'];
          delete properties['__map_id__'];
          for (var key in properties) {
            if (!properties[key]) {
              delete properties[key];
            } else {
              if (this.SHORT_PARAM_[key]) {
                var value = properties[key];
                delete properties[key];
                properties[this.SHORT_PARAM_[key]] = value;
              }
            }
          }
          return properties;
        },this))
  });

  /**
   * @type {ol.FeatureStyleFunction}
   * @private
   */
  this.featureStyleFunction_ = this.appMymaps_.createStyleFunction();
};

/**
 * Remove the feature from the drawn list.
 * If the feature is a mymaps feature then delete it from mymaps and
 * then rewrite the url.
 * @param {ol.Feature} feature The feature to remove.
 */
app.DrawnFeatures.prototype.remove = function(feature) {
  this.features.remove(feature);
  if (!!feature.get('__map_id__')) {
    if (this.appMymaps_.isEditable()) {
      this.appMymaps_.deleteFeature(feature);
    }
  }
  this.encodeFeaturesInUrl_(this.features.getArray());
};

/**
 * Add a feature in the drawn feature list.
 * Save it into mymaps and rewrite the url.
 * @param {ol.Feature} feature The feature to add.
 */
app.DrawnFeatures.prototype.add = function(feature) {
  var features = this.features.getArray().slice();
  features.push(feature);
  this.saveFeature(feature);
  this.encodeFeaturesInUrl_(features);
};

/**
 * @param {Array.<ol.Feature>} features Features to encode in the URL.
 * @private
 */
app.DrawnFeatures.prototype.encodeFeaturesInUrl_ = function(features) {
  var featuresToEncode = features.filter(function(feature) {
    return !feature.get('__map_id__');
  });
  if (featuresToEncode.length > 0) {
    this.ngeoLocation_.updateParams({
      'features': this.fhFormat_.writeFeatures(featuresToEncode)
    });
  } else {
    this.ngeoLocation_.deleteParam('features');
  }
};

/**
 * Save the feature either in url or in mymaps if the current user
 * has the permissions.
 * @param {ol.Feature} feature The feature to save.
 */
app.DrawnFeatures.prototype.saveFeature = function(feature) {
  if (this.appMymaps_.isEditable() &&
      !!feature.get('__map_id__')) {
    this.saveFeatureInMymaps_(feature);
  }
  this.encodeFeaturesInUrl_(this.features.getArray());
};

/**
 * Move anonymous features to mymaps
 * @return {angular.$q.Promise} Promise.
 */
app.DrawnFeatures.prototype.moveAnonymousFeaturesToMymaps = function() {
  var newMymapsFeatures = [];
  this.features.getArray().map(goog.bind(function(feature) {
    if (!feature.get('__map_id__')) {
      feature.set('__map_id__', this.appMymaps_.getMapId());
      newMymapsFeatures.push(feature);
    }
  }, this));

  return this.saveFeaturesInMymaps_(newMymapsFeatures);
};

/**
 * Decode the features encoded in the URL and add them to the collection
 * of drawn features.
 */
app.DrawnFeatures.prototype.drawFeaturesInUrl = function() {
  var encodedFeatures = this.ngeoLocation_.getParam('features');
  if (goog.isDef(encodedFeatures)) {
    var remoteFeatures = this.fhFormat_.readFeatures(encodedFeatures);
    goog.asserts.assert(!goog.isNull(remoteFeatures));
    goog.array.forEach(remoteFeatures, goog.bind(function(feature) {
      var properties = feature.getProperties();
      for (var key in this.SHORT_PARAM_) {
        if (properties[this.SHORT_PARAM_[key]]) {
          feature.set(key, properties[this.SHORT_PARAM_[key]]);
          feature.unset(this.SHORT_PARAM_[key]);
        }
      }
      var opacity = /** @type {string} */ (feature.get('opacity'));
      feature.set('opacity', +opacity);
      var stroke = /** @type {string} */ (feature.get('stroke'));
      feature.set('stroke', +stroke);
      var size = /** @type {string} */ (feature.get('size'));
      feature.set('size', +size);
      var angle = /** @type {string} */ (feature.get('angle'));
      feature.set('angle', +angle);
      var isLabel = /** @type {string} */ (feature.get('isLabel'));
      feature.set('isLabel', isLabel === 'true');
      feature.set('__editable__', true);
      feature.set('__map_id__', undefined);
      feature.setStyle(this.featureStyleFunction_);
    },this));

    this.features.extend(remoteFeatures);
  }
};

/**
 * @param {ol.Feature} feature Feature to save in mymaps.
 * @private
 */
app.DrawnFeatures.prototype.saveFeatureInMymaps_ = function(feature) {
  var currentFeature = feature;
  if (this.appMymaps_.isEditable() && !feature.get('__saving__')) {
    feature.set('__saving__', true);
    this.appMymaps_.saveFeature(feature)
      .then(goog.bind(function(resp) {
          var featureId = resp['id'];
          currentFeature.set('id', featureId);
          feature.set('__saving__', false);
        }, this));
  }
};

/**
 * @param {Array.<ol.Feature>} features An array of features to save in mymaps.
 * @return {angular.$q.Promise} Promise.
 * @private
 */
app.DrawnFeatures.prototype.saveFeaturesInMymaps_ = function(features) {
  return this.appMymaps_.saveFeatures(features);
};

/**
 * Clear the drawn features.
 */
app.DrawnFeatures.prototype.clear = function() {
  this.features.clear();
  this.appMymaps_.clear();
};

/**
 * Clear the features belonging to mymaps.
 */
app.DrawnFeatures.prototype.clearMymapsFeatures = function() {
  var mymapsFeatures = this.features.getArray().filter(function(feature) {
    return !!feature.get('__map_id__');
  });

  mymapsFeatures.forEach(goog.bind(function(feature) {
    this.features.remove(feature);
  }, this));
  this.appMymaps_.clear();
  this.encodeFeaturesInUrl_(this.features.getArray());
};

/**
 * Clear the anonymous features.
 */
app.DrawnFeatures.prototype.clearAnonymousFeatures = function() {
  var anonymousFeatures = this.features.getArray().filter(function(feature) {
    return !feature.get('__map_id__');
  });

  anonymousFeatures.forEach(goog.bind(function(feature) {
    this.features.remove(feature);
  }, this));
  this.encodeFeaturesInUrl_(this.features.getArray());
};

/**
 * Get the current drawn features as an array.
 * @return {Array.<ol.Feature>?} The features array.
 */
app.DrawnFeatures.prototype.getArray = function() {
  return this.features.getArray();
};

/**
 * Get the current drawn features as a Collection.
 * @return {ol.Collection} The collection of drawn features.
 */
app.DrawnFeatures.prototype.getCollection = function() {
  return this.features;
};

app.module.service('appDrawnFeatures', app.DrawnFeatures);
<commit_msg>Use a unique short name<commit_after>/**
 * @fileoverview Provides a drawn features service useful to share
 * information about the drawn features throughout the application.
 */

goog.provide('app.DrawnFeatures');

goog.require('app');
goog.require('ngeo.Location');
goog.require('ngeo.format.FeatureHash');
goog.require('ol.Collection');

/**
 * @constructor
 * @param {ngeo.Location} ngeoLocation Location service.
 * @param {app.Mymaps} appMymaps Mymaps service.
 * @ngInject
 */
app.DrawnFeatures = function(ngeoLocation, appMymaps) {

  /**
   * @type {app.Mymaps}
   * @private
   */
  this.appMymaps_ = appMymaps;

  /**
   * @type {ol.Collection}
   */
  this.features = new ol.Collection();

  /**
   * @type {ngeo.Location}
   * @private
   */
  this.ngeoLocation_ = ngeoLocation;

  /**
   * @const
   * @private
   */
  this.SHORT_PARAM_ = {
    'angle': 'a',
    'color': 'c',
    'description': 'd',
    'stroke': 'e',
    'isLabel': 'i',
    'linestyle': 'l',
    'name' : 'n',
    'opacity': 'o',
    'shape': 's',
    'size': 't'
  };

  /**
   * @type {ngeo.format.FeatureHash}
   * @private
   */
  this.fhFormat_ = new ngeo.format.FeatureHash({
    encodeStyles: false,
    properties: (
        goog.bind(
        /**
         * @param {ol.Feature} feature Feature.
         * @return {Object.<string, (string|number)>} Properties to encode.
         */
        function(feature) {
          // Do not encode the __editable__ and __selected__ properties.
          var properties = feature.getProperties();
          delete properties['__editable__'];
          delete properties['__selected__'];
          delete properties['__map_id__'];
          for (var key in properties) {
            if (!properties[key]) {
              delete properties[key];
            } else {
              if (this.SHORT_PARAM_[key]) {
                var value = properties[key];
                delete properties[key];
                properties[this.SHORT_PARAM_[key]] = value;
              }
            }
          }
          return properties;
        },this))
  });

  /**
   * @type {ol.FeatureStyleFunction}
   * @private
   */
  this.featureStyleFunction_ = this.appMymaps_.createStyleFunction();
};

/**
 * Remove the feature from the drawn list.
 * If the feature is a mymaps feature then delete it from mymaps and
 * then rewrite the url.
 * @param {ol.Feature} feature The feature to remove.
 */
app.DrawnFeatures.prototype.remove = function(feature) {
  this.features.remove(feature);
  if (!!feature.get('__map_id__')) {
    if (this.appMymaps_.isEditable()) {
      this.appMymaps_.deleteFeature(feature);
    }
  }
  this.encodeFeaturesInUrl_(this.features.getArray());
};

/**
 * Add a feature in the drawn feature list.
 * Save it into mymaps and rewrite the url.
 * @param {ol.Feature} feature The feature to add.
 */
app.DrawnFeatures.prototype.add = function(feature) {
  var features = this.features.getArray().slice();
  features.push(feature);
  this.saveFeature(feature);
  this.encodeFeaturesInUrl_(features);
};

/**
 * @param {Array.<ol.Feature>} features Features to encode in the URL.
 * @private
 */
app.DrawnFeatures.prototype.encodeFeaturesInUrl_ = function(features) {
  var featuresToEncode = features.filter(function(feature) {
    return !feature.get('__map_id__');
  });
  if (featuresToEncode.length > 0) {
    this.ngeoLocation_.updateParams({
      'features': this.fhFormat_.writeFeatures(featuresToEncode)
    });
  } else {
    this.ngeoLocation_.deleteParam('features');
  }
};

/**
 * Save the feature either in url or in mymaps if the current user
 * has the permissions.
 * @param {ol.Feature} feature The feature to save.
 */
app.DrawnFeatures.prototype.saveFeature = function(feature) {
  if (this.appMymaps_.isEditable() &&
      !!feature.get('__map_id__')) {
    this.saveFeatureInMymaps_(feature);
  }
  this.encodeFeaturesInUrl_(this.features.getArray());
};

/**
 * Move anonymous features to mymaps
 * @return {angular.$q.Promise} Promise.
 */
app.DrawnFeatures.prototype.moveAnonymousFeaturesToMymaps = function() {
  var newMymapsFeatures = [];
  this.features.getArray().map(goog.bind(function(feature) {
    if (!feature.get('__map_id__')) {
      feature.set('__map_id__', this.appMymaps_.getMapId());
      newMymapsFeatures.push(feature);
    }
  }, this));

  return this.saveFeaturesInMymaps_(newMymapsFeatures);
};

/**
 * Decode the features encoded in the URL and add them to the collection
 * of drawn features.
 */
app.DrawnFeatures.prototype.drawFeaturesInUrl = function() {
  var encodedFeatures = this.ngeoLocation_.getParam('features');
  if (goog.isDef(encodedFeatures)) {
    var remoteFeatures = this.fhFormat_.readFeatures(encodedFeatures);
    goog.asserts.assert(!goog.isNull(remoteFeatures));
    goog.array.forEach(remoteFeatures, goog.bind(function(feature) {
      var properties = feature.getProperties();
      for (var key in this.SHORT_PARAM_) {
        if (properties[this.SHORT_PARAM_[key]]) {
          feature.set(key, properties[this.SHORT_PARAM_[key]]);
          feature.unset(this.SHORT_PARAM_[key]);
        }
      }
      var opacity = /** @type {string} */ (feature.get('opacity'));
      feature.set('opacity', +opacity);
      var stroke = /** @type {string} */ (feature.get('stroke'));
      feature.set('stroke', +stroke);
      var size = /** @type {string} */ (feature.get('size'));
      feature.set('size', +size);
      var angle = /** @type {string} */ (feature.get('angle'));
      feature.set('angle', +angle);
      var isLabel = /** @type {string} */ (feature.get('isLabel'));
      feature.set('isLabel', isLabel === 'true');
      feature.set('__editable__', true);
      feature.set('__map_id__', undefined);
      feature.setStyle(this.featureStyleFunction_);
    },this));

    this.features.extend(remoteFeatures);
  }
};

/**
 * @param {ol.Feature} feature Feature to save in mymaps.
 * @private
 */
app.DrawnFeatures.prototype.saveFeatureInMymaps_ = function(feature) {
  var currentFeature = feature;
  if (this.appMymaps_.isEditable() && !feature.get('__saving__')) {
    feature.set('__saving__', true);
    this.appMymaps_.saveFeature(feature)
      .then(goog.bind(function(resp) {
          var featureId = resp['id'];
          currentFeature.set('id', featureId);
          feature.set('__saving__', false);
        }, this));
  }
};

/**
 * @param {Array.<ol.Feature>} features An array of features to save in mymaps.
 * @return {angular.$q.Promise} Promise.
 * @private
 */
app.DrawnFeatures.prototype.saveFeaturesInMymaps_ = function(features) {
  return this.appMymaps_.saveFeatures(features);
};

/**
 * Clear the drawn features.
 */
app.DrawnFeatures.prototype.clear = function() {
  this.features.clear();
  this.appMymaps_.clear();
};

/**
 * Clear the features belonging to mymaps.
 */
app.DrawnFeatures.prototype.clearMymapsFeatures = function() {
  var mymapsFeatures = this.features.getArray().filter(function(feature) {
    return !!feature.get('__map_id__');
  });

  mymapsFeatures.forEach(goog.bind(function(feature) {
    this.features.remove(feature);
  }, this));
  this.appMymaps_.clear();
  this.encodeFeaturesInUrl_(this.features.getArray());
};

/**
 * Clear the anonymous features.
 */
app.DrawnFeatures.prototype.clearAnonymousFeatures = function() {
  var anonymousFeatures = this.features.getArray().filter(function(feature) {
    return !feature.get('__map_id__');
  });

  anonymousFeatures.forEach(goog.bind(function(feature) {
    this.features.remove(feature);
  }, this));
  this.encodeFeaturesInUrl_(this.features.getArray());
};

/**
 * Get the current drawn features as an array.
 * @return {Array.<ol.Feature>?} The features array.
 */
app.DrawnFeatures.prototype.getArray = function() {
  return this.features.getArray();
};

/**
 * Get the current drawn features as a Collection.
 * @return {ol.Collection} The collection of drawn features.
 */
app.DrawnFeatures.prototype.getCollection = function() {
  return this.features;
};

app.module.service('appDrawnFeatures', app.DrawnFeatures);
<|endoftext|>


<commit_before><commit_msg>Fix jshint<commit_after><|endoftext|>


<commit_before>import { get as fetch } from 'axios';
import React, { Component, PureComponent, Children } from 'react';
import PropTypes from 'prop-types';
import { render, findDOMNode, unmountComponentAtNode } from 'react-dom';
import { dissoc, memoize, groupBy } from 'ramda';

/**
 * @constant includeMap
 * @type {Object}
 */
const includeMap = [
    { extensions: ['js'],  tag: 'script', attrs: { type: 'text/javascript' } },
    { extensions: ['css'], tag: 'style',  attrs: {} }
];

/**
 * @constant defaultContextTypes
 * @type {Object}
 */
const defaultContextTypes = {
    router: PropTypes.object
};

/**
 * @method throwError
 * @param {String} message
 * @throws {Error}
 * @return {void}
 */
const throwError = message => {
    throw new Error(`ReactShadow: ${message}.`);
};

/**
 * @method fetchInclude
 * @param {String} document
 * @return {Promise}
 */
const fetchInclude = memoize(document => {

    return new Promise(resolve => {
        fetch(document).then(response => response.data).then(resolve).catch(() => resolve(''));
    });

});

/**
 * @method withContext
 * @param {Object} contextTypes
 * @return {ShadowDOM}
 */
export const withContext = contextTypes => {

    /**
     * @method createContextProvider
     * @param {Object} context
     * @return {ContextProvider}
     */
    const createContextProvider = context => {

        /**
         * @class ContextProvider
         * @extends {Component}
         */
        return class ContextProvider extends PureComponent {

            /**
             * @constant propTypes
             * @type {Object}
             */
            static propTypes = {
                children: PropTypes.node.isRequired
            };

            /**
             * @constant childContextTypes
             * @type {Object}
             */
            static childContextTypes = contextTypes;

            /**
             * @method getChildContext
             * @return {Object}
             */
            getChildContext() {
                return context;
            }

            /**
             * @method componentDidCatch
             * @param {String} error
             * @return {void}
             */
            componentDidCatch(error) {
                throwError(error);
            }

            /**
             * @method render
             * @return {XML}
             */
            render() {
                return this.props.children;
            }

        };

    };

    /**
     * @class ShadowDOM
     * @extends Component
     */
    return class ShadowDOM extends Component {

        /**
         * @constant contextTypes
         * @type {Object}
         */
        static contextTypes = contextTypes;

        /**
         * @constant propTypes
         * @type {Object}
         */
        static propTypes = {
            children: PropTypes.node.isRequired,
            include: PropTypes.oneOfType([PropTypes.string, PropTypes.array]).isRequired,
            nodeName: PropTypes.string.isRequired,
            boundaryMode: PropTypes.oneOf(['open', 'closed']).isRequired,
            delegatesFocus: PropTypes.bool.isRequired
        };

        /**
         * @constant defaultProps
         * @type {Object}
         */
        static defaultProps = {
            include: [],
            nodeName: 'span',
            boundaryMode: 'open',
            delegatesFocus: false
        };

        /**
         * @constant state
         * @type {Object}
         */
        state = { resolving: false };

        /**
         * @constant ContextProvider
         * @type {ContextProvider}
         */
        ContextProvider = createContextProvider(this.context);

        /**
         * @constant WrappedComponent
         * @type {Object}
         */
        WrappedComponent = this.props.children;

        /**
         * @method componentDidMount
         * @return {void}
         */
        componentDidMount() {

            const { boundaryMode: mode, delegatesFocus } = this.props;

            // Create the shadow root and take the CSS documents from props.
            const node = findDOMNode(this);
            const root = node.attachShadow ? node.attachShadow({ mode, delegatesFocus }) : node.createShadowRoot();
            const include = [].concat(this.props.include);
            const container = this.wrapContainer();

            // Render the passed in component to the shadow root, and then `setState` if there
            // are no CSS documents to be resolved.
            render(container, root);

            include.length === 0 ? this.setState({ root }) : do {

                // Otherwise we'll fetch and attach the passed in stylesheets which need to be
                // resolved before `state.resolved` becomes `true` again.
                this.setState({ root, resolving: true });
                this.attachIncludes(include).then(() => this.setState({ resolving: false }));

            };

        }

        /**
         * @method componentDidUpdate
         * @return {void}
         */
        componentDidUpdate() {

            // Updates consist of simply rendering the container element into the shadow root again, as
            // the `this.wrapContainer()` element contains the passed in component's children.
            render(this.wrapContainer(), this.state.root);

        }

        /**
         * @method componentWillUnmount
         * @return {void}
         */
        componentWillUnmount() {
            unmountComponentAtNode(this.state.root);
        }

        /**
         * @method wrapContainer
         * @return {Object}
         */
        wrapContainer() {

            // Wrap children in a container if it's an array of children, otherwise simply render the single child
            // which is a valid `ReactElement` instance.
            const { children } = this.props.children.props;
            const child = children.length ? <this.props.nodeName>{children}</this.props.nodeName> : children;
            const ContextProvider = this.ContextProvider;

            /**
             * @method getChildContext
             * @return {Object}
             */
            ContextProvider.prototype.getChildContext = () => this.context;

            return <ContextProvider>{child}</ContextProvider>;

        }

        /**
         * @method attachIncludes
         * @param include {Array}
         * @return {void}
         */
        attachIncludes(include) {

            // Group all of the includes by their extension.
            const groupedFiles = groupBy(file => file.extension)(include.map(path => ({ path, extension: path.split('.').pop() })));
            const includeFiles = Object.keys(groupedFiles).map(extension => {

                const nodeData = includeMap.find(model => model.extensions.includes(extension));
                const files = groupedFiles[extension].map(model => model.path);

                !nodeData && throwError(`Files with extension of "${extension}" are unsupported`);

                const containerElement = document.createElement(nodeData.tag);

                // Apply all of the attributes defined in the `includeMap` to the node.
                Object.keys(nodeData.attrs).map(key => containerElement.setAttribute(key, nodeData.attrs[key]));

                // Load each file individually and then concatenate them.
                return Promise.all(files.map(fetchInclude)).then(fileData => {
                    containerElement.innerHTML = fileData.reduce((xs, fileDatum) => `${xs} ${fileDatum}`).trim();
                    containerElement.innerHTML.length && this.state.root.appendChild(containerElement);
                });

            });

            return Promise.all(includeFiles);

        }

        /**
         * @method throwInvariants
         * @return {Boolean|void}
         */
        throwInvariants() {

            // Ensure that the passed child isn't an array of children.
            Array.isArray(this.props.children) && throwError('You must pass a single child rather than multiple children');

            if (typeof this.props.children.type !== 'string') {

                // Ensure that the passed child has a valid node name.
                throwError('Immediate descendant of <ShadowDOM /> must be a HTML node, rather than a React component');

            }

            return true;

        }

        /**
         * @method render
         * @return {XML}
         */
        render() {

            return this.throwInvariants() && do {

                // Props from the passed component, minus `children` as that's handled by `componentDidMount`.
                const child = Children.only(this.props.children);
                const childProps = dissoc('children', child.props);
                const className = this.state.resolving ? 'resolving' : 'resolved';
                const classNames  = `${childProps.className ? childProps.className : ''} ${className}`.trim();
                const props = { ...childProps, className: classNames };

                <child.type {...props} />;

            };

        }

    };

};

export default withContext(defaultContextTypes);
<commit_msg>Renamed method's name<commit_after>import { get as fetch } from 'axios';
import React, { Component, PureComponent, Children } from 'react';
import PropTypes from 'prop-types';
import { render, findDOMNode, unmountComponentAtNode } from 'react-dom';
import { dissoc, memoize, groupBy } from 'ramda';

/**
 * @constant includeMap
 * @type {Object}
 */
const includeMap = [
    { extensions: ['js'],  tag: 'script', attrs: { type: 'text/javascript' } },
    { extensions: ['css'], tag: 'style',  attrs: {} }
];

/**
 * @constant defaultContextTypes
 * @type {Object}
 */
const defaultContextTypes = {
    router: PropTypes.object
};

/**
 * @method throwError
 * @param {String} message
 * @throws {Error}
 * @return {void}
 */
const throwError = message => {
    throw new Error(`ReactShadow: ${message}.`);
};

/**
 * @method fetchInclude
 * @param {String} document
 * @return {Promise}
 */
const fetchInclude = memoize(document => {

    return new Promise(resolve => {
        fetch(document).then(response => response.data).then(resolve).catch(() => resolve(''));
    });

});

/**
 * @method withContext
 * @param {Object} contextTypes
 * @return {ShadowDOM}
 */
export const withContext = contextTypes => {

    /**
     * @method createContextProvider
     * @param {Object} context
     * @return {ContextProvider}
     */
    const createContextProvider = context => {

        /**
         * @class ContextProvider
         * @extends {Component}
         */
        return class ContextProvider extends PureComponent {

            /**
             * @constant propTypes
             * @type {Object}
             */
            static propTypes = {
                children: PropTypes.node.isRequired
            };

            /**
             * @constant childContextTypes
             * @type {Object}
             */
            static childContextTypes = contextTypes;

            /**
             * @method getChildContext
             * @return {Object}
             */
            getChildContext() {
                return context;
            }

            /**
             * @method componentDidCatch
             * @param {String} error
             * @return {void}
             */
            componentDidCatch(error) {
                throwError(error);
            }

            /**
             * @method render
             * @return {XML}
             */
            render() {
                return this.props.children;
            }

        };

    };

    /**
     * @class ShadowDOM
     * @extends Component
     */
    return class ShadowDOM extends Component {

        /**
         * @constant contextTypes
         * @type {Object}
         */
        static contextTypes = contextTypes;

        /**
         * @constant propTypes
         * @type {Object}
         */
        static propTypes = {
            children: PropTypes.node.isRequired,
            include: PropTypes.oneOfType([PropTypes.string, PropTypes.array]).isRequired,
            nodeName: PropTypes.string.isRequired,
            boundaryMode: PropTypes.oneOf(['open', 'closed']).isRequired,
            delegatesFocus: PropTypes.bool.isRequired
        };

        /**
         * @constant defaultProps
         * @type {Object}
         */
        static defaultProps = {
            include: [],
            nodeName: 'span',
            boundaryMode: 'open',
            delegatesFocus: false
        };

        /**
         * @constant state
         * @type {Object}
         */
        state = { resolving: false };

        /**
         * @constant ContextProvider
         * @type {ContextProvider}
         */
        ContextProvider = createContextProvider(this.context);

        /**
         * @constant WrappedComponent
         * @type {Object}
         */
        WrappedComponent = this.props.children;

        /**
         * @method componentDidMount
         * @return {void}
         */
        componentDidMount() {

            const { boundaryMode: mode, delegatesFocus } = this.props;

            // Create the shadow root and take the CSS documents from props.
            const node = findDOMNode(this);
            const root = node.attachShadow ? node.attachShadow({ mode, delegatesFocus }) : node.createShadowRoot();
            const include = [].concat(this.props.include);
            const container = this.wrapContainer();

            // Render the passed in component to the shadow root, and then `setState` if there
            // are no CSS documents to be resolved.
            render(container, root);

            include.length === 0 ? this.setState({ root }) : do {

                // Otherwise we'll fetch and attach the passed in stylesheets which need to be
                // resolved before `state.resolved` becomes `true` again.
                this.setState({ root, resolving: true });
                this.attachIncludes(include).then(() => this.setState({ resolving: false }));

            };

        }

        /**
         * @method componentDidUpdate
         * @return {void}
         */
        componentDidUpdate() {

            // Updates consist of simply rendering the container element into the shadow root again, as
            // the `this.wrapContainer()` element contains the passed in component's children.
            render(this.wrapContainer(), this.state.root);

        }

        /**
         * @method componentWillUnmount
         * @return {void}
         */
        componentWillUnmount() {
            unmountComponentAtNode(this.state.root);
        }

        /**
         * @method wrapContainer
         * @return {Object}
         */
        wrapContainer() {

            // Wrap children in a container if it's an array of children, otherwise simply render the single child
            // which is a valid `ReactElement` instance.
            const { children } = this.props.children.props;
            const child = children.length ? <this.props.nodeName>{children}</this.props.nodeName> : children;
            const ContextProvider = this.ContextProvider;

            /**
             * @method getChildContext
             * @return {Object}
             */
            ContextProvider.prototype.getChildContext = () => this.context;

            return <ContextProvider>{child}</ContextProvider>;

        }

        /**
         * @method attachIncludes
         * @param include {Array}
         * @return {void}
         */
        attachIncludes(include) {

            // Group all of the includes by their extension.
            const groupedFiles = groupBy(file => file.extension)(include.map(path => ({ path, extension: path.split('.').pop() })));
            const includeFiles = Object.keys(groupedFiles).map(extension => {

                const nodeData = includeMap.find(model => model.extensions.includes(extension));
                const files = groupedFiles[extension].map(model => model.path);

                !nodeData && throwError(`Files with extension of "${extension}" are unsupported`);

                const containerElement = document.createElement(nodeData.tag);

                // Apply all of the attributes defined in the `includeMap` to the node.
                Object.keys(nodeData.attrs).map(key => containerElement.setAttribute(key, nodeData.attrs[key]));

                // Load each file individually and then concatenate them.
                return Promise.all(files.map(fetchInclude)).then(fileData => {
                    containerElement.innerHTML = fileData.reduce((xs, fileDatum) => `${xs} ${fileDatum}`).trim();
                    containerElement.innerHTML.length && this.state.root.appendChild(containerElement);
                });

            });

            return Promise.all(includeFiles);

        }

        /**
         * @method validate
         * @return {Boolean|void}
         */
        validate() {

            // Ensure that the passed child isn't an array of children.
            Array.isArray(this.props.children) && throwError('You must pass a single child rather than multiple children');

            if (typeof this.props.children.type !== 'string') {

                // Ensure that the passed child has a valid node name.
                throwError('Immediate descendant of <ShadowDOM /> must be a HTML node, rather than a React component');

            }

            return true;

        }

        /**
         * @method render
         * @return {XML}
         */
        render() {

            return this.validate() && do {

                // Props from the passed component, minus `children` as that's handled by `componentDidMount`.
                const child = Children.only(this.props.children);
                const childProps = dissoc('children', child.props);
                const className = this.state.resolving ? 'resolving' : 'resolved';
                const classNames  = `${childProps.className ? childProps.className : ''} ${className}`.trim();
                const props = { ...childProps, className: classNames };

                <child.type {...props} />;

            };

        }

    };

};

export default withContext(defaultContextTypes);
<|endoftext|>


<commit_before>export const MONEY_RAISED_EXCLAMATION_POINT_V2 =
  'money-raised-exclamation-point-v2'
export const YAHOO_SEARCH_NEW_USERS = 'yahoo-search-new-users'
export const YAHOO_SEARCH_NEW_USERS_V2 = 'yahoo-search-new-users-v2'
export const YAHOO_SEARCH_EXISTING_USERS = 'yahoo-search-existing-users'
export const SUPPORTING_CAUSE_CHIP = 'supporting-cause-chip'
export const SFAC_EXTENSION_PROMPT = 'sfac-extension-prompt'
export const COLLEGE_AMBASSADOR_2022_NOTIF = 'college-ambassador-2022-notif'
<commit_msg>Reorder constants<commit_after>export const COLLEGE_AMBASSADOR_2022_NOTIF = 'college-ambassador-2022-notif'
export const MONEY_RAISED_EXCLAMATION_POINT_V2 =
  'money-raised-exclamation-point-v2'
export const SFAC_EXTENSION_PROMPT = 'sfac-extension-prompt'
export const SUPPORTING_CAUSE_CHIP = 'supporting-cause-chip'
export const YAHOO_SEARCH_NEW_USERS = 'yahoo-search-new-users'
export const YAHOO_SEARCH_NEW_USERS_V2 = 'yahoo-search-new-users-v2'
export const YAHOO_SEARCH_EXISTING_USERS = 'yahoo-search-existing-users'
<|endoftext|>