<commit_before>/* call using this enclosure
  (function(){
    var url = 'https://rawgit.com/jamesona/SEO-Tools/master/am-dashboard/dashboard.js';
    document.head.appendChild(document.createElement('script')).src=url;
    function initialize(){
      if (typeof(Dashboard) !== 'undefined' && typeof(ko) !== 'undefined' && ko.dataFor(app) !== undefined) {
          //console.log('Knockout:');console.log(ko);console.log('App:');console.log(ko.dataFor(app));
          db = new Dashboard(ko.dataFor(app))
      } else {
          setTimeout(function(){initialize()}, 100);
      }
    }
    initialize();
  })();
*/

function Dashboard(app) {
  var self = this;
  this.app = app;
  console.log(this.app);
  this.Tools = {
    bobParse: function(raw){
      var clients = [], data = {};
      // exit on null entry
      if ( raw == null ) return;
      for (var cells = raw.replace(/Basic[\r\n\s\ta-z]*Partner ID[\t\s]+/i, '').split(/\t/),
        client = {}, cols = ['Account ID',	'Account Start Date',	'Account Bucket',	'Account Spend',
        'Date of Next Ticket',	'Engaged Status',	'Timezone',	'Welcome Call',	'Keyword Research',
        'Local Profile Tab',	'Obtain or Create Google Logins',	'Create and Verify Google Profile',
        'Obtain Site Access',	'Implement Onsite Edits',	'Create Yahoo Account',	'Create and Verify Yahoo Profile',
        'Create and Verify Bing Profile',	'Install Analytics',	'Company Name',	'Contact Name',	'Website URL',
        'Email Address',	'Phone Number',	'Partner ID',];
        cells.length>0;){
        keys = Object.keys(client).length;
        if (keys<cols.length-1){
          var param = cols[keys];
          client[param] = cells[0];
          cells.shift();
        } else {
          client.count = keys;
          clients.push(client);
          client = {};
        }
      }
      for (var i=0;i<clients.length;i++){
        var date = clients[i]['Date of Next Ticket']
        if (data[date] === undefined) data[date] = [];
        data[date].push(clients[i]);
      }
      return data;
    },
    bobCal: function(){},
    todoistExport: function(){
      var data = ko.dataFor(app).contentViewModel().customersDataTable.dataSource(),
      taskDate = function(day){
        var days = [new Date(),new Date(),new Date()];
        if (days[0].getDay() == 5) {
          days[1].setDate(days[0].getDate()+3);
          days[2].setDate(days[0].getDate()+4);
        } else if (days[0].getDay() == 4) {
          days[1].setDate(days[0].getDate()+1);
          days[2].setDate(days[0].getDate()+4);
        } else {
          days[1].setDate(days[0].getDate()+1);
          days[2].setDate(days[0].getDate()+2);
        }
        return 'date '+days[day].toDateString().substring(4);
      };
      export = data.CustomerId+' - '+data.Name+'[[NOTE]]: https://launchpad.boostability.com/#customerservice/customersearch/'+data.CustomerId;
      export += '\n...'+data.CustomerId+' Welcome Call [['+taskDate(2)+']]';
      export += '\n......'+data.CustomerId+' 1st Welcome Call [['+taskDate(0)+']]';
      export += '\n......'+data.CustomerId+' 1st Welcome Email [['+taskDate(0)+']]';
      export += '\n......'+data.CustomerId+' 2nd Welcome Call [['+taskDate(1)+']]';
      export += '\n......'+data.CustomerId+' 2nd Welcome Email [['+taskDate(1)+']]';
      export += '\n......'+data.CustomerId+' 3rd Welcome Call [['+taskDate(2)+']]';
      export += '\n......'+data.CustomerId+' 3rd Welcome Email [['+taskDate(2)+']]';
      export += '\n...'+data.CustomerId+' Keyword Research';
      export += '\n...'+data.CustomerId+' Local Profile';
      bootbox.alert(export);
    },
    openClient: function(client) {
      self.app.showManageCustomer(client);
    },
    closeClient: function() {
      var buttons = document.getElementsByClassName('close'),
      i = buttons.length - 1;
      if (i >= 1) buttons[i - 1].click();
    },
    createElement: function(parent, tag, attributes) {
      var element = parent.appendChild(document.createElement(tag));
      for (var attribute in attributes) {
        if (attributes.hasOwnProperty(attribute)) {
          element[attribute] = attributes[attribute];
        }
      }
      return element;
    },
  };
  this.Tickets = {
    calendar: function(month, year, data) {
      console.log(data);
      if (typeof(month) == Object) {data = month, month = null;}
      this.current_date = new Date();
      this.day_labels = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
      this.month_labels = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
      this.month = (isNaN(month) || month === null) ? this.current_date.getMonth() : month;
      this.year = (isNaN(year) || year === null) ? this.current_date.getFullYear() : year;
      this.draw = function(ele){
          if (this.month > 11) {
            this.month -= 12;
            this.year += 1;
          } else if (month < 0) {
            this.month += 12;
            this.year -= 1;
          }
          // get dates
          var startingDay = new Date(this.year, this.month, 1).getDay(),
          endingDate = new Date(this.year, this.month + 1, 0),
          monthLength = endingDate.getDate(),
          inLastRow = 6 - endingDate.getDay();

          // generate header
          this.table = document.createElement('table');
          this.head = document.createElement('thead');
          this.prev = document.createElement('th');
          this.next = document.createElement('th');
          this.title = document.createElement('th');
          this.days = document.createElement('tr');
          this.body = document.createElement('tbody');
          this.cells = '';
          this.table.setAttribute('class', 'calendar');
          this.table.appendChild(this.head);
          this.head.appendChild(this.prev);
          this.prev.innerHTML = "«";
          this.prev.id = 'prev';
          this.head.appendChild(this.title);
          this.head.appendChild(this.next);
          this.next.innerHTML = "»";
          this.next.id = 'next';
          this.table.appendChild(this.days);
          this.title.innerHTML = this.month_labels[this.month] + " " + this.year;
          this.title.setAttribute('colspan', '5');
          this.days.setAttribute('class', 'header');
          for (var i = 0; i <= 6; i++ ) this.cells += '' + this.day_labels[i] + '	';
          this.days.innerHTML = this.cells;

          //generate calendar
          var html = '
';
          if ( startingDay ) html += '	';
          for (var day = 1; day <= monthLength; day++) {
          html += '
' + day + '
';
          //if data argument present, append key value for current day
          if (data) {
            var today = (this.month+1)+'/'+day+'/'+this.year;
            if (data[today]) html += '
'+Object.keys(data[today]).length+' Clients
';
          }
          html += '	';
          if ( (day + startingDay) % 7 === 0 && day != monthLength ) html += '

';
          }
          if ( inLastRow ) html += '	';
          html += '
';
          this.table.innerHTML += html;
          if (ele) {
            ele.innerHTML = this.table.outerHTML;
          } else {
            return this.table.outerHTML;
          }
          // save reference to dom node in object
          this.node = ele;
          // save reference to calendar object for enclosure scope
          var cal = this;
              (function(){
            // save calendar object reference for listeners
            var self = this;
                self.prev.addEventListener('click', function(){
              cal.month--;
                    cal.draw(cal.node);
                });
            self.next.addEventListener('click', function(){
                    cal.month++;
              cal.draw(cal.node);
                });
                document.onkeydown = function(e) {
                  e = e || window.event;
                    if (e.keyCode == '37') {
                    // left arrow
                    cal.month--;
                    cal.draw(cal.node);
                    } else if (e.keyCode == '39') {
                        // right arrow
                        cal.month++;
                    cal.draw(cal.node);
                    }
                };
              })();
        };
    },
    getTickets: function() {
      //get tickets
      if (self.app.contentViewModel() !== undefined){
        if (typeof(self.app.contentViewModel().myTickets) === "function"){
          self.Tickets.ticketArray = self.app.contentViewModel().myTickets();
        } else if (localStorage.ticketCache) {
          self.Tickets.ticketArray = JSON.parse(localStorage.ticketCache);
        }
      } else {
        self.Tickets.ticketArray = JSON.parse(localStorage.ticketCache);
      }
      //return results
      if (self.Tickets.ticketArray) {
        localStorage.ticketCache = JSON.stringify(self.Tickets.ticketArray);
        return self.Tickets.ticketArray;
      } else {
        alert('Unable to access tickets at this time!');
        return [];
      }
    },
    getCritical: function() {
      var tickets = this.getTickets(),
      critical = [];
      for (var i = 0; i < tickets.length; i++) {
        if (tickets[i].ScheduledEndDate < new Date()) {
          critical.push(tickets[i]);
        }
      }
      if (tickets.length > 0){
        return critical;
      } else {
        return false;
      }
    },
    countCritical: function() {
      var criticals = self.Tickets.getCritical();
      if (criticals) {
        return 'Critical Tickets: ' + criticals.length + '';
      } else {
        return 'Error loading tickets!';
      }
    },
    sortTickets: function(tickets){
      if (! tickets){
        tickets = this.getTickets();
      }
      var data = {};
      for (var i=0;i<tickets.length;i++){
        var ticket = tickets[i],
        date = new Date(ticket.ScheduledEndDate),
        day = date.getDate()+'/'+(date.getMonth()+1)+'/'+date.getFullYear();
        if (! data[day]){ data[day] = [];}
        data[day].push(ticket);
      }
      return data;
    },
    listTickets: function(tickets){
      var list = document.createElement('ul');
      for (var i=0;i<tickets.length;i++){
        var ticket = tickets[i],
        listItem = document.createElement('li'),
        text = ticket.CompanyName+': '+ticket.TicketTypeName;
        text += ' (Due: '+(ticket.ScheduledEndDate.getMonth()+1);
        text += '/'+ticket.ScheduledEndDate.getDate()+'/';
        text += ticket.ScheduledEndDate.getFullYear()+')';
        listItem.innerHTML = text;
        list.appendChild(listItem);
      }
      return list;
    },
    tryCache: function(){
      try {
        if (self.Tickets.ticketArray) {
          localStorage.ticketCache = JSON.stringify(self.Tickets.ticketArray);
        }
      } catch(err) {
        setTimeout(function(){self.Tickets.tryCache()}, 1000);
      }
    },
  };
  this.HTML = {};
  this.HTML.dashboard = this.Tools.createElement(document.body, 'div', {
        className: 'navbar navbar-inverse navbar-fixed-bottom',
        id: 'dashboard',
  });
  this.HTML.style = this.Tools.createElement(this.HTML.dashboard, 'link', {
    rel: 'stylesheet',
    type: 'text/css',
    href: 'https://rawgit.com/jamesona/SEO-Tools/master/am-dashboard/dashboard.css',
  }),
  this.HTML.nav = this.Tools.createElement(this.HTML.dashboard, 'ul', {
    className: 'nav navbar-nav',
  }),
  this.HTML.tools = this.Tools.createElement(this.HTML.nav, 'li', {
    innerHTML: 'Tools',
    className: 'dropup',
  }),
  this.HTML.toolsMenu = this.Tools.createElement(this.HTML.tools, 'ul', {
    className: 'dropdown-menu',
  }),
  this.HTML.todoistExport = this.Tools.createElement(this.HTML.toolsMenu, 'li', {
    innerHTML: 'Todoist Export',
    onclick: function(){
      self.Tools.todoistExport();
    },
  }),
  this.HTML.tickets = this.Tools.createElement(this.HTML.nav, 'li', {
    innerHTML: 'Tickets',
    className: 'dropup',
  }),
  this.HTML.ticketsMenu = this.Tools.createElement(this.HTML.tickets, 'ul', {
    className: 'dropdown-menu',
  }),
  this.HTML.ticketCalendar = this.Tools.createElement(this.HTML.ticketsMenu, 'li', {
    innerHTML: 'Calendar',
    onclick: function(){
      var node = bootbox.alert('none')[0].children[0].children[0].children[0],
      data = self.Tickets.sortTickets();
      console.log(data);
      calendar = new self.Tickets.calendar(data);
      calendar.draw(node);
    }
  }),
  this.HTML.critical = this.Tools.createElement(this.HTML.nav, 'li', {
    innerHTML: self.Tickets.countCritical(), //'Click to show Critical',
    id: 'critical',
    onclick: function(){this.innerHTML = self.Tickets.countCritical()},
  });

  window.beforeunload = function(){
    self.Tickets.tryCache();
  };
  window.onhashchange = function(){
    if (window.location.href == 'https://launchpad.boostability.com/#/customerservice/activetickets'){
      self.Tickets.tryCache();
    }
  };
  if (localStorage.ticketCache) self.Tickets.ticketArray = JSON.parse(localStorage.ticketCache);
}
<commit_msg>Update dashboard.js<commit_after>/* call using this enclosure
  (function(){
    var url = 'https://rawgit.com/jamesona/SEO-Tools/master/am-dashboard/dashboard.js';
    document.head.appendChild(document.createElement('script')).src=url;
    function initialize(){
      if (typeof(Dashboard) !== 'undefined' && typeof(ko) !== 'undefined' && ko.dataFor(app) !== undefined) {
          //console.log('Knockout:');console.log(ko);console.log('App:');console.log(ko.dataFor(app));
          db = new Dashboard(ko.dataFor(app))
      } else {
          setTimeout(function(){initialize()}, 100);
      }
    }
    initialize();
  })();
*/

function Dashboard(app) {
  var self = this;
  this.app = app;
  console.log(this.app);
  this.Tools = {
    bobParse: function(raw){
      var clients = [], data = {};
      // exit on null entry
      if ( raw == null ) return;
      for (var cells = raw.replace(/Basic[\r\n\s\ta-z]*Partner ID[\t\s]+/i, '').split(/\t/),
        client = {}, cols = ['Account ID',	'Account Start Date',	'Account Bucket',	'Account Spend',
        'Date of Next Ticket',	'Engaged Status',	'Timezone',	'Welcome Call',	'Keyword Research',
        'Local Profile Tab',	'Obtain or Create Google Logins',	'Create and Verify Google Profile',
        'Obtain Site Access',	'Implement Onsite Edits',	'Create Yahoo Account',	'Create and Verify Yahoo Profile',
        'Create and Verify Bing Profile',	'Install Analytics',	'Company Name',	'Contact Name',	'Website URL',
        'Email Address',	'Phone Number',	'Partner ID',];
        cells.length>0;){
        keys = Object.keys(client).length;
        if (keys<cols.length-1){
          var param = cols[keys];
          client[param] = cells[0];
          cells.shift();
        } else {
          client.count = keys;
          clients.push(client);
          client = {};
        }
      }
      for (var i=0;i<clients.length;i++){
        var date = clients[i]['Date of Next Ticket']
        if (data[date] === undefined) data[date] = [];
        data[date].push(clients[i]);
      }
      return data;
    },
    bobCal: function(){},
    todoistExport: function(){
      var data = ko.dataFor(app).contentViewModel().customersDataTable.dataSource(),
      taskDate = function(day){
        var days = [new Date(),new Date(),new Date()];
        if (days[0].getDay() == 5) {
          days[1].setDate(days[0].getDate()+3);
          days[2].setDate(days[0].getDate()+4);
        } else if (days[0].getDay() == 4) {
          days[1].setDate(days[0].getDate()+1);
          days[2].setDate(days[0].getDate()+4);
        } else {
          days[1].setDate(days[0].getDate()+1);
          days[2].setDate(days[0].getDate()+2);
        }
        return 'date '+days[day].toDateString().substring(4);
      };
      text = data.CustomerId+' - '+data.Name+'[[NOTE]]: https://launchpad.boostability.com/#customerservice/customersearch/'+data.CustomerId;
      text += '\n...'+data.CustomerId+' Welcome Call [['+taskDate(2)+']]';
      text += '\n......'+data.CustomerId+' 1st Welcome Call [['+taskDate(0)+']]';
      text += '\n......'+data.CustomerId+' 1st Welcome Email [['+taskDate(0)+']]';
      text += '\n......'+data.CustomerId+' 2nd Welcome Call [['+taskDate(1)+']]';
      text += '\n......'+data.CustomerId+' 2nd Welcome Email [['+taskDate(1)+']]';
      text += '\n......'+data.CustomerId+' 3rd Welcome Call [['+taskDate(2)+']]';
      text += '\n......'+data.CustomerId+' 3rd Welcome Email [['+taskDate(2)+']]';
      text += '\n...'+data.CustomerId+' Keyword Research';
      text += '\n...'+data.CustomerId+' Local Profile';
      bootbox.alert(text);
    },
    openClient: function(client) {
      self.app.showManageCustomer(client);
    },
    closeClient: function() {
      var buttons = document.getElementsByClassName('close'),
      i = buttons.length - 1;
      if (i >= 1) buttons[i - 1].click();
    },
    createElement: function(parent, tag, attributes) {
      var element = parent.appendChild(document.createElement(tag));
      for (var attribute in attributes) {
        if (attributes.hasOwnProperty(attribute)) {
          element[attribute] = attributes[attribute];
        }
      }
      return element;
    },
  };
  this.Tickets = {
    calendar: function(month, year, data) {
      console.log(data);
      if (typeof(month) == Object) {data = month, month = null;}
      this.current_date = new Date();
      this.day_labels = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
      this.month_labels = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
      this.month = (isNaN(month) || month === null) ? this.current_date.getMonth() : month;
      this.year = (isNaN(year) || year === null) ? this.current_date.getFullYear() : year;
      this.draw = function(ele){
          if (this.month > 11) {
            this.month -= 12;
            this.year += 1;
          } else if (month < 0) {
            this.month += 12;
            this.year -= 1;
          }
          // get dates
          var startingDay = new Date(this.year, this.month, 1).getDay(),
          endingDate = new Date(this.year, this.month + 1, 0),
          monthLength = endingDate.getDate(),
          inLastRow = 6 - endingDate.getDay();

          // generate header
          this.table = document.createElement('table');
          this.head = document.createElement('thead');
          this.prev = document.createElement('th');
          this.next = document.createElement('th');
          this.title = document.createElement('th');
          this.days = document.createElement('tr');
          this.body = document.createElement('tbody');
          this.cells = '';
          this.table.setAttribute('class', 'calendar');
          this.table.appendChild(this.head);
          this.head.appendChild(this.prev);
          this.prev.innerHTML = "«";
          this.prev.id = 'prev';
          this.head.appendChild(this.title);
          this.head.appendChild(this.next);
          this.next.innerHTML = "»";
          this.next.id = 'next';
          this.table.appendChild(this.days);
          this.title.innerHTML = this.month_labels[this.month] + " " + this.year;
          this.title.setAttribute('colspan', '5');
          this.days.setAttribute('class', 'header');
          for (var i = 0; i <= 6; i++ ) this.cells += '' + this.day_labels[i] + '	';
          this.days.innerHTML = this.cells;

          //generate calendar
          var html = '
';
          if ( startingDay ) html += '	';
          for (var day = 1; day <= monthLength; day++) {
          html += '
' + day + '
';
          //if data argument present, append key value for current day
          if (data) {
            var today = (this.month+1)+'/'+day+'/'+this.year;
            if (data[today]) html += '
'+Object.keys(data[today]).length+' Clients
';
          }
          html += '	';
          if ( (day + startingDay) % 7 === 0 && day != monthLength ) html += '

';
          }
          if ( inLastRow ) html += '	';
          html += '
';
          this.table.innerHTML += html;
          if (ele) {
            ele.innerHTML = this.table.outerHTML;
          } else {
            return this.table.outerHTML;
          }
          // save reference to dom node in object
          this.node = ele;
          // save reference to calendar object for enclosure scope
          var cal = this;
              (function(){
            // save calendar object reference for listeners
            var self = this;
                self.prev.addEventListener('click', function(){
              cal.month--;
                    cal.draw(cal.node);
                });
            self.next.addEventListener('click', function(){
                    cal.month++;
              cal.draw(cal.node);
                });
                document.onkeydown = function(e) {
                  e = e || window.event;
                    if (e.keyCode == '37') {
                    // left arrow
                    cal.month--;
                    cal.draw(cal.node);
                    } else if (e.keyCode == '39') {
                        // right arrow
                        cal.month++;
                    cal.draw(cal.node);
                    }
                };
              })();
        };
    },
    getTickets: function() {
      //get tickets
      if (self.app.contentViewModel() !== undefined){
        if (typeof(self.app.contentViewModel().myTickets) === "function"){
          self.Tickets.ticketArray = self.app.contentViewModel().myTickets();
        } else if (localStorage.ticketCache) {
          self.Tickets.ticketArray = JSON.parse(localStorage.ticketCache);
        }
      } else {
        self.Tickets.ticketArray = JSON.parse(localStorage.ticketCache);
      }
      //return results
      if (self.Tickets.ticketArray) {
        localStorage.ticketCache = JSON.stringify(self.Tickets.ticketArray);
        return self.Tickets.ticketArray;
      } else {
        alert('Unable to access tickets at this time!');
        return [];
      }
    },
    getCritical: function() {
      var tickets = this.getTickets(),
      critical = [];
      for (var i = 0; i < tickets.length; i++) {
        if (tickets[i].ScheduledEndDate < new Date()) {
          critical.push(tickets[i]);
        }
      }
      if (tickets.length > 0){
        return critical;
      } else {
        return false;
      }
    },
    countCritical: function() {
      var criticals = self.Tickets.getCritical();
      if (criticals) {
        return 'Critical Tickets: ' + criticals.length + '';
      } else {
        return 'Error loading tickets!';
      }
    },
    sortTickets: function(tickets){
      if (! tickets){
        tickets = this.getTickets();
      }
      var data = {};
      for (var i=0;i<tickets.length;i++){
        var ticket = tickets[i],
        date = new Date(ticket.ScheduledEndDate),
        day = date.getDate()+'/'+(date.getMonth()+1)+'/'+date.getFullYear();
        if (! data[day]){ data[day] = [];}
        data[day].push(ticket);
      }
      return data;
    },
    listTickets: function(tickets){
      var list = document.createElement('ul');
      for (var i=0;i<tickets.length;i++){
        var ticket = tickets[i],
        listItem = document.createElement('li'),
        text = ticket.CompanyName+': '+ticket.TicketTypeName;
        text += ' (Due: '+(ticket.ScheduledEndDate.getMonth()+1);
        text += '/'+ticket.ScheduledEndDate.getDate()+'/';
        text += ticket.ScheduledEndDate.getFullYear()+')';
        listItem.innerHTML = text;
        list.appendChild(listItem);
      }
      return list;
    },
    tryCache: function(){
      try {
        if (self.Tickets.ticketArray) {
          localStorage.ticketCache = JSON.stringify(self.Tickets.ticketArray);
        }
      } catch(err) {
        setTimeout(function(){self.Tickets.tryCache()}, 1000);
      }
    },
  };
  this.HTML = {};
  this.HTML.dashboard = this.Tools.createElement(document.body, 'div', {
        className: 'navbar navbar-inverse navbar-fixed-bottom',
        id: 'dashboard',
  });
  this.HTML.style = this.Tools.createElement(this.HTML.dashboard, 'link', {
    rel: 'stylesheet',
    type: 'text/css',
    href: 'https://rawgit.com/jamesona/SEO-Tools/master/am-dashboard/dashboard.css',
  }),
  this.HTML.nav = this.Tools.createElement(this.HTML.dashboard, 'ul', {
    className: 'nav navbar-nav',
  }),
  this.HTML.tools = this.Tools.createElement(this.HTML.nav, 'li', {
    innerHTML: 'Tools',
    className: 'dropup',
  }),
  this.HTML.toolsMenu = this.Tools.createElement(this.HTML.tools, 'ul', {
    className: 'dropdown-menu',
  }),
  this.HTML.todoistExport = this.Tools.createElement(this.HTML.toolsMenu, 'li', {
    innerHTML: 'Todoist Export',
    onclick: function(){
      self.Tools.todoistExport();
    },
  }),
  this.HTML.tickets = this.Tools.createElement(this.HTML.nav, 'li', {
    innerHTML: 'Tickets',
    className: 'dropup',
  }),
  this.HTML.ticketsMenu = this.Tools.createElement(this.HTML.tickets, 'ul', {
    className: 'dropdown-menu',
  }),
  this.HTML.ticketCalendar = this.Tools.createElement(this.HTML.ticketsMenu, 'li', {
    innerHTML: 'Calendar',
    onclick: function(){
      var node = bootbox.alert('none')[0].children[0].children[0].children[0],
      data = self.Tickets.sortTickets();
      console.log(data);
      calendar = new self.Tickets.calendar(data);
      calendar.draw(node);
    }
  }),
  this.HTML.critical = this.Tools.createElement(this.HTML.nav, 'li', {
    innerHTML: self.Tickets.countCritical(), //'Click to show Critical',
    id: 'critical',
    onclick: function(){this.innerHTML = self.Tickets.countCritical()},
  });

  window.beforeunload = function(){
    self.Tickets.tryCache();
  };
  window.onhashchange = function(){
    if (window.location.href == 'https://launchpad.boostability.com/#/customerservice/activetickets'){
      self.Tickets.tryCache();
    }
  };
  if (localStorage.ticketCache) self.Tickets.ticketArray = JSON.parse(localStorage.ticketCache);
}
<|endoftext|>


<commit_before>module('data');

test('D.data & removeData, expected returns', function() {
    expect(4);
    var elem = document.body;

    equal(
        D.data(elem, 'hello', 'world'), 'world',
        'D.data(elem, key, value) returns value'
   );
    equal(
        D.data(elem, 'hello'), 'world',
        'D.data(elem, key) returns value'
   );
    deepEqual(
        D.data(elem, { goodnight: 'moon' }), { goodnight: 'moon' },
        'D.data(elem, obj) returns obj'
   );
    equal(
        D.removeData(elem, 'hello'), undefined,
        'D.removeData(elem, key, value) returns undefined'
   );

});

test('D.hasData no side effects', function() {
    expect(1);

    var obj = document.createElement('div'),
        numNames = _.keys(obj).length;
    D.hasData(obj);

    equal(_.keys(obj).length, numNames,
        'No data expandos where added when calling D.hasData(o)'
    );
});

function dataTests(elem) {
    var dataObj, internalDataObj;

    equal(D.data(elem, 'foo'), undefined, 'No data exists initially');
    strictEqual(D.hasData(elem), false, 'D.hasData agrees no data exists initially');

    strictEqual(D.data(elem), undefined, 'Calling data with no args returns undefined when no data has been set');

    strictEqual(D.hasData(elem), false, 'D.hasData agrees no data exists even when an empty data obj exists');

    D.data(elem, 'bar', 'baz');
    dataObj = D.data(elem);
    deepEqual(dataObj, { bar: 'baz' }, 'TODO: Describe me');

    dataObj.foo = 'bar';
    equal(D.data(elem, 'foo'), 'bar', 'Data is readable by D.data when set directly on a returned data object');

    strictEqual(D.hasData(elem), true, 'D.hasData agrees data exists when data exists');

    D.data(elem, 'foo', 'baz');
    equal(D.data(elem, 'foo'), 'baz', 'Data can be changed by D.data');
    equal(dataObj.foo, 'baz', 'Changes made through D.data propagate to referenced data object');

    D.data(elem, 'foo', undefined);
    strictEqual(D.data(elem, 'foo'), undefined, 'Data is unset by passing undefined to D.data');

    D.data(elem, 'foo', null);
    strictEqual(D.data(elem, 'foo'), null, 'Setting null using D.data works OK');

    D.data(elem, 'foo', 'foo1');

    D.data(elem, { 'bar' : 'baz', 'boom' : 'bloz' });
    strictEqual(D.data(elem, 'foo'), 'foo1', 'Passing an object extends the data object instead of replacing it');
    equal(D.data(elem, 'boom'), 'bloz', 'Extending the data object works');

    // TODO: Test internal event data?
}

test('D.data(div)', function() {
    expect(13);

    var div = document.createElement('div');

    dataTests(div);

    // We stored one key in the private data
    // assert that nothing else was put in there, and that that
    // one stayed there.

    // Stupid jQuery test
//    QUnit.expectJqData(div, 'foo');
});

test('D.data({})', function() {
    expect(13);

    dataTests({});
});

test('D.data(window)', function() {
    expect(13);

    // remove bound handlers from window object to stop potential false positives caused by fix for #5280 in
    // transports/xhr.js
    D(window).off('unload');

    dataTests(window);
});

test('D.data(document)', function() {
    expect(13);

    dataTests(document);

    // Stupid jQuery test
//    QUnit.expectJqData(document, 'foo');
});

test('D.data(<embed>)', function() {
    expect(13);

    dataTests(document.createElement('embed'));
});

test('D.data(<applet>)', function() {
    expect(13);

    dataTests(document.createElement('applet'));
});

test('D.data(object/flash)', function() {
    expect(13);

    var flash = document.createElement('object');
    flash.setAttribute('classid', 'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000');

    dataTests(flash);
});

// attempting to access the data of an undefined D element should be undefined
test('D().data() === undefined (#14101)', 2, function() {
    strictEqual(D().data(), undefined);
    strictEqual(D().data('key'), undefined);
});

test('.data()', function() {
    expect(4);

    var div, dataObj, nodiv, obj;

    div = D('#foo');
    strictEqual(div.data('foo'), undefined, 'Make sure that missing result is undefined');
    div.data('test', 'success');

    dataObj = div.data();

    deepEqual(dataObj, {test: 'success'}, 'data() returns entire data object with expected properties');
    strictEqual(div.data('foo'), undefined, 'Make sure that missing result is still undefined');

    nodiv = D('#unfound');
    equal(nodiv.data(), null, 'data() on empty set returns null');

    obj = { foo: 'bar' };
    D(obj).data('foo', 'baz');
});

function testDataTypes($obj) {
    _.each({
        'null': null,
        'true': true,
        'false': false,
        'zero': 0,
        'one': 1,
        'empty string': '',
        'empty array': [],
        'array': [1],
        'empty object': {},
        'object': { foo: 'bar' },
        'date': new Date(),
        'regex': /test/,
        'function': function() {}
    }, function(value, type) {
        strictEqual($obj.data('test', value).data('test'), value, 'Data set to ' + type);
    });
}

test('D(Element).data(String, Object).data(String)', function() {
    expect(18);
    var parent = D('

'),
        div = parent.children();

    strictEqual(div.data('test'), undefined, 'No data exists initially');
    strictEqual(div.data('test', 'success').data('test'), 'success', 'Data added');
    strictEqual(div.data('test', 'overwritten').data('test'), 'overwritten', 'Data overwritten');
    strictEqual(div.data('test', undefined).data('test'), undefined, '.data(key, undefined) sets value and is is chainable');
    strictEqual(div.data('notexist'), undefined, 'No data exists for unset key');
    testDataTypes(div);

    parent.remove();
});

test('.data(object) does not retain references. #13815', function() {
    expect(2);

    var $divs = D('

').appendTo('#qunit-fixture');

    $divs.data({ 'type': 'foo' });
    $divs.eq(0).data('type', 'bar');

    equal($divs.eq(0).data('type'), 'bar', 'Correct updated value');
    equal($divs.eq(1).data('type'), 'foo', 'Original value retained');
});

test('.data(Object)', function() {
    expect(2);

    var div = D('
');

    div.data({ 'test': 'in', 'test2': 'in2' });
    equal(div.data('test'), 'in', 'Verify setting an object in data');
    equal(div.data('test2'), 'in2', 'Verify setting an object in data');

    // manually clean up detached elements
    div.remove();
});

test('D.removeData', function() {
    expect(10);

    var obj,
        div = D('#foo')[0];
    D.data(div, 'test', 'testing');
    D.removeData(div, 'test');
    equal(D.data(div, 'test'), undefined, 'Check removal of data');

    D.data(div, 'test2', 'testing');
    D.removeData(div);
    ok(!D.data(div, 'test2'), 'Make sure that the data property no longer exists.');
    ok(!div[D.expando], 'Make sure the expando no longer exists, as well.');

    D.data(div, {
        test3: 'testing',
        test4: 'testing'
    });
    D.removeData(div, 'test3 test4');
    ok(!D.data(div, 'test3') || D.data(div, 'test4'), 'Multiple delete with spaces.');

    D.data(div, {
        test3: 'testing',
        test4: 'testing'
    });
    D.removeData(div, ['test3', 'test4']);
    ok(!D.data(div, 'test3') || D.data(div, 'test4'), 'Multiple delete by array.');

    D.data(div, {
        'test3 test4': 'testing',
        'test3': 'testing'
    });
    D.removeData(div, 'test3 test4');
    ok(!D.data(div, 'test3 test4'), 'Multiple delete with spaces deleted key with exact name');
    ok(D.data(div, 'test3'), 'Left the partial matched key alone');

    obj = {};
    D.data(obj, 'test', 'testing');
    equal(D.data(obj, 'test'), 'testing', 'Verify data on plain object');
    D.removeData(obj, 'test');
    equal(D.data(obj, 'test'), undefined, 'Check removal of data on plain object');

    D.data(window, 'BAD', true);
    D.removeData(window, 'BAD');
    ok(!D.data(window, 'BAD'), 'Make sure that the value was not still set.');
});

test('.removeData()', function() {
    expect(6);
    var div = D('#foo');
    div.data('test', 'testing');
    div.removeData('test');
    equal(div.data('test'), undefined, 'Check removal of data');

    div.data('test', 'testing');
    div.data('test.foo', 'testing2');
    div.removeData('test.bar');
    equal(div.data('test.foo'), 'testing2', 'Make sure data is intact');
    equal(div.data('test'), 'testing', 'Make sure data is intact');

    div.removeData('test');
    equal(div.data('test.foo'), 'testing2', 'Make sure data is intact');
    equal(div.data('test'), undefined, 'Make sure data is intact');

    div.removeData('test.foo');
    equal(div.data('test.foo'), undefined, 'Make sure data is intact');
});

test('.data supports interoperable removal of properties SET TWICE #13850', function() {
    var div = D('
').appendTo('#qunit-fixture'),
        datas = {
            'non-empty': 'a string',
            'empty-string': '',
            'one-value': 1,
            'zero-value': 0,
            'an-array': [],
            'an-object': {},
            'bool-true': true,
            'bool-false': false,
            // JSHint enforces double quotes,
            // but JSON strings need double quotes to parse
            // so we need escaped double quotes here
            'some-json': '{ \'foo\': \'bar\' }'
        };

    expect(9);

    _.each(datas, function(val, key) {
        div.data(key, val);
        div.data(key, val);

        div.removeData(key);

        equal(div.data(key), undefined, 'removal: ' + key);
    });
});

test('.removeData supports removal of hyphenated properties via array (#12786)', function() {
    expect(2);

    var div, plain, compare;

    div = D('
').appendTo('#qunit-fixture');

    // When data is batch assigned (via plain object), the properties
    // are not camel cased as they are with (property, value) calls
    compare = {
        // From batch assignment .data({ 'a-a': 1 })
        'a-a': 1,
        // From property, value assignment .data('b-b', 1)
        'b-b': 1
    };

    // Mixed assignment
    div.data({ 'a-a': 1 });
    div.data('b-b', 1);

    deepEqual(div.data(), compare, 'Data appears as expected. (div)');

    div.removeData(['a-a', 'b-b']);

    // NOTE: Timo's proposal for 'propEqual' (or similar) would be nice here
    deepEqual(div.data(), {}, 'Data is empty. (div)');
});

test('.data doesnt throw when calling selection is empty. #13551', function() {
    expect(1);

    try {
        D(null).data('prop');
        ok(true, 'D(null).data("prop") does not throw');
    } catch (e) {
        ok(false, e.message);
    }
});

test('Check proper data removal of non-element descendants nodes (#8335)', function() {
    expect(1);

    // TODO: Implement .contents()?
    var div = D('
text
'),
        text = div.contents();

    text.data('test', 'test'); // This should be a noop.
    div.remove();

    ok(!text.data('test'), 'Be sure data is not stored in non-element');
});
<commit_msg>Minor - remove todo<commit_after>module('data');

test('D.data & removeData, expected returns', function() {
    expect(4);
    var elem = document.body;

    equal(
        D.data(elem, 'hello', 'world'), 'world',
        'D.data(elem, key, value) returns value'
   );
    equal(
        D.data(elem, 'hello'), 'world',
        'D.data(elem, key) returns value'
   );
    deepEqual(
        D.data(elem, { goodnight: 'moon' }), { goodnight: 'moon' },
        'D.data(elem, obj) returns obj'
   );
    equal(
        D.removeData(elem, 'hello'), undefined,
        'D.removeData(elem, key, value) returns undefined'
   );

});

test('D.hasData no side effects', function() {
    expect(1);

    var obj = document.createElement('div'),
        numNames = _.keys(obj).length;
    D.hasData(obj);

    equal(_.keys(obj).length, numNames,
        'No data expandos where added when calling D.hasData(o)'
    );
});

function dataTests(elem) {
    var dataObj, internalDataObj;

    equal(D.data(elem, 'foo'), undefined, 'No data exists initially');
    strictEqual(D.hasData(elem), false, 'D.hasData agrees no data exists initially');

    strictEqual(D.data(elem), undefined, 'Calling data with no args returns undefined when no data has been set');

    strictEqual(D.hasData(elem), false, 'D.hasData agrees no data exists even when an empty data obj exists');

    D.data(elem, 'bar', 'baz');
    dataObj = D.data(elem);
    deepEqual(dataObj, { bar: 'baz' }, 'TODO: Describe me');

    dataObj.foo = 'bar';
    equal(D.data(elem, 'foo'), 'bar', 'Data is readable by D.data when set directly on a returned data object');

    strictEqual(D.hasData(elem), true, 'D.hasData agrees data exists when data exists');

    D.data(elem, 'foo', 'baz');
    equal(D.data(elem, 'foo'), 'baz', 'Data can be changed by D.data');
    equal(dataObj.foo, 'baz', 'Changes made through D.data propagate to referenced data object');

    D.data(elem, 'foo', undefined);
    strictEqual(D.data(elem, 'foo'), undefined, 'Data is unset by passing undefined to D.data');

    D.data(elem, 'foo', null);
    strictEqual(D.data(elem, 'foo'), null, 'Setting null using D.data works OK');

    D.data(elem, 'foo', 'foo1');

    D.data(elem, { 'bar' : 'baz', 'boom' : 'bloz' });
    strictEqual(D.data(elem, 'foo'), 'foo1', 'Passing an object extends the data object instead of replacing it');
    equal(D.data(elem, 'boom'), 'bloz', 'Extending the data object works');

    // TODO: Test internal event data?
}

test('D.data(div)', function() {
    expect(13);

    var div = document.createElement('div');

    dataTests(div);

    // We stored one key in the private data
    // assert that nothing else was put in there, and that that
    // one stayed there.

    // Stupid jQuery test
//    QUnit.expectJqData(div, 'foo');
});

test('D.data({})', function() {
    expect(13);

    dataTests({});
});

test('D.data(window)', function() {
    expect(13);

    // remove bound handlers from window object to stop potential false positives caused by fix for #5280 in
    // transports/xhr.js
    D(window).off('unload');

    dataTests(window);
});

test('D.data(document)', function() {
    expect(13);

    dataTests(document);

    // Stupid jQuery test
//    QUnit.expectJqData(document, 'foo');
});

test('D.data(<embed>)', function() {
    expect(13);

    dataTests(document.createElement('embed'));
});

test('D.data(<applet>)', function() {
    expect(13);

    dataTests(document.createElement('applet'));
});

test('D.data(object/flash)', function() {
    expect(13);

    var flash = document.createElement('object');
    flash.setAttribute('classid', 'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000');

    dataTests(flash);
});

// attempting to access the data of an undefined D element should be undefined
test('D().data() === undefined (#14101)', 2, function() {
    strictEqual(D().data(), undefined);
    strictEqual(D().data('key'), undefined);
});

test('.data()', function() {
    expect(4);

    var div, dataObj, nodiv, obj;

    div = D('#foo');
    strictEqual(div.data('foo'), undefined, 'Make sure that missing result is undefined');
    div.data('test', 'success');

    dataObj = div.data();

    deepEqual(dataObj, {test: 'success'}, 'data() returns entire data object with expected properties');
    strictEqual(div.data('foo'), undefined, 'Make sure that missing result is still undefined');

    nodiv = D('#unfound');
    equal(nodiv.data(), null, 'data() on empty set returns null');

    obj = { foo: 'bar' };
    D(obj).data('foo', 'baz');
});

function testDataTypes($obj) {
    _.each({
        'null': null,
        'true': true,
        'false': false,
        'zero': 0,
        'one': 1,
        'empty string': '',
        'empty array': [],
        'array': [1],
        'empty object': {},
        'object': { foo: 'bar' },
        'date': new Date(),
        'regex': /test/,
        'function': function() {}
    }, function(value, type) {
        strictEqual($obj.data('test', value).data('test'), value, 'Data set to ' + type);
    });
}

test('D(Element).data(String, Object).data(String)', function() {
    expect(18);
    var parent = D('

'),
        div = parent.children();

    strictEqual(div.data('test'), undefined, 'No data exists initially');
    strictEqual(div.data('test', 'success').data('test'), 'success', 'Data added');
    strictEqual(div.data('test', 'overwritten').data('test'), 'overwritten', 'Data overwritten');
    strictEqual(div.data('test', undefined).data('test'), undefined, '.data(key, undefined) sets value and is is chainable');
    strictEqual(div.data('notexist'), undefined, 'No data exists for unset key');
    testDataTypes(div);

    parent.remove();
});

test('.data(object) does not retain references. #13815', function() {
    expect(2);

    var $divs = D('

').appendTo('#qunit-fixture');

    $divs.data({ 'type': 'foo' });
    $divs.eq(0).data('type', 'bar');

    equal($divs.eq(0).data('type'), 'bar', 'Correct updated value');
    equal($divs.eq(1).data('type'), 'foo', 'Original value retained');
});

test('.data(Object)', function() {
    expect(2);

    var div = D('
');

    div.data({ 'test': 'in', 'test2': 'in2' });
    equal(div.data('test'), 'in', 'Verify setting an object in data');
    equal(div.data('test2'), 'in2', 'Verify setting an object in data');

    // manually clean up detached elements
    div.remove();
});

test('D.removeData', function() {
    expect(10);

    var obj,
        div = D('#foo')[0];
    D.data(div, 'test', 'testing');
    D.removeData(div, 'test');
    equal(D.data(div, 'test'), undefined, 'Check removal of data');

    D.data(div, 'test2', 'testing');
    D.removeData(div);
    ok(!D.data(div, 'test2'), 'Make sure that the data property no longer exists.');
    ok(!div[D.expando], 'Make sure the expando no longer exists, as well.');

    D.data(div, {
        test3: 'testing',
        test4: 'testing'
    });
    D.removeData(div, 'test3 test4');
    ok(!D.data(div, 'test3') || D.data(div, 'test4'), 'Multiple delete with spaces.');

    D.data(div, {
        test3: 'testing',
        test4: 'testing'
    });
    D.removeData(div, ['test3', 'test4']);
    ok(!D.data(div, 'test3') || D.data(div, 'test4'), 'Multiple delete by array.');

    D.data(div, {
        'test3 test4': 'testing',
        'test3': 'testing'
    });
    D.removeData(div, 'test3 test4');
    ok(!D.data(div, 'test3 test4'), 'Multiple delete with spaces deleted key with exact name');
    ok(D.data(div, 'test3'), 'Left the partial matched key alone');

    obj = {};
    D.data(obj, 'test', 'testing');
    equal(D.data(obj, 'test'), 'testing', 'Verify data on plain object');
    D.removeData(obj, 'test');
    equal(D.data(obj, 'test'), undefined, 'Check removal of data on plain object');

    D.data(window, 'BAD', true);
    D.removeData(window, 'BAD');
    ok(!D.data(window, 'BAD'), 'Make sure that the value was not still set.');
});

test('.removeData()', function() {
    expect(6);
    var div = D('#foo');
    div.data('test', 'testing');
    div.removeData('test');
    equal(div.data('test'), undefined, 'Check removal of data');

    div.data('test', 'testing');
    div.data('test.foo', 'testing2');
    div.removeData('test.bar');
    equal(div.data('test.foo'), 'testing2', 'Make sure data is intact');
    equal(div.data('test'), 'testing', 'Make sure data is intact');

    div.removeData('test');
    equal(div.data('test.foo'), 'testing2', 'Make sure data is intact');
    equal(div.data('test'), undefined, 'Make sure data is intact');

    div.removeData('test.foo');
    equal(div.data('test.foo'), undefined, 'Make sure data is intact');
});

test('.data supports interoperable removal of properties SET TWICE #13850', function() {
    var div = D('
').appendTo('#qunit-fixture'),
        datas = {
            'non-empty': 'a string',
            'empty-string': '',
            'one-value': 1,
            'zero-value': 0,
            'an-array': [],
            'an-object': {},
            'bool-true': true,
            'bool-false': false,
            // JSHint enforces double quotes,
            // but JSON strings need double quotes to parse
            // so we need escaped double quotes here
            'some-json': '{ \'foo\': \'bar\' }'
        };

    expect(9);

    _.each(datas, function(val, key) {
        div.data(key, val);
        div.data(key, val);

        div.removeData(key);

        equal(div.data(key), undefined, 'removal: ' + key);
    });
});

test('.removeData supports removal of hyphenated properties via array (#12786)', function() {
    expect(2);

    var div, plain, compare;

    div = D('
').appendTo('#qunit-fixture');

    // When data is batch assigned (via plain object), the properties
    // are not camel cased as they are with (property, value) calls
    compare = {
        // From batch assignment .data({ 'a-a': 1 })
        'a-a': 1,
        // From property, value assignment .data('b-b', 1)
        'b-b': 1
    };

    // Mixed assignment
    div.data({ 'a-a': 1 });
    div.data('b-b', 1);

    deepEqual(div.data(), compare, 'Data appears as expected. (div)');

    div.removeData(['a-a', 'b-b']);

    // NOTE: Timo's proposal for 'propEqual' (or similar) would be nice here
    deepEqual(div.data(), {}, 'Data is empty. (div)');
});

test('.data doesnt throw when calling selection is empty. #13551', function() {
    expect(1);

    try {
        D(null).data('prop');
        ok(true, 'D(null).data("prop") does not throw');
    } catch (e) {
        ok(false, e.message);
    }
});

test('Check proper data removal of non-element descendants nodes (#8335)', function() {
    expect(1);

    var div = D('
text
'),
        text = div.contents();

    text.data('test', 'test'); // This should be a noop.
    div.remove();

    ok(!text.data('test'), 'Be sure data is not stored in non-element');
});
<|endoftext|>


<commit_before>/**
 * Tests for the environmental (browser, jquery, etc.) options
 */

/*jshint boss: true, laxbreak: true, node: true */
/*global wrap: true */

var JSHINT = require('../jshint.js').JSHINT,
    assert = require('assert'),
    fs     = require('fs');

function wrap(globals) {
    return '(function () { return [ ' + globals.join(',') + ' ]; }());';
}

assert.globalsKnown = function (globals, options) {
    JSHINT(wrap(globals), options || {});
    var report = JSHINT.data();

    assert.isUndefined(report.implieds);
    assert.eql(report.globals.length, globals.length);

    var dict = {};
    for (var i = 0, g; g = report.globals[i]; i++)
        globals[g] = true;

    for (i = 0, g = null; g = globals[i]; i++)
        assert.ok(g in globals);
};

assert.globalsImplied = function (globals, options) {
    JSHINT(wrap(globals), options || {});
    var report = JSHINT.data();

    assert.isDefined(report.implieds);
    assert.isUndefined(report.globals, 0);

    var implieds = [];
    for (var i = 0, warn; warn = report.implieds[i]; i++)
        implieds.push(warn.name);

    assert.eql(implieds.length, globals.length);
};

/** Option `node` predefines Node.js globals */
exports.node = function () {
    var globals = [
            "__filename"
          , "__dirname"
          , "Buffer"
          , "GLOBAL"
          , "global"
          , "module"
          , "process"
          , "require"
          , "exports"
        ];

    assert.globalsImplied(globals);
    assert.globalsKnown(globals, { node: true });
};

/** Option `jquery` predefines jQuery globals */
exports.jquery = function () {
    var globals = [ 'jQuery', '$' ];

    assert.globalsImplied(globals);
    assert.globalsKnown(globals, { jquery: true });
};

/** Option `couch` predefines CouchDB globals */
exports.couch = function () {
    var globals = [
            "require"
          , "respond"
          , "getRow"
          , "emit"
          , "send"
          , "start"
          , "sum"
          , "log"
          , "exports"
          , "module"
        ];

    assert.globalsImplied(globals);
    assert.globalsKnown(globals, { couch: true });
};

/** Option `prototypejs` predefines Prototype.js and Scriptaculous globals */
exports.prototypejs = function () {
    var globals = [
            "$"
          , "$$"
          , "$A"
          , "$F"
          , "$H"
          , "$R"
          , "$break"
          , "$continue"
          , "$w"
          , "Abstract"
          , "Ajax"
          , "Class"
          , "Enumerable"
          , "Element"
          , "Event"
          , "Field"
          , "Form"
          , "Hash"
          , "Insertion"
          , "ObjectRange"
          , "PeriodicalExecuter"
          , "Position"
          , "Prototype"
          , "Selector"
          , "Template"
          , "Toggle"
          , "Try"
          , "Autocompleter"
          , "Builder"
          , "Control"
          , "Draggable"
          , "Draggables"
          , "Droppables"
          , "Effect"
          , "Sortable"
          , "SortableObserver"
          , "Sound"
          , "Scriptaculous"
        ];

    assert.globalsImplied(globals);
    assert.globalsKnown(globals, { prototypejs: true });
};

/**
 * Option `devel` predefines global functions used for development
 * (console, alert, etc.)
 */
exports.devel = function () {
    var globals = [
            "alert"
          , "confirm"
          , "console"
          , "Debug"
          , "opera"
          , "prompt"
        ];

    assert.globalsImplied(globals);
    assert.globalsKnown(globals, { devel: true });
};

/**
 * Option `browser` predefines globals usually found in browser environments.
 * In addition to stuff like window, setInterval,.. it also supports some
 * more or less stable HTML5 variables like FileReader, localStorage,..
 * and typed arrays like Int32Array, Uint32Array, etc.
 *
 * More info:
 *  + HTML5: http://www.html5rocks.com/
 *  + Typed arrays: https://developer.mozilla.org/en/JavaScript_typed_arrays
 */
exports.browser = function () {
    var globals = [
            'ArrayBuffer'
          , 'ArrayBufferView'
          , 'addEventListener'
          , 'applicationCache'
          , 'blur'
          , 'clearInterval'
          , 'clearTimeout'
          , 'close'
          , 'closed'
          , 'DataView'
          , 'defaultStatus'
          , 'document'
          , 'event'
          , 'FileReader'
          , 'Float32Array'
          , 'Float64Array'
          , 'focus'
          , 'frames'
          , 'getComputedStyle'
          , 'history'
          , 'Int16Array'
          , 'Int32Array'
          , 'Int8Array'
          , 'Image'
          , 'length'
          , 'localStorage'
          , 'location'
          , 'moveBy'
          , 'moveTo'
          , 'name'
          , 'navigator'
          , 'onbeforeunload'
          , 'onblur'
          , 'onerror'
          , 'onfocus'
          , 'onload'
          , 'onresize'
          , 'onunload'
          , 'open'
          , 'openDatabase'
          , 'opener'
          , 'Option'
          , 'parent'
          , 'print'
          , 'removeEventListener'
          , 'resizeBy'
          , 'resizeTo'
          , 'screen'
          , 'scroll'
          , 'scrollBy'
          , 'scrollTo'
          , 'setInterval'
          , 'setTimeout'
          , 'status'
          , 'top'
          , 'Uint16Array'
          , 'Uint32Array'
          , 'Uint8Array'
          , 'WebSocket'
          , 'window'
          , 'Worker'
          , 'XMLHttpRequest'
        ];

    assert.globalsImplied(globals);
    assert.globalsKnown(globals, { browser: true });
};<commit_msg>Added a test case for the option rhino<commit_after>/**
 * Tests for the environmental (browser, jquery, etc.) options
 */

/*jshint boss: true, laxbreak: true, node: true */
/*global wrap: true */

var JSHINT = require('../jshint.js').JSHINT,
    assert = require('assert'),
    fs     = require('fs');

function wrap(globals) {
    return '(function () { return [ ' + globals.join(',') + ' ]; }());';
}

assert.globalsKnown = function (globals, options) {
    JSHINT(wrap(globals), options || {});
    var report = JSHINT.data();

    assert.isUndefined(report.implieds);
    assert.eql(report.globals.length, globals.length);

    var dict = {};
    for (var i = 0, g; g = report.globals[i]; i++)
        globals[g] = true;

    for (i = 0, g = null; g = globals[i]; i++)
        assert.ok(g in globals);
};

assert.globalsImplied = function (globals, options) {
    JSHINT(wrap(globals), options || {});
    var report = JSHINT.data();

    assert.isDefined(report.implieds);
    assert.isUndefined(report.globals, 0);

    var implieds = [];
    for (var i = 0, warn; warn = report.implieds[i]; i++)
        implieds.push(warn.name);

    assert.eql(implieds.length, globals.length);
};

/** Option `node` predefines Node.js globals */
exports.node = function () {
    var globals = [
            "__filename"
          , "__dirname"
          , "Buffer"
          , "GLOBAL"
          , "global"
          , "module"
          , "process"
          , "require"
          , "exports"
        ];

    assert.globalsImplied(globals);
    assert.globalsKnown(globals, { node: true });
};

/** Option `jquery` predefines jQuery globals */
exports.jquery = function () {
    var globals = [ 'jQuery', '$' ];

    assert.globalsImplied(globals);
    assert.globalsKnown(globals, { jquery: true });
};

/** Option `couch` predefines CouchDB globals */
exports.couch = function () {
    var globals = [
            "require"
          , "respond"
          , "getRow"
          , "emit"
          , "send"
          , "start"
          , "sum"
          , "log"
          , "exports"
          , "module"
        ];

    assert.globalsImplied(globals);
    assert.globalsKnown(globals, { couch: true });
};

/** Option `prototypejs` predefines Prototype.js and Scriptaculous globals */
exports.prototypejs = function () {
    var globals = [
            "$"
          , "$$"
          , "$A"
          , "$F"
          , "$H"
          , "$R"
          , "$break"
          , "$continue"
          , "$w"
          , "Abstract"
          , "Ajax"
          , "Class"
          , "Enumerable"
          , "Element"
          , "Event"
          , "Field"
          , "Form"
          , "Hash"
          , "Insertion"
          , "ObjectRange"
          , "PeriodicalExecuter"
          , "Position"
          , "Prototype"
          , "Selector"
          , "Template"
          , "Toggle"
          , "Try"
          , "Autocompleter"
          , "Builder"
          , "Control"
          , "Draggable"
          , "Draggables"
          , "Droppables"
          , "Effect"
          , "Sortable"
          , "SortableObserver"
          , "Sound"
          , "Scriptaculous"
        ];

    assert.globalsImplied(globals);
    assert.globalsKnown(globals, { prototypejs: true });
};

/**
 * Option `devel` predefines global functions used for development
 * (console, alert, etc.)
 */
exports.devel = function () {
    var globals = [
            "alert"
          , "confirm"
          , "console"
          , "Debug"
          , "opera"
          , "prompt"
        ];

    assert.globalsImplied(globals);
    assert.globalsKnown(globals, { devel: true });
};

/**
 * Option `browser` predefines globals usually found in browser environments.
 * In addition to stuff like window, setInterval,.. it also supports some
 * more or less stable HTML5 variables like FileReader, localStorage,..
 * and typed arrays like Int32Array, Uint32Array, etc.
 *
 * More info:
 *  + HTML5: http://www.html5rocks.com/
 *  + Typed arrays: https://developer.mozilla.org/en/JavaScript_typed_arrays
 */
exports.browser = function () {
    var globals = [
            'ArrayBuffer'
          , 'ArrayBufferView'
          , 'addEventListener'
          , 'applicationCache'
          , 'blur'
          , 'clearInterval'
          , 'clearTimeout'
          , 'close'
          , 'closed'
          , 'DataView'
          , 'defaultStatus'
          , 'document'
          , 'event'
          , 'FileReader'
          , 'Float32Array'
          , 'Float64Array'
          , 'focus'
          , 'frames'
          , 'getComputedStyle'
          , 'history'
          , 'Int16Array'
          , 'Int32Array'
          , 'Int8Array'
          , 'Image'
          , 'length'
          , 'localStorage'
          , 'location'
          , 'moveBy'
          , 'moveTo'
          , 'name'
          , 'navigator'
          , 'onbeforeunload'
          , 'onblur'
          , 'onerror'
          , 'onfocus'
          , 'onload'
          , 'onresize'
          , 'onunload'
          , 'open'
          , 'openDatabase'
          , 'opener'
          , 'Option'
          , 'parent'
          , 'print'
          , 'removeEventListener'
          , 'resizeBy'
          , 'resizeTo'
          , 'screen'
          , 'scroll'
          , 'scrollBy'
          , 'scrollTo'
          , 'setInterval'
          , 'setTimeout'
          , 'status'
          , 'top'
          , 'Uint16Array'
          , 'Uint32Array'
          , 'Uint8Array'
          , 'WebSocket'
          , 'window'
          , 'Worker'
          , 'XMLHttpRequest'
        ];

    assert.globalsImplied(globals);
    assert.globalsKnown(globals, { browser: true });
};

exports.rhino = function () {
    var globals = [
            'defineClass'
          , 'deserialize'
          , 'gc'
          , 'help'
          , 'load'
          , 'loadClass'
          , 'print'
          , 'quit'
          , 'readFile'
          , 'readUrl'
          , 'runCommand'
          , 'seal'
          , 'serialize'
          , 'spawn'
          , 'sync'
          , 'toint32'
          , 'version'
        ];

    assert.globalsImplied(globals);
    assert.globalsKnown(globals, { rhino: true });
};<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 The Gravitee team (http://gravitee.io)
 *
 * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
 *
 * 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.
 */
'use strict';

const webpack = require('webpack');
const conf = require('./gulp.conf');
const path = require('path');

const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const pkg = require('../package.json');
const autoprefixer = require('autoprefixer');
const CopyWebpackPlugin = require('copy-webpack-plugin');

let packages = Object.keys(pkg.dependencies);
packages.splice(packages.indexOf('swagger-ui-dist'), 1);

module.exports = {
  mode: 'production',
  module: {
    rules: [
      {
        test: /\.ts$/,
        exclude: /node_modules/,
        use: 'tslint-loader',
        enforce: 'pre'
      },
      {
        test: /\.(css|scss)$/,
        loaders: ExtractTextPlugin.extract({
          fallback: 'style-loader',
          use: 'css-loader!sass-loader!postcss-loader'
        }),
        include: [
          path.resolve(__dirname, '..') + '/src/index.scss'
        ]
      },
      {
        test: /\.ts$/,
        exclude: /node_modules/,
        loaders: [
          'ng-annotate-loader',
          'ts-loader?transpileOnly=true'
        ]
      },
      {
        test: /\.html$/,
        exclude: /node_modules/,
        loader: 'html-loader',
        options: {
          minimize: true,
          removeComments: true,
          collapseWhitespace: true,
          removeAttributeQuotes: true
        }
      },
      {
        test: /\.(jpe?g|png|gif|svg)$/i,
        loaders: [
          'file-loader?hash=sha512&digest=hex&name=[hash].[ext]'
        ]
      },
      {
        test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
        use: 'url-loader?limit=10000&minetype=application/font-woff'
      },
      {
        test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
        use: 'file-loader'
      }
    ]
  },
  plugins: [
    new webpack.ProvidePlugin({
      $: 'jquery',
      jQuery: 'jquery',
      moment: 'moment'
    }),
    new webpack.optimize.OccurrenceOrderPlugin(),
    new webpack.NoEmitOnErrorsPlugin(),
    new HtmlWebpackPlugin({
      template: conf.path.src('index.html')
    }),
    new ExtractTextPlugin('index-[hash].css'),
    new webpack.LoaderOptionsPlugin({
        options: {
          postcss: () => [autoprefixer],
          resolve: {},
          ts: {
            configFileName: 'tsconfig.json'
          },
          tslint: {
            configuration: require('../tslint.json')
          }
        }
      }),
    new CopyWebpackPlugin([
      {
        from: './constants.json',
        to: ''
      }, {
        from: './build.json',
        to: ''
      },
      {
        from: './themes',
        to: './themes'
      },
      {
        from: './docs',
        to: './docs'
      },
      { from: './src/swagger-oauth2-redirect.html', to: './swagger-oauth2-redirect.html' }
    ], {
      copyUnmodified: true,
    })
  ],
  output: {
    path: path.join(process.cwd(), conf.paths.dist),
    filename: '[name]-[hash].js'
  },
  resolve: {
    alias: {
      'read-more': 'read-more/js/directives/readmore.js'
    },
    extensions: [
      '.webpack.js',
      '.web.js',
      '.js',
      '.ts',
      '.json'
    ]
  },
  entry: {
    vendor: packages,
    app: `./${conf.path.src('index')}`
  },
  node: {
    fs: 'empty',
    module: 'empty'
  },
  externals: [{'api-console': {}, 'unicode': {}}],
  optimization: {
    minimize: true,
    splitChunks: {
      chunks: 'all'
    }
  }
};
<commit_msg>fix: JS error on dist<commit_after>/*
 * Copyright (C) 2015 The Gravitee team (http://gravitee.io)
 *
 * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
 *
 * 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.
 */
'use strict';

const webpack = require('webpack');
const conf = require('./gulp.conf');
const path = require('path');

const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const pkg = require('../package.json');
const autoprefixer = require('autoprefixer');
const CopyWebpackPlugin = require('copy-webpack-plugin');

let packages = Object.keys(pkg.dependencies);
packages.splice(packages.indexOf('swagger-ui-dist'), 1);

module.exports = {
  mode: 'production',
  module: {
    rules: [
      {
        test: /\.ts$/,
        exclude: /node_modules/,
        use: 'tslint-loader',
        enforce: 'pre'
      },
      {
        test: /\.(css|scss)$/,
        loaders: ExtractTextPlugin.extract({
          fallback: 'style-loader',
          use: 'css-loader!sass-loader!postcss-loader'
        }),
        include: [
          path.resolve(__dirname, '..') + '/src/index.scss'
        ]
      },
      {
        test: /\.ts$/,
        exclude: /node_modules/,
        loaders: [
          'ng-annotate-loader',
          'ts-loader?transpileOnly=true'
        ]
      },
      {
        test: /\.html$/,
        exclude: /node_modules/,
        loader: 'html-loader',
        options: {
          minimize: true,
          removeComments: true,
          collapseWhitespace: true,
          removeAttributeQuotes: true
        }
      },
      {
        test: /\.(jpe?g|png|gif|svg)$/i,
        loaders: [
          'file-loader?hash=sha512&digest=hex&name=[hash].[ext]'
        ]
      },
      {
        test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
        use: 'url-loader?limit=10000&minetype=application/font-woff'
      },
      {
        test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
        use: 'file-loader'
      }
    ]
  },
  plugins: [
    new webpack.ProvidePlugin({
      $: 'jquery',
      jQuery: 'jquery',
      moment: 'moment',
      tinycolor: 'tinycolor2'
    }),
    new webpack.optimize.OccurrenceOrderPlugin(),
    new webpack.NoEmitOnErrorsPlugin(),
    new HtmlWebpackPlugin({
      template: conf.path.src('index.html')
    }),
    new ExtractTextPlugin('index-[hash].css'),
    new webpack.LoaderOptionsPlugin({
        options: {
          postcss: () => [autoprefixer],
          resolve: {},
          ts: {
            configFileName: 'tsconfig.json'
          },
          tslint: {
            configuration: require('../tslint.json')
          }
        }
      }),
    new CopyWebpackPlugin([
      {
        from: './constants.json',
        to: ''
      }, {
        from: './build.json',
        to: ''
      },
      {
        from: './themes',
        to: './themes'
      },
      {
        from: './docs',
        to: './docs'
      },
      { from: './src/swagger-oauth2-redirect.html', to: './swagger-oauth2-redirect.html' }
    ], {
      copyUnmodified: true,
    })
  ],
  output: {
    path: path.join(process.cwd(), conf.paths.dist),
    filename: '[name]-[hash].js'
  },
  resolve: {
    alias: {
      'read-more': 'read-more/js/directives/readmore.js'
    },
    extensions: [
      '.webpack.js',
      '.web.js',
      '.js',
      '.ts',
      '.json'
    ]
  },
  entry: {
    vendor: packages,
    app: `./${conf.path.src('index')}`
  },
  node: {
    fs: 'empty',
    module: 'empty'
  },
  externals: [{'api-console': {}, 'unicode': {}}],
  optimization: {
    minimize: true,
    splitChunks: {
      chunks: 'all'
    }
  }
};
<|endoftext|>


<commit_before>//maybe make a modal for when you first open up the page -- 'prepare for battle'

var gameRef;
var myPlayerNumber;
var opponent;

//Taken fro the firebase recipe page
function go() {
  var userId = prompt('Username?', 'Guest');
  // Consider adding '/<unique id>' if you have multiple games.
  gameRef = new Firebase(GAME_LOCATION);
  assignPlayerNumberAndPlayGame(userId, gameRef);
};

function findOpponentNumber(myPlayerNumber) {
  if (myPlayerNumber === 1) {
    opponent = 0
  } else {
    opponent = 1;
  }
}

// The maximum number of players.  If there are already
// NUM_PLAYERS assigned, users won't be able to join the game.
var NUM_PLAYERS = 2;

// The root of your game data.
var GAME_LOCATION = "https://adamsbattleship.firebaseio.com/";

// A location under GAME_LOCATION that will store the list of
// players who have joined the game (up to MAX_PLAYERS).
var PLAYERS_LOCATION = 'player_list';

// A location under GAME_LOCATION that you will use to store data
// for each player (their game state, etc.)
var PLAYER_DATA_LOCATION = 'player_data';

// A location under GAME_LOCATION that you will use to track
//which player's turn it is.
var PLAYER_TURN_LOCATION = 'player_turn';

// Called after player assignment completes.
function playGame(myPlayerNumber, userId, justJoinedGame, gameRef) {
  var playerDataRef = gameRef.child(PLAYER_DATA_LOCATION).child(myPlayerNumber);
  var turnCounterLocation = gameRef.child(PLAYER_TURN_LOCATION);
  alert('You are player number ' + myPlayerNumber +
    '.  Your data will be located at ' + playerDataRef.toString());
  findOpponentNumber(myPlayerNumber);
  playerDataRef.child('fleet').set('');
  turnCounterLocation.set(0);
  //if (justJoinedGame) {
    //alert('Doing first-time initialization of data.');
    playerDataRef.set({userId: userId, state: 'game state'});
  //}
}

// Use transaction() to assign a player number, then call playGame().
function assignPlayerNumberAndPlayGame(userId, gameRef) {
  var playerListRef = gameRef.child(PLAYERS_LOCATION);
  myPlayerNumber, alreadyInGame = false;

  playerListRef.transaction(function(playerList) {
    // Attempt to (re)join the given game. Notes:
    //
    // 1. Upon very first call, playerList will likely appear null (even if the
    // list isn't empty), since Firebase runs the update function optimistically
    // before it receives any data.
    // 2. The list is assumed not to have any gaps (once a player joins, they
    // don't leave).
    // 3. Our update function sets some external variables but doesn't act on
    // them until the completion callback, since the update function may be
    // called multiple times with different data.
    if (playerList === null) {
      playerList = [];
    }

    for (var i = 0; i < playerList.length; i++) {
      if (playerList[i] === userId) {
        // Already seated so abort transaction to not unnecessarily update playerList.
        alreadyInGame = true;
        myPlayerNumber = i; // Tell completion callback which seat we have.
        return;
      }
    }

    if (i < NUM_PLAYERS) {
      // Empty seat is available so grab it and attempt to commit modified playerList.
      playerList[i] = userId;  // Reserve our seat.
      myPlayerNumber = i; // Tell completion callback which seat we reserved.
      return playerList;
    }

    // Abort transaction and tell completion callback we failed to join.
    myPlayerNumber = null;
  }, function (error, committed) {
    // Transaction has completed.  Check if it succeeded or we were already in
    // the game and so it was aborted.
    if (committed || alreadyInGame) {
      playGame(myPlayerNumber, userId, !alreadyInGame, gameRef);
    } else {
      alert('Game is full.  Can\'t join. :-(');
    }
  });
}

//Ship Coordinates
var carrier = [];
var battleship = [];
var sub = [];
var destroyer = [];
var patrol = [];
var unabated = true;

$(document).ready(function() {

  go(); //initialize firebase

  $( ".piece" ).draggable({ opacity: 0.6, revert: 'invalid', Index: 100, appenTo: 'td' });
  $('.sea-1 td').droppable();

  // Mother function for setting the board
  $('.sea-1 td').on('drop', function(){
    var x = $(this).data("x");
    var y = $(this).data("y");
    console.log(x +'' + y);
    var coordinates = [x, y];
    var length = shipLength(selectedPiece);
    var fitsOnSea = checkIfPieceFits(coordinates, length, orientation);
    checkForOtherShips(coordinates, length, orientation);
    if (fitsOnSea && unabated) {
      renderPieces(coordinates, length, orientation, selectedPiece);
      hideFromFleet(selectedPiece);
      checkIfAllPiecesArePlaced();
    } else {
      alert("Over the line!");
    }
  });

  //Hide ships from fleet after placing on board
  function hideFromFleet(selectedPiece) {
    var piece = '#'+selectedPiece;
    $(piece).hide('highlight', 200);
  }

  function checkForOtherShips(coordinates, length, orientation) {
    // For horizontal orientation
    for (var i = 0; i < length; i++) {
      if (orientation == 'Horizontal'){
        var cellCoordinates = [coordinates[0] + i, coordinates[1]];
        var cellElement = boardCell(cellCoordinates, 1);
      } else { //For vertical orientation
        var cellCoordinates = [coordinates[0], coordinates[1] - i ];
        var cellElement = boardCell(cellCoordinates, 1);
      }
      if (cellElement.hasClass('occupied')) {
        unabated = false;
        break;
      } else {
        unabated = true;
      }
    }
  }

  function checkIfPieceFits(coordinates, length, orientation) {
    var gridLength = $('.sea-1 tr').length;
    if(orientation == 'Horizontal') {
      if (coordinates[0] + length > gridLength + 1) {
        return false;
      } else {
        return true;
      }
    } else {
      if (coordinates[1] - length < 0) {
        return false;
      } else {
        return true;
      }
    }
  }

  // SELECT PIECE
  var selectedPiece;

  function selectPiece(pieceName) {
    selectedPiece = pieceName;
    console.log(selectedPiece);
  }

  function shipLength(pieceName) {
    switch (pieceName) {
      case 'carrier':
        return 5;
        break;
      case 'battleship':
        return 4;
        break;
      case 'patrol':
        return 2;
        break;
      case 'sub':
        return 3;
        break;
      case 'destroyer':
        return 3;
    }
  }

  $("div.piece").mousedown(function() {
    var pieceName = $(this).data("name");
    selectPiece(pieceName);
  });

  function renderPieces(coordinates, length, orientation, selectedPiece) {
    // For horizontal orientation
    for (var i = 0; i < length; i++) {
      if (orientation == 'Horizontal'){
        var cellCoordinates = [coordinates[0] + i, coordinates[1]];
        var cellElement = boardCell(cellCoordinates, 1);
      } else { //For vertical orientation
        var cellCoordinates = [coordinates[0], coordinates[1] - i ];
        var cellElement = boardCell(cellCoordinates, 1);
      }
      if (i === length-1){
        cellElement.css("background-image", "url('tableimages/" + orientation + (5) +".gif')");
        cellElement.addClass('occupied');
      } else {
        cellElement.css("background-image", "url('tableimages/" + orientation + (i+1) +".gif')");
        cellElement.addClass('occupied');
      }
      logCoordinates(cellCoordinates, selectedPiece);
    }
    fleetSet();
  }

  function logCoordinates(coordinates, selectedPiece) {
    switch(selectedPiece) {
      case 'carrier':
        carrier.push(coordinates);
        break;
      case 'battleship':
        battleship.push(coordinates);
        break;
      case 'sub':
        sub.push(coordinates);
        break;
      case 'destroyer':
        destroyer.push(coordinates);
        break;
      case 'patrol':
        patrol.push(coordinates);
    }
  }

  function fleetSet() { //to log to database
    gameRef.child("player_data/" + myPlayerNumber + "/fleet/carrier").set(carrier);
    gameRef.child("player_data/" + myPlayerNumber + "/fleet/battleship").set(battleship);
    gameRef.child("player_data/" + myPlayerNumber + "/fleet/sub").set(sub);
    gameRef.child("player_data/" + myPlayerNumber + "/fleet/destroyer").set(destroyer);
    gameRef.child("player_data/" + myPlayerNumber + "/fleet/patrol").set(patrol);
  }

  function boardCell(coordinates, gridNumber) {
    var x = coordinates[0];
    var y = coordinates[1];
    var cell = $(".sea-" + gridNumber + " td[data-x='" + x + "'][data-y='" + y + "']");
    return cell;
  }

  function checkIfAllPiecesArePlaced() {
    var occupiedSquares = $('.sea-1 .occupied').length;
    if( occupiedSquares === 17) {
      allPiecesAreOnBoard = true;
      gameInit();
    }
  }

  // TOGGLE ORIENTATION
  var orientation = "Horizontal";

  function toggleOrientation() {
    if (orientation == "Horizontal") {
      orientation = "Vertical";
    } else {
      orientation = "Horizontal";
    }
  }

  $("div#toggle").click(function() { //flip ship orientation
    toggleOrientation();
    $("div.piece").each(function() {
      var width = $(this).width();
      var height = $(this).height();
      var background = $(this).attr('id') + orientation;
      $(this).css("background-image", "url('tableimages/" + background +".gif')");
      $(this).css("background-size", height + 'px ' + width + 'px');
      $(this).width(height);
      $(this).height(width);
    })
  });

  //Attacking
  var hit = false;
  var allPiecesAreOnBoard = false;
  var playerTurn;

  $('.sea-2 td').click(function(){
    checkTurn();
    console.log(playerTurn);
    if(playerTurn === myPlayerNumber && allPiecesAreOnBoard) {
      var x = $(this).data("x");
      var y = $(this).data("y");
      var attackCoordinates = [x, y];
      gameRef.child("player_data/" + opponent + "/fleet").on("value", function(snapshot) {
        var opponentCarrier = snapshot.val().carrier;
        var opponentBattleship = snapshot.val().battleship;
        var opponentDestroyer = snapshot.val().destroyer;
        var opponentSub = snapshot.val().sub;
        var opponentPatrol = snapshot.val().patrol;
        var totalOccupiedCells = opponentCarrier.concat(opponentBattleship, opponentDestroyer, opponentSub, opponentPatrol);
        checkForHit(attackCoordinates, totalOccupiedCells); //check for hit or miss
        renderAttack(attackCoordinates); //render attack with css
        gameRef.child(PLAYER_TURN_LOCATION).set(opponent);
        console.log(myPlayerNumber + ' just attacked. Now ' + playerTurn + 's turn' );
      });
    }
  });

  function checkTurn(){
    gameRef.child(PLAYER_TURN_LOCATION).on("value", function(snapshot) {
      var turn = snapshot.val();
      playerTurn = turn;
    });
  }

  function checkForHit(attackCoordinates, totalOccupiedCells) {
    for (var i=0; i<totalOccupiedCells.length; i++) {
      console.log(attackCoordinates.toString() + 'and' + totalOccupiedCells[i].toString() );
      if (attackCoordinates.toString() === totalOccupiedCells[i].toString()) {
        hit = true;
        break;
      } else {
        hit = false;
      }
    }
  }

  function renderAttack(coordinates) {
    var cellCoordinates = [coordinates[0], coordinates[1]];
    var cellElement = boardCell(cellCoordinates, 2);
    if (hit === true) {
      cellElement.css("background-image", "url('tableimages/hit.gif')");
    } else {
      cellElement.css("background-image", "url('tableimages/miss.gif')");
    }
  }

  function gameInit() {
    gameRef.child("player_data/" + myPlayerNumber + "/state").set('ready');
    gameRef.child("player_data/" + opponent + "/state").on("value", function(snapshot) {
      var opponentReady = snapshot.val();
      if (opponentReady !== "ready") {
        $('#lightbox').show('drop');
        $('#begin-modal').show('drop');
        waitForOpponent();
      }
    });
  }

  function waitForOpponent() {
    var opponentReadyStatus = gameRef.child("/player_data/" + opponent);
    opponentReadyStatus.on("child_changed", function(snapshot) {
      var changedStatus = snapshot.val();
      console.log(changedStatus);
      if (changedStatus === "ready") {
        $('#lightbox').hide('pulsate');
        $('#begin-modal').hide('pulsate');
      }
    });
  }

});
<commit_msg>check for which ship is being hit<commit_after>//maybe make a modal for when you first open up the page -- 'prepare for battle'

var gameRef;
var myPlayerNumber;
var opponent;

//Taken fro the firebase recipe page
function go() {
  var userId = prompt('Username?', 'Guest');
  // Consider adding '/<unique id>' if you have multiple games.
  gameRef = new Firebase(GAME_LOCATION);
  assignPlayerNumberAndPlayGame(userId, gameRef);
};

function findOpponentNumber(myPlayerNumber) {
  if (myPlayerNumber === 1) {
    opponent = 0
  } else {
    opponent = 1;
  }
}

// The maximum number of players.  If there are already
// NUM_PLAYERS assigned, users won't be able to join the game.
var NUM_PLAYERS = 2;

// The root of your game data.
var GAME_LOCATION = "https://adamsbattleship.firebaseio.com/";

// A location under GAME_LOCATION that will store the list of
// players who have joined the game (up to MAX_PLAYERS).
var PLAYERS_LOCATION = 'player_list';

// A location under GAME_LOCATION that you will use to store data
// for each player (their game state, etc.)
var PLAYER_DATA_LOCATION = 'player_data';

// A location under GAME_LOCATION that you will use to track
//which player's turn it is.
var PLAYER_TURN_LOCATION = 'player_turn';

// Called after player assignment completes.
function playGame(myPlayerNumber, userId, justJoinedGame, gameRef) {
  var playerDataRef = gameRef.child(PLAYER_DATA_LOCATION).child(myPlayerNumber);
  var turnCounterLocation = gameRef.child(PLAYER_TURN_LOCATION);
  alert('You are player number ' + myPlayerNumber +
    '.  Your data will be located at ' + playerDataRef.toString());
  findOpponentNumber(myPlayerNumber);
  playerDataRef.child('fleet').set('');
  turnCounterLocation.set(0);
  //if (justJoinedGame) {
    //alert('Doing first-time initialization of data.');
    playerDataRef.set({userId: userId, state: 'game state'});
  //}
}

// Use transaction() to assign a player number, then call playGame().
function assignPlayerNumberAndPlayGame(userId, gameRef) {
  var playerListRef = gameRef.child(PLAYERS_LOCATION);
  myPlayerNumber, alreadyInGame = false;

  playerListRef.transaction(function(playerList) {
    // Attempt to (re)join the given game. Notes:
    //
    // 1. Upon very first call, playerList will likely appear null (even if the
    // list isn't empty), since Firebase runs the update function optimistically
    // before it receives any data.
    // 2. The list is assumed not to have any gaps (once a player joins, they
    // don't leave).
    // 3. Our update function sets some external variables but doesn't act on
    // them until the completion callback, since the update function may be
    // called multiple times with different data.
    if (playerList === null) {
      playerList = [];
    }

    for (var i = 0; i < playerList.length; i++) {
      if (playerList[i] === userId) {
        // Already seated so abort transaction to not unnecessarily update playerList.
        alreadyInGame = true;
        myPlayerNumber = i; // Tell completion callback which seat we have.
        return;
      }
    }

    if (i < NUM_PLAYERS) {
      // Empty seat is available so grab it and attempt to commit modified playerList.
      playerList[i] = userId;  // Reserve our seat.
      myPlayerNumber = i; // Tell completion callback which seat we reserved.
      return playerList;
    }

    // Abort transaction and tell completion callback we failed to join.
    myPlayerNumber = null;
  }, function (error, committed) {
    // Transaction has completed.  Check if it succeeded or we were already in
    // the game and so it was aborted.
    if (committed || alreadyInGame) {
      playGame(myPlayerNumber, userId, !alreadyInGame, gameRef);
    } else {
      alert('Game is full.  Can\'t join. :-(');
    }
  });
}

//Ship Coordinates
var carrier = [];
var battleship = [];
var sub = [];
var destroyer = [];
var patrol = [];
var unabated = true;

$(document).ready(function() {

  go(); //initialize firebase

  $( ".piece" ).draggable({ opacity: 0.6, revert: 'invalid', Index: 100, appenTo: 'td' });
  $('.sea-1 td').droppable();

  // Mother function for setting the board
  $('.sea-1 td').on('drop', function(){
    var x = $(this).data("x");
    var y = $(this).data("y");
    var coordinates = [x, y];
    var length = shipLength(selectedPiece);
    var fitsOnSea = checkIfPieceFits(coordinates, length, orientation);
    checkForOtherShips(coordinates, length, orientation);
    if (fitsOnSea && unabated) {
      renderPieces(coordinates, length, orientation, selectedPiece);
      hideFromFleet(selectedPiece);
      checkIfAllPiecesArePlaced();
    } else {
      alert("Over the line!");
    }
  });

  //Hide ships from fleet after placing on board
  function hideFromFleet(selectedPiece) {
    var piece = '#'+selectedPiece;
    $(piece).hide('highlight', 200);
  }

  function checkForOtherShips(coordinates, length, orientation) {
    // For horizontal orientation
    for (var i = 0; i < length; i++) {
      if (orientation == 'Horizontal'){
        var cellCoordinates = [coordinates[0] + i, coordinates[1]];
        var cellElement = boardCell(cellCoordinates, 1);
      } else { //For vertical orientation
        var cellCoordinates = [coordinates[0], coordinates[1] - i ];
        var cellElement = boardCell(cellCoordinates, 1);
      }
      if (cellElement.hasClass('occupied')) {
        unabated = false;
        break;
      } else {
        unabated = true;
      }
    }
  }

  function checkIfPieceFits(coordinates, length, orientation) {
    var gridLength = $('.sea-1 tr').length;
    if(orientation == 'Horizontal') {
      if (coordinates[0] + length > gridLength + 1) {
        return false;
      } else {
        return true;
      }
    } else {
      if (coordinates[1] - length < 0) {
        return false;
      } else {
        return true;
      }
    }
  }

  // SELECT PIECE
  var selectedPiece;

  function selectPiece(pieceName) {
    selectedPiece = pieceName;
  }

  function shipLength(pieceName) {
    switch (pieceName) {
      case 'carrier':
        return 5;
        break;
      case 'battleship':
        return 4;
        break;
      case 'patrol':
        return 2;
        break;
      case 'sub':
        return 3;
        break;
      case 'destroyer':
        return 3;
    }
  }

  $("div.piece").mousedown(function() {
    var pieceName = $(this).data("name");
    selectPiece(pieceName);
  });

  function renderPieces(coordinates, length, orientation, selectedPiece) {
    // For horizontal orientation
    for (var i = 0; i < length; i++) {
      if (orientation == 'Horizontal'){
        var cellCoordinates = [coordinates[0] + i, coordinates[1]];
        var cellElement = boardCell(cellCoordinates, 1);
      } else { //For vertical orientation
        var cellCoordinates = [coordinates[0], coordinates[1] - i ];
        var cellElement = boardCell(cellCoordinates, 1);
      }
      if (i === length-1){
        cellElement.css("background-image", "url('tableimages/" + orientation + (5) +".gif')");
        cellElement.addClass('occupied');
      } else {
        cellElement.css("background-image", "url('tableimages/" + orientation + (i+1) +".gif')");
        cellElement.addClass('occupied');
      }
      logCoordinates(cellCoordinates, selectedPiece);
    }
    fleetSet();
  }

  function logCoordinates(coordinates, selectedPiece) {
    switch(selectedPiece) {
      case 'carrier':
        carrier.push(coordinates);
        break;
      case 'battleship':
        battleship.push(coordinates);
        break;
      case 'sub':
        sub.push(coordinates);
        break;
      case 'destroyer':
        destroyer.push(coordinates);
        break;
      case 'patrol':
        patrol.push(coordinates);
    }
  }

  function fleetSet() { //to log to database
    gameRef.child("player_data/" + myPlayerNumber + "/fleet/carrier").set(carrier);
    gameRef.child("player_data/" + myPlayerNumber + "/fleet/battleship").set(battleship);
    gameRef.child("player_data/" + myPlayerNumber + "/fleet/sub").set(sub);
    gameRef.child("player_data/" + myPlayerNumber + "/fleet/destroyer").set(destroyer);
    gameRef.child("player_data/" + myPlayerNumber + "/fleet/patrol").set(patrol);
  }

  function boardCell(coordinates, gridNumber) {
    var x = coordinates[0];
    var y = coordinates[1];
    var cell = $(".sea-" + gridNumber + " td[data-x='" + x + "'][data-y='" + y + "']");
    return cell;
  }

  function checkIfAllPiecesArePlaced() {
    var occupiedSquares = $('.sea-1 .occupied').length;
    if( occupiedSquares === 17) {
      allPiecesAreOnBoard = true;
      gameInit();
    }
  }

  // TOGGLE ORIENTATION
  var orientation = "Horizontal";

  function toggleOrientation() {
    if (orientation == "Horizontal") {
      orientation = "Vertical";
    } else {
      orientation = "Horizontal";
    }
  }

  $("div#toggle").click(function() { //flip ship orientation
    toggleOrientation();
    $("div.piece").each(function() {
      var width = $(this).width();
      var height = $(this).height();
      var background = $(this).attr('id') + orientation;
      $(this).css("background-image", "url('tableimages/" + background +".gif')");
      $(this).css("background-size", height + 'px ' + width + 'px');
      $(this).width(height);
      $(this).height(width);
    })
  });

  //Attacking
  var hit = false;
  var allPiecesAreOnBoard = false;
  var playerTurn;

  $('.sea-2 td').click(function(){
    checkTurn();
    if(playerTurn === myPlayerNumber && allPiecesAreOnBoard) {
      var x = $(this).data("x");
      var y = $(this).data("y");
      var attackCoordinates = [x, y];
      gameRef.child("player_data/" + opponent + "/fleet").on("value", function(snapshot) {
        var opponentCarrier = snapshot.val().carrier;
        var opponentBattleship = snapshot.val().battleship;
        var opponentDestroyer = snapshot.val().destroyer;
        var opponentSub = snapshot.val().sub;
        var opponentPatrol = snapshot.val().patrol;
        var totalOccupiedCells = [opponentCarrier, opponentBattleship, opponentDestroyer, opponentSub, opponentPatrol];
        debugger
        checkForHit(attackCoordinates, totalOccupiedCells); //check for hit or miss
        renderAttack(attackCoordinates); //render attack with css
        gameRef.child(PLAYER_TURN_LOCATION).set(opponent);
      });
    }
  });

  function checkTurn(){
    gameRef.child(PLAYER_TURN_LOCATION).on("value", function(snapshot) {
      var turn = snapshot.val();
      playerTurn = turn;
    });
  }

  function checkForHit(attackCoordinates, totalOccupiedCells) {
    for (var i=0; i<totalOccupiedCells.length; i++) {
      for(var j=0; j<totalOccupiedCells[i].length; j++) {
        if (attackCoordinates.toString() === totalOccupiedCells[i][j].toString()) {
          hit = true;
          checkWhichShip(i);
          return
        } else {
          hit = false;
        }
      }
    }
  }

  function checkWhichShip(i) {
    switch(i) {
      case 0:
        alert('hit the carrier');
        break;
      case 1:
        alert('hit the battleship');
        break;
      case 2:
        alert('hit the destroyer');
        break;
      case 3:
        alert('hit the sub');
        break;
      case 4:
        alert('hit the patrol');
    }
  }

  function renderAttack(coordinates) {
    var cellCoordinates = [coordinates[0], coordinates[1]];
    var cellElement = boardCell(cellCoordinates, 2);
    if (hit === true) {
      cellElement.css("background-image", "url('tableimages/hit.gif')");
    } else {
      cellElement.css("background-image", "url('tableimages/miss.gif')");
    }
  }

  function gameInit() {
    gameRef.child("player_data/" + myPlayerNumber + "/state").set('ready');
    gameRef.child("player_data/" + opponent + "/state").on("value", function(snapshot) {
      var opponentReady = snapshot.val();
      if (opponentReady !== "ready") {
        $('#lightbox').show('drop');
        $('#begin-modal').show('drop');
        waitForOpponent();
      }
    });
  }

  function waitForOpponent() {
    var opponentReadyStatus = gameRef.child("/player_data/" + opponent);
    opponentReadyStatus.on("child_changed", function(snapshot) {
      var changedStatus = snapshot.val();
      if (changedStatus === "ready") {
        $('#lightbox').hide('pulsate');
        $('#begin-modal').hide('pulsate');
      }
    });
  }

});
<|endoftext|>