<commit_before>'use strict';

//Cookie store constructor
function CookieStore (location, minCustomers, maxCustomers, avgCookies,hourlyAvg, totalOfHour){
  this.location = location;
  this.minCustomers = minCustomers;
  this.maxCustomers = maxCustomers;
  this.avgCookies = avgCookies;
  this.hourlyAvg = hourlyAvg || [];
  this.totalOfDay = 0;
  this.totalOfHour = 0;
}

//Average cookies per hour
CookieStore.prototype.getAvgCookieCount = function(){
  for (var hours = 0; hours < 15; hours++){
    var cookiesPerHour =  Math.floor(Math.random() * ((this.maxCustomers - this.minCustomers + 1) + this.minCustomers) * this.avgCookies);
    this.hourlyAvg.push(cookiesPerHour);
    this.totalOfDay += cookiesPerHour;
  }
};

//Cookie Stores
var firstAndPike = new CookieStore('1st and Pike',23,65,6.3);
var seatac = new CookieStore('Seatac Airport',3,24,1.2);
var seattleCenter = new CookieStore('Seattle Center',11,38,3.7);
var capitolHill = new CookieStore('Capitol Hill',20,38,2.3);
var alki = new CookieStore('Alki',2,16,4.6);

//Cookie store Array
var stores = [firstAndPike,seatac,seattleCenter,capitolHill,alki];

//Time Array
var time = ['6am','7am','8am','9am','10am','11am','12pm','1pm','2pm','3pm','4pm','5pm','6pm','7pm','8pm',];

firstAndPike.getAvgCookieCount();
seatac.getAvgCookieCount();
seattleCenter.getAvgCookieCount();
capitolHill.getAvgCookieCount();
alki.getAvgCookieCount();

console.log(firstAndPike.totalOfDay);
//Table html node
var tableEl = document.createElement('table');

//Table Row for store time
var timeEl = document.createElement('tr');
tableEl.appendChild(timeEl);

//blank header over store names
var storeHrs = document.createElement('th');
storeHrs.textContent = ' ';
tableEl.appendChild(storeHrs);

//lists store hours
for (var t = 0; t < time.length; t++){
  var storeTime = document.createElement('th');
  storeTime.textContent = time[t];
  tableEl.appendChild(storeTime);
}
var totalCount = document.createElement('th');
totalCount.textContent = 'Daily Location Total';
tableEl.appendChild(totalCount);
//table of store names
for ( var i = 0; i < stores.length; i++){
  var currentStore = stores[i];

  //creates rows for each store
  var rowEl = document.createElement('tr');
  tableEl.appendChild(rowEl);

  //lists store names as headers
  var nameEl = document.createElement('th');
  nameEl.textContent = currentStore.location;
  rowEl.appendChild(nameEl);

  //table of average cookie sales per hour
  for(var ii = 0; ii < time.length; ii++){
    var salesEl = document.createElement('td');
    salesEl.textContent = currentStore.hourlyAvg[ii];
    rowEl.appendChild(salesEl);
  };

  //total cookies sold for the day
  var totalDaysCookies = document.createElement('td');
  totalDaysCookies.textContent = currentStore.totalOfDay;
  rowEl.appendChild(totalDaysCookies);
};

//table row for totals/hr
var dayTotalEl = document.createElement('tr');
tableEl.appendChild(dayTotalEl);

//table header for totals/hr
var daySalesEl = document.createElement('th');
daySalesEl.textContent = 'Totals';
tableEl.appendChild(daySalesEl);

document.getElementById('stores').appendChild(tableEl);

//table of first and pike cookie sales

/*
//First and Pike Store
var firstAndPike = {
  location: '1st and Pike',
  minCustomers: 23,
  maxCustomers: 65,
  avgCookiesPerCust: 6.3,
  totalCookies: 0,
  cookiesPerHour: [],
  //Calculation for cookies per hour
  cookiesNeeded: function(){
    for (var i = 6; i < 21; i++){
      var randomNumCustomers = Math.floor(Math.random() * (this.maxCustomers + - this.minCustomers) + this.minCustomers);
      var totalCookiesSold = randomNumCustomers * this.avgCookiesPerCust;
      this.cookiesPerHour.push(parseInt(totalCookiesSold));
    }
  },
  cookieTotal: function(){
    for (var i = 0; i < this.cookiesPerHour.length; i++)
      this.totalCookies += this.cookiesPerHour[i];
  }
};

//Seatac Store
var seatac = {
  location: 'Seatac Airport',
  minCustomers: 3,
  maxCustomers: 24,
  avgCookiesPerCust: 1.2,
  totalCookies: 0,
  cookiesPerHour: [],
  cookiesNeeded: function(){
    for (var i = 6; i < 21; i++){
      var randomNumCustomers = Math.floor(Math.random() * (this.maxCustomers + - this.minCustomers) + this.minCustomers);
      var totalCookiesSold = randomNumCustomers * this.avgCookiesPerCust;
      this.cookiesPerHour.push(parseInt(totalCookiesSold));
    }
  },
  cookieTotal: function(){
    for (var i = 0; i < this.cookiesPerHour.length; i++)
      this.totalCookies += this.cookiesPerHour[i];
  }
};

//Seattle Center Store
var seattleCenter = {
  location: 'Seattle Center',
  minCustomers: 11,
  maxCustomers: 38,
  avgCookiesPerCust: 3.7,
  totalCookies: 0,
  cookiesPerHour: [],
  cookiesNeeded: function(){
    for (var i = 6; i < 21; i++){
      var randomNumCustomers = Math.floor(Math.random() * (this.maxCustomers + - this.minCustomers) + this.minCustomers);
      var totalCookiesSold = randomNumCustomers * this.avgCookiesPerCust;
      this.cookiesPerHour.push(parseInt(totalCookiesSold));
    }
  },
  cookieTotal: function(){
    for (var i = 0; i < this.cookiesPerHour.length; i++)
      this.totalCookies += this.cookiesPerHour[i];
  }
};

// Capitol Hill Store
var capitolHill = {
  location: 'Capitol Hill',
  minCustomers: 20,
  maxCustomers: 38,
  avgCookiesPerCust: 2.3,
  totalCookies: 0,
  cookiesPerHour: [],
  cookiesNeeded: function(){
    for (var i = 6; i < 21; i++){
      var randomNumCustomers = Math.floor(Math.random() * (this.maxCustomers + - this.minCustomers) + this.minCustomers);
      var totalCookiesSold = randomNumCustomers * this.avgCookiesPerCust;
      this.cookiesPerHour.push(parseInt(totalCookiesSold));
    }
  },
  cookieTotal: function(){
    for (var i = 0; i < this.cookiesPerHour.length; i++)
      this.totalCookies += this.cookiesPerHour[i];
  }
};
// Alki Store
var alki = {
  location: 'Alki',
  minCustomers: 2,
  maxCustomers: 16,
  avgCookiesPerCust: 4.6,
  cookiesPerHour: [],
  totalCookies: 0,
  cookiesNeeded: function(){
    for (var i = 6; i < 21; i++){
      var randomNumCustomers = Math.floor(Math.random() * (this.maxCustomers + - this.minCustomers) + this.minCustomers);
      var totalCookiesSold = randomNumCustomers * this.avgCookiesPerCust;
      this.cookiesPerHour.push(parseInt(totalCookiesSold));
    }
  },
  cookieTotal: function(){
    for (var i = 0; i < this.cookiesPerHour.length; i++)
      this.totalCookies += this.cookiesPerHour[i];
  }
};

//Calling function for randomly generated customers per hour
firstAndPike.cookiesNeeded();
seatac.cookiesNeeded();
seattleCenter.cookiesNeeded();
capitolHill.cookiesNeeded();
alki.cookiesNeeded();

//Calling function to count cookie total
firstAndPike.cookieTotal();
seatac.cookieTotal();
seattleCenter.cookieTotal();
capitolHill.cookieTotal();
alki.cookieTotal();

//Array for store hours
var time = ['6am','7am','8am','9am','10am','11am','12pm','1pm','2pm','3pm','4pm','5pm','6pm','7pm','8pm'];

//Array of cookies per hour
var salesPerHour = [firstAndPike.cookiesPerHour,seatac.cookiesPerHour,seattleCenter.cookiesPerHour,capitolHill.cookiesPerHour,alki.cookiesPerHour];
console.log(salesPerHour);

//List for First and Pike
var salesList = document.getElementById('firstPike');

for (var i = 0; i < firstAndPike.cookiesPerHour.length; i++){
  var listTotal = document.createElement('li');
  listTotal.textContent = time[i] + ': ' + firstAndPike.cookiesPerHour[i];
  salesList.appendChild(listTotal);
}
var totalSales = document.createElement('li');
totalSales.textContent = 'Total:' + firstAndPike.totalCookies;
salesList.appendChild(totalSales);

//List for Seatac
var salesList = document.getElementById('seatac');

for (var i = 0; i < seatac.cookiesPerHour.length; i++){
  var listTotal = document.createElement('li');
  listTotal.textContent = time[i] + ': ' + seatac.cookiesPerHour[i];
  salesList.appendChild(listTotal);
}
var totalSales = document.createElement('li');
totalSales.textContent = 'Total:' + seatac.totalCookies;
salesList.appendChild(totalSales);

//List for Seattle Center
var salesList = document.getElementById('scenter');

for (var i = 0; i < seattleCenter.cookiesPerHour.length; i++){
  var listTotal = document.createElement('li');
  listTotal.textContent = time[i] + ': ' + seattleCenter.cookiesPerHour[i];
  salesList.appendChild(listTotal);
}
var totalSales = document.createElement('li');
totalSales.textContent = 'Total:' + seattleCenter.totalCookies;
salesList.appendChild(totalSales);

//List for Capitol Hill
var salesList = document.getElementById('caphill');

for (var i = 0; i < capitolHill.cookiesPerHour.length; i++){
  var listTotal = document.createElement('li');
  listTotal.textContent = time[i] + ': ' + capitolHill.cookiesPerHour[i];
  salesList.appendChild(listTotal);
}
var totalSales = document.createElement('li');
totalSales.textContent = 'Total:' + capitolHill.totalCookies;
salesList.appendChild(totalSales);

//List for alki
var salesList = document.getElementById('alki');

for (var i = 0; i < alki.cookiesPerHour.length; i++){
  var listTotal = document.createElement('li');
  listTotal.textContent = time[i] + ': ' + alki.cookiesPerHour[i];
  salesList.appendChild(listTotal);
}
var totalSales = document.createElement('li');
totalSales.textContent = 'Total:' + alki.totalCookies;
salesList.appendChild(totalSales);

//cookie array
console.log(firstAndPike.totalCookies);
console.log(seatac.totalCookies);
console.log(seattleCenter.totalCookies);
console.log(capitolHill.totalCookies);
console.log(alki.totalCookies);
//total cookies per hour
console.log(firstAndPike.cookiesPerHour);
console.log(seatac.cookiesPerHour);
console.log(seattleCenter.cookiesPerHour);
console.log(capitolHill.cookiesPerHour);
console.log(alki.cookiesPerHour);
/*
var cookieList = document.createElement('li');
//userElement.setAttribute('id','cookie-list');
cookieList.textContent = alki.cookiesPerHour;
sectionEl.appendChild(cookieList);

/*
//Object literal notation
var userFullName = prompt('please enter your full name');
var userEmail = prompt('please enter your email');

var myUser = {
  fullName:userFullName,
  userName:'Carlomari',
  email: userEmail,
  numberOfFollowers: 5,
  login: function(){
    console.log(this.fullName + ' has now loged in!');
  }
};

console.log(myUser);
myUser.login();

console.log('--------PRESENT ELEMENTS!-----------');

//'h1' is an element node type
var userElement = document.createElement('h1'); //step 1
//userElement =

console.log(userElement);
//html element node
userElement.setAttribute('id', 'first-user-heading'); //step 2
//userElement =

userElement.textContent = myUser.fullName;
//userElement =
someUserName

//place on top of page
var sectionEl = document.getElementById('main-content');
//sectionEl =

sectionEl.appendChild(userElement); //Step 3
/*
//Gcode
var userHeadingEl = document.getElementById('first-user-heading'); //alt step 1
userHeadingEl.textContent = myUser.fullName; //alt step 2

var userElement = document.createElement('h1'); //step 1
// userElement =

userElement.setAttribute('id', 'first-user-heading'); //step 2
// userElement =

userElement.textContent = myUser.fullName;
//userElement =
someUsername

var sectionEl = document.getElementById('main-content'); //reference to parent
//

sectionEl.appendChild(userElement); //step 3
*/
<commit_msg>removed old code<commit_after>'use strict';

//Cookie store constructor
function CookieStore (location, minCustomers, maxCustomers, avgCookies,hourlyAvg, totalOfHour){
  this.location = location;
  this.minCustomers = minCustomers;
  this.maxCustomers = maxCustomers;
  this.avgCookies = avgCookies;
  this.hourlyAvg = hourlyAvg || [];
  this.totalOfDay = 0;
  this.totalOfHour = 0;
}

//Average cookies per hour
CookieStore.prototype.getAvgCookieCount = function(){
  for (var hours = 0; hours < 15; hours++){
    var cookiesPerHour =  Math.floor(Math.random() * ((this.maxCustomers - this.minCustomers + 1) + this.minCustomers) * this.avgCookies);
    this.hourlyAvg.push(cookiesPerHour);
    this.totalOfDay += cookiesPerHour;
  }
};

//Cookie Stores
var firstAndPike = new CookieStore('1st and Pike',23,65,6.3);
var seatac = new CookieStore('Seatac Airport',3,24,1.2);
var seattleCenter = new CookieStore('Seattle Center',11,38,3.7);
var capitolHill = new CookieStore('Capitol Hill',20,38,2.3);
var alki = new CookieStore('Alki',2,16,4.6);

//Cookie store Array
var stores = [firstAndPike,seatac,seattleCenter,capitolHill,alki];

//Time Array
var time = ['6am','7am','8am','9am','10am','11am','12pm','1pm','2pm','3pm','4pm','5pm','6pm','7pm','8pm',];

firstAndPike.getAvgCookieCount();
seatac.getAvgCookieCount();
seattleCenter.getAvgCookieCount();
capitolHill.getAvgCookieCount();
alki.getAvgCookieCount();

console.log(firstAndPike.totalOfDay);
//Table html node
var tableEl = document.createElement('table');

//Table Row for store time
var timeEl = document.createElement('tr');
tableEl.appendChild(timeEl);

//blank header over store names
var storeHrs = document.createElement('th');
storeHrs.textContent = ' ';
tableEl.appendChild(storeHrs);

//lists store hours
for (var t = 0; t < time.length; t++){
  var storeTime = document.createElement('th');
  storeTime.textContent = time[t];
  tableEl.appendChild(storeTime);
}
var totalCount = document.createElement('th');
totalCount.textContent = 'Daily Location Total';
tableEl.appendChild(totalCount);
//table of store names
for ( var i = 0; i < stores.length; i++){
  var currentStore = stores[i];

  //creates rows for each store
  var rowEl = document.createElement('tr');
  tableEl.appendChild(rowEl);

  //lists store names as headers
  var nameEl = document.createElement('th');
  nameEl.textContent = currentStore.location;
  rowEl.appendChild(nameEl);

  //table of average cookie sales per hour
  for(var ii = 0; ii < time.length; ii++){
    var salesEl = document.createElement('td');
    salesEl.textContent = currentStore.hourlyAvg[ii];
    rowEl.appendChild(salesEl);
  };

  //total cookies sold for the day
  var totalDaysCookies = document.createElement('td');
  totalDaysCookies.textContent = currentStore.totalOfDay;
  rowEl.appendChild(totalDaysCookies);
};

//table row for totals/hr
var dayTotalEl = document.createElement('tr');
tableEl.appendChild(dayTotalEl);

//table header for totals/hr
var daySalesEl = document.createElement('th');
daySalesEl.textContent = 'Totals';
tableEl.appendChild(daySalesEl);

document.getElementById('stores').appendChild(tableEl);
<|endoftext|>


<commit_before>/*
 * @author     Alexander Shumilov
 * @copyright  2013-2018 MapCentia ApS
 * @license    http://www.gnu.org/licenses/#AGPL  GNU AFFERO GENERAL PUBLIC LICENSE 3
 */

'use strict';

const API_URL = `/api/state-snapshots`;

import TitleFieldComponent from './../shared/TitleFieldComponent';

/**
 * @type {*|exports|module.exports}
 */
var cloud, anchor, utils, state, print, urlparser, serializeLayers, backboneEvents;

/**
 *
 * @type {exports|module.exports}
 */
const uuidv4 = require('uuid/v4');

const cookie = require('js-cookie');

let _self = false;

const exId = `state-snapshots`;

/**
 *
 * @type {{set: module.exports.set, init: module.exports.init}}
 */
module.exports = {
    /**
     *
     * @param o
     * @returns {exports}
     */
    set: function (o) {
        anchor = o.anchor;
        cloud = o.cloud;
        state = o.state;
        print = o.print;
        urlparser = o.urlparser;
        serializeLayers = o.serializeLayers;
        backboneEvents = o.backboneEvents;
        utils = o.utils;

        _self = this;
        return this;
    },

    /**
     * Module initialization
     */
    init: function () {
        /**
         *
         */
        var React = require('react');

        /**
         *
         */
        var ReactDOM = require('react-dom');

        let buttonStyle = {
            padding: `4px`,
            margin: `0px`
        };

        /**
         *
         */
        class StateSnapshots extends React.Component {

            constructor(props) {
                super(props);

                this.state = {
                    browserOwnerSnapshots: [],
                    userOwnerSnapshots: [],
                    loading: false,
                    authenticated: false,
                    updatedItemId: false,
                    stateApplyingIsBlocked: false
                };

                this.applySnapshot = this.applySnapshot.bind(this);
                this.createSnapshot = this.createSnapshot.bind(this);
                this.deleteSnapshot = this.deleteSnapshot.bind(this);
                this.seizeSnapshot = this.seizeSnapshot.bind(this);
                this.seizeAllSnapshots = this.seizeAllSnapshots.bind(this);
                this.copyToClipboard = this.copyToClipboard.bind(this);

                // Setting unique cookie if it have not been set yet
                let trackingCookie = uuidv4();
                if (cookie.get('vidi-state-tracker')) {
                    trackingCookie = cookie.get('vidi-state-tracker');
                } else {
                    cookie.set('vidi-state-tracker', trackingCookie);
                }
            }

            /**
             *
             */
            componentDidMount() {
                let _self = this;
                backboneEvents.get().on(`session:authChange`, (authenticated) => {
                    if (this.state.authenticated !== authenticated) {
                        this.setState({ authenticated });
                        this.refreshSnapshotsList();
                    }
                });

                this.refreshSnapshotsList();
            }

            /**
             * Creates snapshot
             *
             * @param {Boolean} anonymous Specifies if the created snapshot belongs to browser or user
             */
            createSnapshot(title, anonymous = false) {
                let _self = this;

                _self.setState({ loading: true });
                state.getState().then(state => {
                    if ('modules' in state === false) {
                        throw new Error(`No modules data in state`);
                    }

                    state.map = anchor.getCurrentMapParameters();
                    $.ajax({
                        url: API_URL + '/' + vidiConfig.appDatabase,
                        method: 'POST',
                        contentType: 'application/json; charset=utf-8',
                        dataType: 'json',
                        data: JSON.stringify({
                            title,
                            anonymous,
                            snapshot: state
                        })
                    }).then(() => {
                        _self.setState({ loading: false });
                        _self.refreshSnapshotsList();
                    });
                });
            }

            /**
             * Applies snapshot
             *
             * @param {Object} item Applies snapshot
             */
            applySnapshot(item) {
                this.setState({ stateApplyingIsBlocked: true });
                state.applyState(item.snapshot).then(() => {
                    this.setState({ stateApplyingIsBlocked: false });
                });
            }

            /**
             * Deletes snapshot
             *
             * @param {String} id Snapshot identifier
             */
            deleteSnapshot(id) {
                if (confirm(`${__(`Delete state snapshot`)}?`)) {
                    let _self = this;
                    $.ajax({
                        url: `${API_URL}/${vidiConfig.appDatabase}/${id}`,
                        method: 'DELETE',
                        dataType: 'json'
                    }).then(data => {
                        _self.refreshSnapshotsList();
                    });
                }
            }

            /**
             * Updates snapshot
             *
             * @param {String} id Snapshot identifier
             */
            updateSnapshot(data, title) {
                let _self = this;

                _self.setState({ loading: true });
                state.getState().then(state => {
                    if ('modules' in state === false) {
                        throw new Error(`No modules data in state`);
                    }

                    state.map = anchor.getCurrentMapParameters();

                    data.title = title;
                    data.snapshot = state;
                    $.ajax({
                        url: `${API_URL}/${vidiConfig.appDatabase}/${data.id}`,
                        method: 'PUT',
                        dataType: 'json',
                        contentType: 'application/json; charset=utf-8',
                        data: JSON.stringify(data)
                    }).then(data => {
                        _self.refreshSnapshotsList();
                        _self.setState({
                            updatedItemId: false,
                            loading: false
                        });
                    });
                });
            }

            /**
             * Enables updat form for snapshot
             *
             * @param {String} id Snapshot identifier
             */
            enableUpdateSnapshotForm(id) {
                this.setState({
                    updatedItemId: id
                });
            }

            /**
             * Makes state snapshot belong to user, not browser
             */
            seizeSnapshot(item) {
                let _self = this;
                if (confirm(`${__(`Add local state snapshot to user's ones`)}?`)) {
                    $.ajax({
                        url: `${API_URL}/${vidiConfig.appDatabase}/${item.id}/seize`,
                        method: 'PUT',
                        dataType: 'json',
                        contentType: 'application/json; charset=utf-8'
                    }).then(data => {
                        _self.refreshSnapshotsList();
                    });
                }
            }

            /**
             * Makes all state snapshots belong to user, not browser
             */
            seizeAllSnapshots() {
                if (confirm(`${__(`Add local state snapshots to user's ones`)}?`)) {
                    let _self = this;
                    let promises = [];
                    this.state.browserOwnerSnapshots.map(item => {
                        promises.push($.ajax({
                            url: `${API_URL}/${vidiConfig.appDatabase}/${item.id}`,
                            method: 'PUT',
                            dataType: 'json',
                            contentType: 'application/json; charset=utf-8',
                            data: JSON.stringify({ anonymous: false })
                        }));
                    });

                    Promise.all(promises).then(() => {
                        _self.refreshSnapshotsList();
                    });
                }
            }

            /**
             * Retrives state snapshots list from server
             */
            refreshSnapshotsList() {
                let _self = this;

                this.setState({ loading: true });
                $.getJSON(API_URL + '/' + vidiConfig.appDatabase).then(data => {
                    let browserOwnerSnapshots = [];
                    let userOwnerSnapshots = [];
                    data.map(item => {
                        if (item.browserId) {
                            browserOwnerSnapshots.push(item);
                        } else if (item.userId) {
                            userOwnerSnapshots.push(item);
                        } else {
                            throw new Error(`Invalid state snapshot`);
                        }
                    });

                    _self.setState({ browserOwnerSnapshots, userOwnerSnapshots, loading: false });
                });
            }

            copyToClipboard (str) {
                const el = document.createElement('textarea');
                el.value = str;
                document.body.appendChild(el);
                el.select();
                document.execCommand('copy');
                document.body.removeChild(el);
            }

            /**
             * Renders the component
             *
             * @returns {XML}
             */
            render() {
                let snapshotIdStyle = {
                    fontFamily: `"Courier New", Courier, "Lucida Sans Typewriter", "Lucida Typewriter", monospace`,
                    marginRight: `10px`
                };

                const createSnapshotRecord = (item, index, local = false) => {
                    let date = new Date(item.created_at);
                    let dateFormatted = (`${date.getHours()}:${date.getMinutes()} ${date.getDate()}-${date.getMonth() + 1}-${date.getFullYear()}`);

                    let importButton = false;
                    if (local && this.state.authenticated) {
                        importButton = (<button type="button" className="btn btn-xs btn-primary" onClick={() => this.seizeSnapshot(item)} style={buttonStyle}>
                            <i title={__(`Add local state snapshot to user's ones`)} className="material-icons">person_add
                        </button>);
                    }

                    let queryParameters = urlparser.uriObj.search(true);
                    let configString = ``;
                    if (`config` in queryParameters && queryParameters.config) {
                        configString = `&config=${queryParameters.config}`;
                    }

                    let permaLink = `${window.location.origin}${anchor.getUri()}?state=${item.id}${configString}`;

                    let titleLabel = ({item.id.substring(0, 6)});
                    if (item.title) {
                        titleLabel = (<span style={{marginRight: `10px`}} title={item.title}>{item.title.substring(0, 24)});
                    }

                    let updateSnapshotControl = (<button
                        type="button"
                        className="btn btn-xs btn-primary"
                        onClick={() => this.enableUpdateSnapshotForm(item.id)}
                        title={__(`Update state snapshot with current application state`)}
                        style={buttonStyle}>
                        autorenew
                    </button>);
                    if (this.state.updatedItemId === item.id) {
                        let type = (local ? 'browserOwned' : 'userOwned')
                        updateSnapshotControl = (<TitleFieldComponent
                            value={item.title}
                            onAdd={(newTitle) => { this.updateSnapshot(item, newTitle) }}
                            onCancel={() => { this.setState({ updatedItemId: false }) }}
                            type={type}/>);
                    }

                    return (

                                {titleLabel}
                                {dateFormatted}
                                <button
                                    type="button"
                                    className="btn btn-xs btn-primary"
                                    onClick={() => { this.applySnapshot(item); }}
                                    disabled={this.state.stateApplyingIsBlocked}
                                    title={__(`Apply state snapshot`)}
                                    style={buttonStyle}>
                                    play_arrow
                                </button>
                                {updateSnapshotControl}
                                <button
                                    type="button"
                                    className="btn btn-xs btn-primary"
                                    onClick={() => this.deleteSnapshot(item.id)}
                                    title={__(`Delete state snapshot`)}
                                    style={buttonStyle}>
                                    delete
                                </button>
                                {importButton}

                                     { this.copyToClipboard(permaLink) }}>{__(`copy link`)}
                                    <input className="form-control" type="text" defaultValue={permaLink}/>

);
                };

                let browserOwnerSnapshots = (<div style={{textAlign: `center`}}>
                    {__(`No local snapshots`)}

);

                let importAllIsDisabled = true;
                if (this.state.browserOwnerSnapshots && this.state.browserOwnerSnapshots.length > 0) {
                    if (this.state.authenticated) importAllIsDisabled = false;

                    browserOwnerSnapshots = [];
                    this.state.browserOwnerSnapshots.map((item, index) => {
                        browserOwnerSnapshots.push(createSnapshotRecord(item, index, true));
                    });
                }

                let userOwnerSnapshots = (<div style={{textAlign: `center`}}>
                    {__(`No user snapshots`)}

);
                if (this.state.userOwnerSnapshots && this.state.userOwnerSnapshots.length > 0) {
                    userOwnerSnapshots = [];
                    this.state.userOwnerSnapshots.map((item, index) => {
                        userOwnerSnapshots.push(createSnapshotRecord(item, index));
                    });
                }

                let userOwnerSnapshotsPanel = false;
                if (this.state.authenticated) {
                    userOwnerSnapshotsPanel = (

                                {__(`User snapshots`)}
                                <TitleFieldComponent onAdd={(title) => { this.createSnapshot(title) }} type="userOwned"/>

{userOwnerSnapshots}

);
                }

                let overlay = false;
                if (this.state.loading) {
                    overlay = (

);
                }

                return (

                    {overlay}

                                    {__(`Local snapshots`)}
                                    <TitleFieldComponent onAdd={(title) => { this.createSnapshot(title, true) }} type="browserOwned"/>
                                    <button className="btn btn-xs btn-primary" onClick={this.seizeAllSnapshots} disabled={importAllIsDisabled} style={buttonStyle}>
                                        person_add
                                    </button>

{browserOwnerSnapshots}

                        {userOwnerSnapshotsPanel}

);
            }
        }

        if (document.getElementById(exId)) {
            try {
                ReactDOM.render(<StateSnapshots/>, document.getElementById(exId));
            } catch (e) {
                console.log(e);
            }
        } else {
            console.warn(`Unable to find the container for offlineMap extension (element id: ${exId})`);
        }
    },

    /**
     * Fetches state snapshot by its identifier
     *
     * @param {String} id State snapshot identifier
     *
     * @return {Promise}
     */
    getSnapshotByID: (id) => {
        if (!id) {
            throw new Error(`Snapshot identifier was not provided`);
        }

        let result = new Promise((resolve, reject) => {
            $.getJSON(`${API_URL}/${vidiConfig.appDatabase}/${id}`).done((data) => {
                resolve(data);
            }).fail(() => {
                resolve(false);
            });
        });

        return result;
    }
};<commit_msg>Keeping the template and config in state snapshots's meta (#263)<commit_after>/*
 * @author     Alexander Shumilov
 * @copyright  2013-2018 MapCentia ApS
 * @license    http://www.gnu.org/licenses/#AGPL  GNU AFFERO GENERAL PUBLIC LICENSE 3
 */

'use strict';

const API_URL = `/api/state-snapshots`;

import TitleFieldComponent from './../shared/TitleFieldComponent';

/**
 * @type {*|exports|module.exports}
 */
var cloud, anchor, utils, state, print, urlparser, serializeLayers, backboneEvents;

/**
 *
 * @type {exports|module.exports}
 */
const uuidv4 = require('uuid/v4');

const cookie = require('js-cookie');

let _self = false;

const exId = `state-snapshots`;

/**
 *
 * @type {{set: module.exports.set, init: module.exports.init}}
 */
module.exports = {
    /**
     *
     * @param o
     * @returns {exports}
     */
    set: function (o) {
        anchor = o.anchor;
        cloud = o.cloud;
        state = o.state;
        print = o.print;
        urlparser = o.urlparser;
        serializeLayers = o.serializeLayers;
        backboneEvents = o.backboneEvents;
        utils = o.utils;

        _self = this;
        return this;
    },

    /**
     * Module initialization
     */
    init: function () {
        /**
         *
         */
        var React = require('react');

        /**
         *
         */
        var ReactDOM = require('react-dom');

        let buttonStyle = {
            padding: `4px`,
            margin: `0px`
        };

        /**
         *
         */
        class StateSnapshots extends React.Component {

            constructor(props) {
                super(props);

                this.state = {
                    browserOwnerSnapshots: [],
                    userOwnerSnapshots: [],
                    loading: false,
                    authenticated: false,
                    updatedItemId: false,
                    stateApplyingIsBlocked: false
                };

                this.applySnapshot = this.applySnapshot.bind(this);
                this.createSnapshot = this.createSnapshot.bind(this);
                this.deleteSnapshot = this.deleteSnapshot.bind(this);
                this.seizeSnapshot = this.seizeSnapshot.bind(this);
                this.seizeAllSnapshots = this.seizeAllSnapshots.bind(this);
                this.copyToClipboard = this.copyToClipboard.bind(this);

                // Setting unique cookie if it have not been set yet
                let trackingCookie = uuidv4();
                if (cookie.get('vidi-state-tracker')) {
                    trackingCookie = cookie.get('vidi-state-tracker');
                } else {
                    cookie.set('vidi-state-tracker', trackingCookie);
                }
            }

            /**
             *
             */
            componentDidMount() {
                let _self = this;
                backboneEvents.get().on(`session:authChange`, (authenticated) => {
                    if (this.state.authenticated !== authenticated) {
                        this.setState({ authenticated });
                        this.refreshSnapshotsList();
                    }
                });

                this.refreshSnapshotsList();
            }

            /**
             * Creates snapshot
             *
             * @param {Boolean} anonymous Specifies if the created snapshot belongs to browser or user
             */
            createSnapshot(title, anonymous = false) {
                let _self = this;

                _self.setState({ loading: true });
                state.getState().then(state => {
                    if ('modules' in state === false) {
                        throw new Error(`No modules data in state`);
                    }

                    state.map = anchor.getCurrentMapParameters();

                    /*
                        Remembering current configuration (config, template), so when state snapshots panel, for example,
                        will be opened for the same browser but with different configuration, generated snapshot
                        links will be correct
                    */
                    let queryParameters = urlparser.uriObj.search(true);
                    state.meta = {};
                    if (`config` in queryParameters && queryParameters.config) {
                        state.meta.config = queryParameters.config;
                    }

                    if (`tmpl` in queryParameters && queryParameters.tmpl) {
                        state.meta.tmpl = queryParameters.tmpl;
                    }

                    $.ajax({
                        url: API_URL + '/' + vidiConfig.appDatabase,
                        method: 'POST',
                        contentType: 'application/json; charset=utf-8',
                        dataType: 'json',
                        data: JSON.stringify({
                            title,
                            anonymous,
                            snapshot: state
                        })
                    }).then(() => {
                        _self.setState({ loading: false });
                        _self.refreshSnapshotsList();
                    });
                });
            }

            /**
             * Applies snapshot
             *
             * @param {Object} item Applies snapshot
             */
            applySnapshot(item) {
                this.setState({ stateApplyingIsBlocked: true });
                state.applyState(item.snapshot).then(() => {
                    this.setState({ stateApplyingIsBlocked: false });
                });
            }

            /**
             * Deletes snapshot
             *
             * @param {String} id Snapshot identifier
             */
            deleteSnapshot(id) {
                if (confirm(`${__(`Delete state snapshot`)}?`)) {
                    let _self = this;
                    $.ajax({
                        url: `${API_URL}/${vidiConfig.appDatabase}/${id}`,
                        method: 'DELETE',
                        dataType: 'json'
                    }).then(data => {
                        _self.refreshSnapshotsList();
                    });
                }
            }

            /**
             * Updates snapshot
             *
             * @param {String} id Snapshot identifier
             */
            updateSnapshot(data, title) {
                let _self = this;

                _self.setState({ loading: true });
                state.getState().then(state => {
                    if ('modules' in state === false) {
                        throw new Error(`No modules data in state`);
                    }

                    state.map = anchor.getCurrentMapParameters();

                    data.title = title;
                    data.snapshot = state;
                    $.ajax({
                        url: `${API_URL}/${vidiConfig.appDatabase}/${data.id}`,
                        method: 'PUT',
                        dataType: 'json',
                        contentType: 'application/json; charset=utf-8',
                        data: JSON.stringify(data)
                    }).then(data => {
                        _self.refreshSnapshotsList();
                        _self.setState({
                            updatedItemId: false,
                            loading: false
                        });
                    });
                });
            }

            /**
             * Enables updat form for snapshot
             *
             * @param {String} id Snapshot identifier
             */
            enableUpdateSnapshotForm(id) {
                this.setState({
                    updatedItemId: id
                });
            }

            /**
             * Makes state snapshot belong to user, not browser
             */
            seizeSnapshot(item) {
                let _self = this;
                if (confirm(`${__(`Add local state snapshot to user's ones`)}?`)) {
                    $.ajax({
                        url: `${API_URL}/${vidiConfig.appDatabase}/${item.id}/seize`,
                        method: 'PUT',
                        dataType: 'json',
                        contentType: 'application/json; charset=utf-8'
                    }).then(data => {
                        _self.refreshSnapshotsList();
                    });
                }
            }

            /**
             * Makes all state snapshots belong to user, not browser
             */
            seizeAllSnapshots() {
                if (confirm(`${__(`Add local state snapshots to user's ones`)}?`)) {
                    let _self = this;
                    let promises = [];
                    this.state.browserOwnerSnapshots.map(item => {
                        promises.push($.ajax({
                            url: `${API_URL}/${vidiConfig.appDatabase}/${item.id}`,
                            method: 'PUT',
                            dataType: 'json',
                            contentType: 'application/json; charset=utf-8',
                            data: JSON.stringify({ anonymous: false })
                        }));
                    });

                    Promise.all(promises).then(() => {
                        _self.refreshSnapshotsList();
                    });
                }
            }

            /**
             * Retrives state snapshots list from server
             */
            refreshSnapshotsList() {
                let _self = this;

                this.setState({ loading: true });
                $.getJSON(API_URL + '/' + vidiConfig.appDatabase).then(data => {
                    let browserOwnerSnapshots = [];
                    let userOwnerSnapshots = [];
                    data.map(item => {
                        if (item.browserId) {
                            browserOwnerSnapshots.push(item);
                        } else if (item.userId) {
                            userOwnerSnapshots.push(item);
                        } else {
                            throw new Error(`Invalid state snapshot`);
                        }
                    });

                    _self.setState({ browserOwnerSnapshots, userOwnerSnapshots, loading: false });
                });
            }

            copyToClipboard (str) {
                const el = document.createElement('textarea');
                el.value = str;
                document.body.appendChild(el);
                el.select();
                document.execCommand('copy');
                document.body.removeChild(el);
            }

            /**
             * Renders the component
             *
             * @returns {XML}
             */
            render() {
                let snapshotIdStyle = {
                    fontFamily: `"Courier New", Courier, "Lucida Sans Typewriter", "Lucida Typewriter", monospace`,
                    marginRight: `10px`
                };

                const createSnapshotRecord = (item, index, local = false) => {
                    let date = new Date(item.created_at);
                    let dateFormatted = (`${date.getHours()}:${date.getMinutes()} ${date.getDate()}-${date.getMonth() + 1}-${date.getFullYear()}`);

                    let importButton = false;
                    if (local && this.state.authenticated) {
                        importButton = (<button type="button" className="btn btn-xs btn-primary" onClick={() => this.seizeSnapshot(item)} style={buttonStyle}>
                            <i title={__(`Add local state snapshot to user's ones`)} className="material-icons">person_add
                        </button>);
                    }

                    let parameters = [];
                    parameters.push(`state=${item.id}`);

                    // Detecting not prioritized parameters from current URL
                    let highPriorityConfigString = false, lowPriorityConfigString = false;
                    let queryParameters = urlparser.uriObj.search(true);
                    if (`config` in queryParameters && queryParameters.config) {
                        lowPriorityConfigString = queryParameters.config;
                    }

                    if (item.snapshot && item.snapshot.meta) {
                        if (item.snapshot.meta.config) {
                            highPriorityConfigString = item.snapshot.meta.config;
                        }

                        if (item.snapshot.meta.tmpl) {
                            parameters.push(`tmpl=${item.snapshot.meta.tmpl}`);
                        }
                    }

                    if (highPriorityConfigString) {
                        parameters.push(`config=${highPriorityConfigString}`);
                    } else if (lowPriorityConfigString) {
                        parameters.push(`config=${lowPriorityConfigString}`);
                    }

                    let permaLink = `${window.location.origin}${anchor.getUri()}?${parameters.join(`&`)}`;

                    let titleLabel = ({item.id.substring(0, 6)});
                    if (item.title) {
                        titleLabel = (<span style={{marginRight: `10px`}} title={item.title}>{item.title.substring(0, 24)});
                    }

                    let updateSnapshotControl = (<button
                        type="button"
                        className="btn btn-xs btn-primary"
                        onClick={() => this.enableUpdateSnapshotForm(item.id)}
                        title={__(`Update state snapshot with current application state`)}
                        style={buttonStyle}>
                        autorenew
                    </button>);
                    if (this.state.updatedItemId === item.id) {
                        let type = (local ? 'browserOwned' : 'userOwned')
                        updateSnapshotControl = (<TitleFieldComponent
                            value={item.title}
                            onAdd={(newTitle) => { this.updateSnapshot(item, newTitle) }}
                            onCancel={() => { this.setState({ updatedItemId: false }) }}
                            type={type}/>);
                    }

                    return (

                                {titleLabel}
                                {dateFormatted}
                                <button
                                    type="button"
                                    className="btn btn-xs btn-primary"
                                    onClick={() => { this.applySnapshot(item); }}
                                    disabled={this.state.stateApplyingIsBlocked}
                                    title={__(`Apply state snapshot`)}
                                    style={buttonStyle}>
                                    play_arrow
                                </button>
                                {updateSnapshotControl}
                                <button
                                    type="button"
                                    className="btn btn-xs btn-primary"
                                    onClick={() => this.deleteSnapshot(item.id)}
                                    title={__(`Delete state snapshot`)}
                                    style={buttonStyle}>
                                    delete
                                </button>
                                {importButton}

                                     { this.copyToClipboard(permaLink) }}>{__(`copy link`)}
                                    <input className="form-control" type="text" defaultValue={permaLink}/>

);
                };

                let browserOwnerSnapshots = (<div style={{textAlign: `center`}}>
                    {__(`No local snapshots`)}

);

                let importAllIsDisabled = true;
                if (this.state.browserOwnerSnapshots && this.state.browserOwnerSnapshots.length > 0) {
                    if (this.state.authenticated) importAllIsDisabled = false;

                    browserOwnerSnapshots = [];
                    this.state.browserOwnerSnapshots.map((item, index) => {
                        browserOwnerSnapshots.push(createSnapshotRecord(item, index, true));
                    });
                }

                let userOwnerSnapshots = (<div style={{textAlign: `center`}}>
                    {__(`No user snapshots`)}

);
                if (this.state.userOwnerSnapshots && this.state.userOwnerSnapshots.length > 0) {
                    userOwnerSnapshots = [];
                    this.state.userOwnerSnapshots.map((item, index) => {
                        userOwnerSnapshots.push(createSnapshotRecord(item, index));
                    });
                }

                let userOwnerSnapshotsPanel = false;
                if (this.state.authenticated) {
                    userOwnerSnapshotsPanel = (

                                {__(`User snapshots`)}
                                <TitleFieldComponent onAdd={(title) => { this.createSnapshot(title) }} type="userOwned"/>

{userOwnerSnapshots}

);
                }

                let overlay = false;
                if (this.state.loading) {
                    overlay = (

);
                }

                return (

                    {overlay}

                                    {__(`Local snapshots`)}
                                    <TitleFieldComponent onAdd={(title) => { this.createSnapshot(title, true) }} type="browserOwned"/>
                                    <button className="btn btn-xs btn-primary" onClick={this.seizeAllSnapshots} disabled={importAllIsDisabled} style={buttonStyle}>
                                        person_add
                                    </button>

{browserOwnerSnapshots}

                        {userOwnerSnapshotsPanel}

);
            }
        }

        if (document.getElementById(exId)) {
            try {
                ReactDOM.render(<StateSnapshots/>, document.getElementById(exId));
            } catch (e) {
                console.log(e);
            }
        } else {
            console.warn(`Unable to find the container for offlineMap extension (element id: ${exId})`);
        }
    },

    /**
     * Fetches state snapshot by its identifier
     *
     * @param {String} id State snapshot identifier
     *
     * @return {Promise}
     */
    getSnapshotByID: (id) => {
        if (!id) {
            throw new Error(`Snapshot identifier was not provided`);
        }

        let result = new Promise((resolve, reject) => {
            $.getJSON(`${API_URL}/${vidiConfig.appDatabase}/${id}`).done((data) => {
                resolve(data);
            }).fail(() => {
                resolve(false);
            });
        });

        return result;
    }
};<|endoftext|>


<commit_before>'use strict';

(function () {

   var profileId = document.querySelector('#profile-id') || null;
   var profileUsername = document.querySelector('#profile-username') || null;
   var profileRepos = document.querySelector('#profile-repos') || null;
   var displayName = document.querySelector('#display-name');
   var apiUrl = appUrl + '/api/:id';

   function updateHtmlElement (data, element, userProperty) {
      element.innerHTML = data[userProperty];
   }

   ajaxFunctions.ready(ajaxFunctions.ajaxRequest('GET', apiUrl, function (data) {
      var userObject = JSON.parse(data);

      if (userObject.displayName !== null) {
         updateHtmlElement(userObject, displayName, 'displayName');
      } else {
         updateHtmlElement(userObject, displayName, 'username');
      }

      if (profileId !== null) {
         updateHtmlElement(userObject, profileId, 'id');
      }

      if (profileUsername !== null) {
         updateHtmlElement(userObject, profileUsername, 'username');
      }

      if (profileRepos !== null) {
         updateHtmlElement(userObject, profileRepos, 'publicRepos');
      }

   }));
})();
<commit_msg>delete userController.client.js<commit_after><|endoftext|>


<commit_before>define([
  'backbone',
  'extensions/models/model',
  'extensions/views/error'
], function (Backbone, Model, ErrorView) {

  var Controller = function (options) {
    options = options || {};
    _.extend(this, options);
    this.initialize.call(this, options);
  };

  _.extend(Controller.prototype, Backbone.Events, {

    initialize: function () {},

    viewOptions: function () {},
    collectionOptions: function () {},
    collectionData: function () { return []; },

    cacheOptions: function() { return 'public, max-age=600'; },

    renderView: function (options) {
      options = _.extend({}, this.viewOptions(), options);

      if (!this.view) {
        this.view = new this.viewClass(options);
      }

      var view = this.view;
      view.render();

      this.html = view.html || view.$el[0].outerHTML;
      this.ready();
    },

    ready: function () {
      setTimeout(_.bind(function () {
        this.trigger('ready');
      }, this), 0);
    },

    render: function (options) {
      options = options || {};

      var getRequestId = function(m) {
        if (m.get('parent')) {
          return m.get('parent').get('requestId');
        }
        return null;
      };

      var getGOVUKRequestId = function(m) {
        if (m.get('parent')) {
          return m.get('parent').get('govukRequestId');
        }
        return null;
      };

      if (this.collectionClass && !this.collection) {
        this.collection = new this.collectionClass(this.collectionData(), _.extend({
          dataSource: this.model.get('data-source'),
          flattenEverything: true,
          requestId: getRequestId(this.model),
          govukRequestId: getGOVUKRequestId(this.model)
        }, this.collectionOptions()));
      }

      var renderViewOptions = _.merge({
        collection: this.collection,
        model: this.model
      }, options);

      if (this.collection && this.collection.isEmpty()) {
        this.listenToOnce(this.collection, 'reset', function () {
          this.renderView(renderViewOptions);
        }, this);
        this.listenToOnce(this.collection, 'error', function () {
          this.viewClass = ErrorView;
          this.renderView(renderViewOptions);
        }, this);

        this.collection.fetch({ reset: true });
      } else {
        this.renderView(renderViewOptions);
      }
    },

    renderModules: function (modules, parentModel, moduleOptions, renderOptions, callback) {
      var remaining = modules.length;

      callback = _.isFunction(callback) ? callback : function () {};
      if (remaining === 0) {
        callback();
        return;
      }

      var loaded = _.bind(function () {
        remaining--;
        if (remaining === 0) {
          this.trigger('loaded');
          callback();
        }
      }, this);

      return _.map(modules, function (definition) {

        if (!definition.controller) {
          // some modules don't have client-side controllers
          loaded();
          return;
        }

        var model = new Model(definition);
        model.set('parent', parentModel);
        model.set('params', parentModel.get('params'));
        var options = _.isFunction(moduleOptions) ? moduleOptions(model) : moduleOptions;

        var module = new definition.controller(_.merge({ model: model }, options));

        module.once('ready', loaded);

        module.render(_.isFunction(renderOptions) ? renderOptions(model) : renderOptions);

        return module;
      }, this);
    }
  });

  Controller.extend = Backbone.Model.extend;

  return Controller;

});
<commit_msg>Log when a there is an error fetching data<commit_after>define([
  'backbone',
  'extensions/models/model',
  'extensions/views/error'
], function (Backbone, Model, ErrorView) {

  var Controller = function (options) {
    options = options || {};
    _.extend(this, options);
    this.initialize.call(this, options);
  };

  _.extend(Controller.prototype, Backbone.Events, {

    initialize: function () {},

    viewOptions: function () {},
    collectionOptions: function () {},
    collectionData: function () { return []; },

    cacheOptions: function() { return 'public, max-age=600'; },

    renderView: function (options) {
      options = _.extend({}, this.viewOptions(), options);

      if (!this.view) {
        this.view = new this.viewClass(options);
      }

      var view = this.view;
      view.render();

      this.html = view.html || view.$el[0].outerHTML;
      this.ready();
    },

    ready: function () {
      setTimeout(_.bind(function () {
        this.trigger('ready');
      }, this), 0);
    },

    render: function (options) {
      options = options || {};

      var getRequestId = function(m) {
        if (m.get('parent')) {
          return m.get('parent').get('requestId');
        }
        return null;
      };

      var getGOVUKRequestId = function(m) {
        if (m.get('parent')) {
          return m.get('parent').get('govukRequestId');
        }
        return null;
      };

      if (this.collectionClass && !this.collection) {
        this.collection = new this.collectionClass(this.collectionData(), _.extend({
          dataSource: this.model.get('data-source'),
          flattenEverything: true,
          requestId: getRequestId(this.model),
          govukRequestId: getGOVUKRequestId(this.model)
        }, this.collectionOptions()));
      }

      var renderViewOptions = _.merge({
        collection: this.collection,
        model: this.model
      }, options);

      if (this.collection && this.collection.isEmpty()) {
        this.listenToOnce(this.collection, 'reset', function () {
          this.renderView(renderViewOptions);
        }, this);
        this.listenToOnce(this.collection, 'error', function (collection, resp) {
          if (collection && resp) {
            var context = { backdrop_url: collection.url(),
              status: resp.status, response_text: resp.responseText,
              govuk_request_id: collection.options.govukRequestId
            };
            logger.info('Error Fetching %s - %s %s ', collection.url(),
              resp.status, resp.responseText, context
            );
          }
          this.viewClass = ErrorView;
          this.renderView(renderViewOptions);
        }, this);

        this.collection.fetch({ reset: true });
      } else {
        this.renderView(renderViewOptions);
      }
    },

    renderModules: function (modules, parentModel, moduleOptions, renderOptions, callback) {
      var remaining = modules.length;

      callback = _.isFunction(callback) ? callback : function () {};
      if (remaining === 0) {
        callback();
        return;
      }

      var loaded = _.bind(function () {
        remaining--;
        if (remaining === 0) {
          this.trigger('loaded');
          callback();
        }
      }, this);

      return _.map(modules, function (definition) {

        if (!definition.controller) {
          // some modules don't have client-side controllers
          loaded();
          return;
        }

        var model = new Model(definition);
        model.set('parent', parentModel);
        model.set('params', parentModel.get('params'));
        var options = _.isFunction(moduleOptions) ? moduleOptions(model) : moduleOptions;

        var module = new definition.controller(_.merge({ model: model }, options));

        module.once('ready', loaded);

        module.render(_.isFunction(renderOptions) ? renderOptions(model) : renderOptions);

        return module;
      }, this);
    }
  });

  Controller.extend = Backbone.Model.extend;

  return Controller;

});
<|endoftext|>


<commit_before>var rp = require('request-promise')
var api = require('./api')
var uploader = require('./uploader')
var EventEmitter = require('events')
var closest = require('closest-str')

class Bot extends EventEmitter {
  /**
  * Create bot instance
  * @param {Object|String} options - Options for creating bot instance (token/botname and token)
  */
  constructor (options) {
    super()
    this.upload = uploader
    if (typeof options === 'object') {
      this.options = options
      uploader.token = options.token
    } else if (typeof options === 'string') {
      this.options = {
        botname: '',
        token: options
      }
      uploader.token = options
    } else {
      throw new Error('Invalid options type')
    }

    var self = this
    /**
    * Set callback, that will be applied to every new message
    * @param {Function} callback - Function that will be executed
    */
    this.use = (callback) => {
      if (typeof callback === 'function') {
        this.useCallback = callback
      } else {
        throw new Error('Invalid callback')
      }
    }
    /**
    * Returns current VK user
    * @return {Object} - User object (id, first_name, last_name)
    */
    this.getMe = () => self.me

    /**
    * Set dictionary for autoanswering
    * @param {Object} dict - Object in format {"key": "value"}
    * @param {Number} percent - Percentage of dictionary element match required for triggering (float, default = 1)
    */
    this.setDict = (dict, percent) => {
      if (dict) {
        self.isDictSet = true
        closest.setdict(dict)
        closest.setlow(percent || 1)
        closest.setlow('nomatch')
        closest.setmax(1)
      } else {
        throw new Error('No dictionary passed')
      }
    }

    /**
    * Start bot
    */
    this.start = async () => {
      var longpollParams = await api('messages.getLongPollServer', {lp_version: 2}, self.options.token)
      var me = await api('users.get', {}, self.options.token)
      self.me = me[0]

      async function loop (ts) {
        var longpollResponse = await rp(`https://${longpollParams.server}?act=a_check&key=${longpollParams.key}&ts=${ts}&wait=25&mode=10&version=2`)
        longpollResponse = JSON.parse(longpollResponse)
        longpollResponse.updates.map((e) => {
          parser(e, self)
        })
        loop(longpollResponse.ts)
      }
      loop(longpollParams.ts)
    }

    this.api = (method, parameters) => {
      api(method, parameters, self.options.token)
    }
  }
}

async function parser (update, self) {
  if (update[0] === 4) {
    var user
    if (update[2] & 2) {
      user = self.me
    } else {
      var u = await api('users.get', {user_ids: update[6].from || update[3]})
      user = u[0]
    }
    var attachments = []
    if (update[6]) {
      for (var i = 1; i < 11; i++) {
        if (update[6]['attach' + i]) {
          attachments.push({
            type: update[6]['attach' + i + '_type'],
            attach: update[6]['attach' + i]
          })
        } else {
          break
        }
      }
    }
    var messageObject = {
      messageId: update[1],
      peerId: update[3],
      text: update[5],
      from: user,
      isOut: Boolean(update[2] & 2),
      attaches: attachments,
      answer: (text) => {
        api('messages.send', {peer_id: update[3], message: text}, self.options.token)
      }
    }

    if (self.useCallback) {
      self.useCallback(messageObject)
    }
    if (!(update[2] & 2)) {
      if (self.options.botname && messageObject.text.startsWith(self.options.botname)) {
        self.emit(update[5].toLowerCase(), messageObject)
      } else if (self.isDictSet && closest.request(messageObject.text).answer !== 'nomatch') {
        messageObject.answer(closest.request(messageObject.text).answer)
      } else {
        self.emit(update[5].toLowerCase(), messageObject)
      }
    }
  }
}

module.exports = Bot
<commit_msg>Added attachments to message.answer function<commit_after>var rp = require('request-promise')
var api = require('./api')
var uploader = require('./uploader')
var EventEmitter = require('events')
var closest = require('closest-str')

class Bot extends EventEmitter {
  /**
  * Create bot instance
  * @param {Object|String} options - Options for creating bot instance (token/botname and token)
  */
  constructor (options) {
    super()
    this.upload = uploader
    if (typeof options === 'object') {
      this.options = options
      uploader.token = options.token
    } else if (typeof options === 'string') {
      this.options = {
        botname: '',
        token: options
      }
      uploader.token = options
    } else {
      throw new Error('Invalid options type')
    }

    var self = this
    /**
    * Set callback, that will be applied to every new message
    * @param {Function} callback - Function that will be executed
    */
    this.use = (callback) => {
      if (typeof callback === 'function') {
        this.useCallback = callback
      } else {
        throw new Error('Invalid callback')
      }
    }
    /**
    * Returns current VK user
    * @return {Object} - User object (id, first_name, last_name)
    */
    this.getMe = () => self.me

    /**
    * Set dictionary for autoanswering
    * @param {Object} dict - Object in format {"key": "value"}
    * @param {Number} percent - Percentage of dictionary element match required for triggering (float, default = 1)
    */
    this.setDict = (dict, percent) => {
      if (dict) {
        self.isDictSet = true
        closest.setdict(dict)
        closest.setlow(percent || 1)
        closest.setlow('nomatch')
        closest.setmax(1)
      } else {
        throw new Error('No dictionary passed')
      }
    }

    /**
    * Start bot
    */
    this.start = async () => {
      var longpollParams = await api('messages.getLongPollServer', {lp_version: 2}, self.options.token)
      var me = await api('users.get', {}, self.options.token)
      self.me = me[0]

      async function loop (ts) {
        var longpollResponse = await rp(`https://${longpollParams.server}?act=a_check&key=${longpollParams.key}&ts=${ts}&wait=25&mode=10&version=2`)
        longpollResponse = JSON.parse(longpollResponse)
        longpollResponse.updates.map((e) => {
          parser(e, self)
        })
        loop(longpollResponse.ts)
      }
      loop(longpollParams.ts)
    }

    this.api = (method, parameters) => {
      api(method, parameters, self.options.token)
    }
  }
}

async function parser (update, self) {
  if (update[0] === 4) {
    var user
    if (update[2] & 2) {
      user = self.me
    } else {
      var u = await api('users.get', {user_ids: update[6].from || update[3]})
      user = u[0]
    }
    var attachments = []
    if (update[6]) {
      for (var i = 1; i < 11; i++) {
        if (update[6]['attach' + i]) {
          attachments.push({
            type: update[6]['attach' + i + '_type'],
            attach: update[6]['attach' + i]
          })
        } else {
          break
        }
      }
    }
    var messageObject = {
      messageId: update[1],
      peerId: update[3],
      text: update[5],
      from: user,
      isOut: Boolean(update[2] & 2),
      attaches: attachments,
      answer: (text, attach) => {
        var attachment = []
        if (Array.isArray(attach)) attachment = attach
        else if (!attach) attachment = undefined
        else attachment[0] = attach

        api('messages.send', {peer_id: update[3], message: text, attachment}, self.options.token)
      }
    }

    if (self.useCallback) {
      self.useCallback(messageObject)
    }
    if (!(update[2] & 2)) {
      if (self.options.botname && messageObject.text.startsWith(self.options.botname)) {
        self.emit(update[5].toLowerCase(), messageObject)
      } else if (self.isDictSet && closest.request(messageObject.text).answer !== 'nomatch') {
        messageObject.answer(closest.request(messageObject.text).answer)
      } else {
        self.emit(update[5].toLowerCase(), messageObject)
      }
    }
  }
}

module.exports = Bot
<|endoftext|>


<commit_before>'use strict';

/**
 * PropertyCollectionCtrl
 * Controller which holds all the properties of a subject.
 */

angular.module('GSB.controllers.propertyCollection', ['GSB.config', 'GSB.services.availableClasses'])
//Inject $scope, $http, $log and globalConfig (see @js/config.js, @js/services/availableClasses.js) into controller
  .controller('PropertyCollectionCtrl', ['$scope', '$http', '$q', '$log', 'globalConfig', 'AvailablePropertiesService', function($scope, $http, $q, $log, globalConfig, AvailablePropertiesService) {

    var selectedProperties = $scope.subjectInst.selectedProperties;
    AvailablePropertiesService.getProperties($scope.subjectInst.uri)
      .then(function(data) {
        console.log('HIER', data);
        $scope.subjectInst.availableProperties = data;
      }, function(error) {
        console.log('alles doof');
      });
    $scope.propertyOperators = globalConfig.propertyOperators;

    /**
     * Adds a property selected from the availableProperties of a
     * subjectInst to the selectedProperties of the same subjectInst
     */
    $scope.addProperty = function(){
      selectedProperties.push(angular.copy($scope.propertySelected));
      $scope.propertySelected = '';
    };

    /**
     * Removes a given propertyInst from the selectedProperties of the subjectInst
     * @param propertyInst
     */
    $scope.removeProperty = function(propertyInst) {
      selectedProperties.splice(selectedProperties.indexOf(propertyInst), 1);
    };

  }]);
<commit_msg>changed error message<commit_after>'use strict';

/**
 * PropertyCollectionCtrl
 * Controller which holds all the properties of a subject.
 */

angular.module('GSB.controllers.propertyCollection', ['GSB.config', 'GSB.services.availableClasses'])
//Inject $scope, $http, $log and globalConfig (see @js/config.js, @js/services/availableClasses.js) into controller
  .controller('PropertyCollectionCtrl', ['$scope', '$http', '$q', '$log', 'globalConfig', 'AvailablePropertiesService', function($scope, $http, $q, $log, globalConfig, AvailablePropertiesService) {

    var selectedProperties = $scope.subjectInst.selectedProperties;
    AvailablePropertiesService.getProperties($scope.subjectInst.uri)
      .then(function(data) {
        $scope.subjectInst.availableProperties = data;
      }, function(error) {
        log.error(error);
      });
    $scope.propertyOperators = globalConfig.propertyOperators;

    /**
     * Adds a property selected from the availableProperties of a
     * subjectInst to the selectedProperties of the same subjectInst
     */
    $scope.addProperty = function(){
      selectedProperties.push(angular.copy($scope.propertySelected));
      $scope.propertySelected = '';
    };

    /**
     * Removes a given propertyInst from the selectedProperties of the subjectInst
     * @param propertyInst
     */
    $scope.removeProperty = function(propertyInst) {
      selectedProperties.splice(selectedProperties.indexOf(propertyInst), 1);
    };

  }]);
<|endoftext|>


<commit_before>import React from 'react'
import PropTypes from 'prop-types'
import createReactClass from 'create-react-class'
import ICRadioButton from './ICRadioButton'

const ICRadioButtonGroup = createReactClass({
  propTypes: {
    name: PropTypes.string.isRequired,
    checked: PropTypes.bool.isRequired,
    defaultChecked: PropTypes.bool.isRequired,
    onChange: PropTypes.func.isRequired,
    buttonItems: React.PropTypes.arrayOf(React.PropTypes.object).isRequired,
    checkedAndDefaultChecked: (props, propName, componentName) => {
      if (props.checked && props.defaultChecked) {
        return new Error(
          `both 'checked' and 'defaultChecked' are present on ${componentName}.`
        )
      }
    }
  },

  getRadioButtons() {
    return this.getDOMNode().querySelectorAll('input[type="radio"]')
  },

  getChecked() {
    const radioButtons = this.getRadioButtons()
    for (var i = 0; i < radioButtons.length; i++) {
      if (radioButtons[i].checked) {
        return radioButtons[i]
      }
    }
  },

  renderRadioButtons() {
    return this.props.buttonItems.map((buttonItem, index) => {
      const id = `${this.props.name}-${index}`

      const checked = this.props.checked === buttonItem.value ? true : false
      return (
        <ICRadioButton
          label={buttonItem.label}
          value={buttonItem.value}
          id={id}
          name={this.props.name}
          key={id}
          checked={checked}
          onChange={this.props.onChange}
        />
      )
    })
  },

  render() {
    return (

        {this.renderRadioButtons()}

    )
  }
})

export default ICRadioButtonGroup
<commit_msg>Fix PropTypes reference<commit_after>import React from 'react'
import PropTypes from 'prop-types'
import createReactClass from 'create-react-class'
import ICRadioButton from './ICRadioButton'

const ICRadioButtonGroup = createReactClass({
  propTypes: {
    name: PropTypes.string.isRequired,
    checked: PropTypes.bool.isRequired,
    defaultChecked: PropTypes.bool.isRequired,
    onChange: PropTypes.func.isRequired,
    buttonItems: PropTypes.arrayOf(PropTypes.object).isRequired,
    checkedAndDefaultChecked: (props, propName, componentName) => {
      if (props.checked && props.defaultChecked) {
        return new Error(
          `both 'checked' and 'defaultChecked' are present on ${componentName}.`
        )
      }
    }
  },

  getRadioButtons() {
    return this.getDOMNode().querySelectorAll('input[type="radio"]')
  },

  getChecked() {
    const radioButtons = this.getRadioButtons()
    for (var i = 0; i < radioButtons.length; i++) {
      if (radioButtons[i].checked) {
        return radioButtons[i]
      }
    }
  },

  renderRadioButtons() {
    return this.props.buttonItems.map((buttonItem, index) => {
      const id = `${this.props.name}-${index}`

      const checked = this.props.checked === buttonItem.value ? true : false
      return (
        <ICRadioButton
          label={buttonItem.label}
          value={buttonItem.value}
          id={id}
          name={this.props.name}
          key={id}
          checked={checked}
          onChange={this.props.onChange}
        />
      )
    })
  },

  render() {
    return (

        {this.renderRadioButtons()}

    )
  }
})

export default ICRadioButtonGroup
<|endoftext|>


<commit_before>const { /* ScopePermissionService, */ ScopeListService } = require('../../helpers/scopePermissions');
const { courseModel } = require('../model');

module.exports = function setup() {
	const app = this;

	ScopeListService.initialize(app, '/users/:scopeId/courses', async (user, permissions, params) => {
		let filter = 'active';
		let substitution = 'false';
		if (params.query.filter && ['active', 'archived', 'all'].includes(params.query.filter)) {
			({ filter } = params.query);
		}
		if (params.query.substitution && ['true', 'false', 'all'].includes(params.query.substitution)) {
			({ substitution } = params.query);
		}

		const userQuery = { $or: [] };
		if (['false', 'all'].includes(substitution)) {
			userQuery.$or.push(
				{ userIds: user._id },
				{ teacherIds: user._id },
			);
		}
		if (['true', 'all'].includes(substitution)) userQuery.$or.push({ substitutionIds: user._id });

		let untilQuery = {};
		if (filter === 'active') {
			untilQuery = {
				$or: [
					{ untilDate: { $exists: false } },
					{ untilDate: { $gte: Date.now() } },
				],
			};
		}
		if (filter === 'archived') {
			untilQuery = { untilDate: { $lt: Date.now() } };
		}

		if (params.query.count === 'true') {
			const courseCount = await courseModel.count({
				$and: [
					userQuery,
					untilQuery,
				],
			});
			return {
				total: courseCount,
			};
		}

		return app.service('courses').find({
			query: {
				$and: [
					userQuery,
					untilQuery,
				],
				$skip: params.query.$skip,
				$limit: params.query.$limit,
			},
			paginate: params.paginate,
		});
	});
};
<commit_msg>added substitutionIds<commit_after>const { /* ScopePermissionService, */ ScopeListService } = require('../../helpers/scopePermissions');
const { courseModel } = require('../model');

module.exports = function setup() {
	const app = this;

	ScopeListService.initialize(app, '/users/:scopeId/courses', async (user, permissions, params) => {
		let filter = 'active';
		let substitution = 'false';
		if (params.query.filter && ['active', 'archived', 'all'].includes(params.query.filter)) {
			({ filter } = params.query);
		}
		if (params.query.substitution && ['true', 'false', 'all'].includes(params.query.substitution)) {
			({ substitution } = params.query);
		}

		const userQuery = { $or: [] };
		if (['false', 'all'].includes(substitution)) {
			userQuery.$or.push(
				{ userIds: user._id },
				{ teacherIds: user._id },
				{ substitutionIds: user._id },
			);
		}
		if (['true', 'all'].includes(substitution)) userQuery.$or.push({ substitutionIds: user._id });

		let untilQuery = {};
		if (filter === 'active') {
			untilQuery = {
				$or: [
					{ untilDate: { $exists: false } },
					{ untilDate: { $gte: Date.now() } },
				],
			};
		}
		if (filter === 'archived') {
			untilQuery = { untilDate: { $lt: Date.now() } };
		}

		if (params.query.count === 'true') {
			const courseCount = await courseModel.count({
				$and: [
					userQuery,
					untilQuery,
				],
			}).exec();
			return {
				total: courseCount,
			};
		}

		return app.service('courses').find({
			query: {
				$and: [
					userQuery,
					untilQuery,
				],
				$skip: params.query.$skip,
				$limit: params.query.$limit,
			},
			paginate: params.paginate,
		});
	});
};
<|endoftext|>


<commit_before>const execSync = require('sync-exec')
const { env } = process
const production = !!env.production
const src = './src'
const dest = env.dest || './dist'
const noGlobals = !!env.noGlobals // don't generate globals bundle
const noMap = !!env.noMap // don't generate .map files
const codap = !!env.codap // include CODAP-specific modifications
const assetsSrc = codap ? src + '/assets/img/*.*' : src + '/assets/**/*.*'
const assetsDst = codap ? dest + '/img/' : dest

const commitHash = execSync('git log -1 --pretty=format:"%H"').stdout
const date = new Date()

// CODAP builds append '.codap' to js filenames to avoid CODAP compilation
const codapOutputFileName = (webpackChunk) => {
  return webpackChunk.chunk.name.match(/\.js$/) ? '[name].ignore': '[name]';
}

const replacementStrings = {
  html: [
    {
      search: /__COMMIT__/g,
      replace: commitHash
    },
    {
      search: /__DATE__/g,
      replace: date.toString()
    }
  ],
  css: [],
  js: []
}

if (codap) {
  replacementStrings.css.push(
    {
      search: /url\(/g,
      replace: 'static_url('
    },
    {
      search: /\.\.\/fonts/g,
      replace: 'webfonts'
    },
    {
      search: /MuseoSans_500_italic/g,
      replace: 'MuseoSans_500_Italic'
    },
    {
      search: /\.\.\/img/g,
      replace: 'cloud-file-manager/img'
    }
  )
}

const appEntries = {
  'js/app.js': './code/app.coffee',
  'css/app': './style/app.styl'
}

const entry = noGlobals
  ? appEntries
  : { 'js/globals.js': './code/globals.coffee', ...appEntries }

const assets = codap
  ? ['img']
  : ['examples', 'fonts', 'img', 'index.html']

const outputFileName = codap
  ? codapOutputFileName
  : '[name]'

module.exports = {
  production,
  date,
  commitHash,
  entry,
  dest,
  assets,
  outputFileName,
  flags: {
    noGlobals,
    noMap,
    codap,
    assetsDst,
    assetsSrc
  },
  replacementStrings
}
<commit_msg>Keep `.ignore` extension for CODAP builds<commit_after>const execSync = require('sync-exec')
const { env } = process
const production = !!env.production
const src = './src'
const dest = env.dest || './dist'
const noGlobals = !!env.noGlobals // don't generate globals bundle
const noMap = !!env.noMap // don't generate .map files
const codap = !!env.codap // include CODAP-specific modifications
const assetsSrc = codap ? src + '/assets/img/*.*' : src + '/assets/**/*.*'
const assetsDst = codap ? dest + '/img/' : dest

const commitHash = execSync('git log -1 --pretty=format:"%H"').stdout
const date = new Date()

// CODAP builds append '.ignore' to js filenames to avoid CODAP compilation
const codapOutputFileName = (webpackChunk) => {
  return webpackChunk.chunk.name.match(/\.js$/) ? '[name].ignore': '[name]';
}

const replacementStrings = {
  html: [
    {
      search: /__COMMIT__/g,
      replace: commitHash
    },
    {
      search: /__DATE__/g,
      replace: date.toString()
    }
  ],
  css: [],
  js: []
}

if (codap) {
  replacementStrings.css.push(
    {
      search: /url\(/g,
      replace: 'static_url('
    },
    {
      search: /\.\.\/fonts/g,
      replace: 'webfonts'
    },
    {
      search: /MuseoSans_500_italic/g,
      replace: 'MuseoSans_500_Italic'
    },
    {
      search: /\.\.\/img/g,
      replace: 'cloud-file-manager/img'
    }
  )
}

const appEntries = {
  'js/app.js': './code/app.coffee',
  'css/app': './style/app.styl'
}

const entry = noGlobals
  ? appEntries
  : { 'js/globals.js': './code/globals.coffee', ...appEntries }

const assets = codap
  ? ['img']
  : ['examples', 'fonts', 'img', 'index.html']

const outputFileName = codap
  ? codapOutputFileName
  : '[name]'

module.exports = {
  production,
  date,
  commitHash,
  entry,
  dest,
  assets,
  outputFileName,
  flags: {
    noGlobals,
    noMap,
    codap,
    assetsDst,
    assetsSrc
  },
  replacementStrings
}
<|endoftext|>


<commit_before>import React, { Component } from 'react'

import {
  StyleSheet,
  Text,
  View,
  Image,
  TouchableHighlight,
  Alert,
  TextInput,
  ScrollView,
  Switch,
  Animated,
  Easing
} from 'react-native'

export default class RatingChart extends Component{
  constructor (props) {
   super(props)
   this.state = {
   }
 }

 render() {
   const {books} = this.props
   return (
     <View style={styles.bookChart}>
     {this.props.posts.sort(function(a,b) {
       let aScore = a.comments_count
       let bScore = b.comments_count
       return aScore - bScore
     }).map(function(post, i) {
       let score = post.comments_count
       if(score >= 25) {
         scoreColor = 'blue'
       }
       if(score > 20 && score < 25) {
         scoreColor = 'green'
       }
       if(score > 15 && score < 20) {
         scoreColor = 'yellow'
       }
       if(score > 10 && score < 15) {
         scoreColor = 'orange'
       }
       if(score < 10) {
         scoreColor = '#E55223'
       }
       return (
         <View style={styles.bookChart} key={i}>
          <Animated.View
            style={[{height: score, backgroundColor:scoreColor}, styles.bar, styles.barRating]} />
         </View>
       )}
     )}
     </View>
   )
 }
}

const styles = StyleSheet.create({
  bookChart: {
    top: 10,
    height: 100,
    flexDirection: 'row',
    justifyContent: 'center',
    margin: 1,
  },
  bar: {
    width: 4,
    borderTopLeftRadius: 5,
    borderTopRightRadius: 5,
    marginLeft: 1,
  }
});
<commit_msg>styles<commit_after>import React, { Component } from 'react'

import {
  StyleSheet,
  Text,
  View,
  Image,
  TouchableHighlight,
  Alert,
  TextInput,
  ScrollView,
  Switch,
  Animated,
  Easing
} from 'react-native'

export default class RatingChart extends Component{
  constructor (props) {
   super(props)
   this.state = {
   }
 }

 render() {
   const {books} = this.props
   return (
     <View style={styles.bookChart}>
     {this.props.posts.sort(function(a,b) {
       let aScore = a.comments_count
       let bScore = b.comments_count
       return aScore - bScore
     }).map(function(post, i) {
       let score = post.comments_count
       if(score >= 10) {
         scoreColor = '#40170A'
       }
       if(score > 5 && score < 10) {
         scoreColor = '#7F2E14'
       }
       if(score < 5) {
         scoreColor = '#E55223'
       }
       return (
         <View style={styles.bookChart} key={i}>
          <Animated.View
            style={[{height: score, backgroundColor:scoreColor}, styles.bar, styles.barRating]} />
         </View>
       )}
     )}
     </View>
   )
 }
}

const styles = StyleSheet.create({
  bookChart: {
    top: 10,
    height: 100,
    flexDirection: 'row',
    justifyContent: 'center',
    margin: 1,
  },
  bar: {
    width: 4,
    borderTopLeftRadius: 5,
    borderTopRightRadius: 5,
    marginLeft: 1,
  }
});
<|endoftext|>


<commit_before>define(
  'ephox.robin.smartselect.EndofWord',

  [
    'ephox.compass.Arr',
    'ephox.perhaps.Option',
    'ephox.phoenix.api.data.Spot',
    'ephox.robin.data.WordRange',
    'ephox.robin.util.CurrentWord'
  ],

  function (Arr, Option, Spot, WordRange, CurrentWord) {
    var select = function (universe, item, offset, left, right) {
      var getText = function (target) {
        return universe.property().isText(target) ? universe.property().getText(target) : '';
      };

      // ASSUMPTION: item is a text node. Probably an invalid assumption. Clean this up.
      var text = universe.property().getText(item);
      var parts = CurrentWord.around(text, offset);

      var leftText = Arr.map(left, function (l) {
        return getText(l.element()).substring(l.offset());
      }).join('');

      var rightText = Arr.map(right, function (r) {
        return getText(r.element()).substring(0, r.offset());
      }).join('');

      var start = Option.from(left[0]).getOr(Spot.point(item, 0));
      var finish = Option.from(right[right.length - 1]).getOr(Spot.point(item, text.length));
      var current = WordRange(item, offset, item, offset);

      var isLeftEdge = function () {
        return leftText.length === 0 && offset === 0;
      };

      var isRightEdge = function () {
        return rightText.length === 0 && offset === text.length;
      };

      var neither = function () {
        return isLeftEdge() || isRightEdge() ? Option.none() :
          Option.some(WordRange(start.element(), start.offset(), finish.element(), finish.offset()));
      };

      var justBefore = function (bindex) {
        return isRightEdge() ? Option.none() : Option.some(WordRange(item, bindex, finish.element(), finish.offset()));
      };

      var justAfter = function (aindex) {
        return isLeftEdge() ? Option.none() : Option.some(WordRange(start.element(), start.offset(), item, aindex));
      };

      var both = function (bindex, aindex) {
        return bindex === aindex ? Option.none() : Option.some(WordRange(item, bindex, item, aindex));
      };

      return parts.before().fold(function () {
        return parts.after().fold(function () {
          return neither();
        }, function (a) {
          return justAfter(a);
        });
      }, function (b) {
        return parts.after().fold(function () {
          return justBefore(b);
        }, function (a) {
          return both(b, a);
        });
      });
    };

    return {
      select: select
    };
  }
);
<commit_msg>TBIO-143: renamed item > textitem<commit_after>define(
  'ephox.robin.smartselect.EndofWord',

  [
    'ephox.compass.Arr',
    'ephox.perhaps.Option',
    'ephox.phoenix.api.data.Spot',
    'ephox.robin.data.WordRange',
    'ephox.robin.util.CurrentWord'
  ],

  function (Arr, Option, Spot, WordRange, CurrentWord) {
    var select = function (universe, textitem, offset, left, right) {
      var getText = function (target) {
        return universe.property().isText(target) ? universe.property().getText(target) : '';
      };

      var text = universe.property().getText(textitem);
      var parts = CurrentWord.around(text, offset);

      var leftText = Arr.map(left, function (l) {
        return getText(l.element()).substring(l.offset());
      }).join('');

      var rightText = Arr.map(right, function (r) {
        return getText(r.element()).substring(0, r.offset());
      }).join('');

      var start = Option.from(left[0]).getOr(Spot.point(textitem, 0));
      var finish = Option.from(right[right.length - 1]).getOr(Spot.point(textitem, text.length));
      var current = WordRange(textitem, offset, textitem, offset);

      var isLeftEdge = function () {
        return leftText.length === 0 && offset === 0;
      };

      var isRightEdge = function () {
        return rightText.length === 0 && offset === text.length;
      };

      var neither = function () {
        return isLeftEdge() || isRightEdge() ? Option.none() :
          Option.some(WordRange(start.element(), start.offset(), finish.element(), finish.offset()));
      };

      var justBefore = function (bindex) {
        return isRightEdge() ? Option.none() : Option.some(WordRange(textitem, bindex, finish.element(), finish.offset()));
      };

      var justAfter = function (aindex) {
        return isLeftEdge() ? Option.none() : Option.some(WordRange(start.element(), start.offset(), textitem, aindex));
      };

      var both = function (bindex, aindex) {
        return bindex === aindex ? Option.none() : Option.some(WordRange(textitem, bindex, textitem, aindex));
      };

      return parts.before().fold(function () {
        return parts.after().fold(function () {
          return neither();
        }, function (a) {
          return justAfter(a);
        });
      }, function (b) {
        return parts.after().fold(function () {
          return justBefore(b);
        }, function (a) {
          return both(b, a);
        });
      });
    };

    return {
      select: select
    };
  }
);
<|endoftext|>