<commit_before>function popUpModal(target, content){
 if(content){
  jq('div#popup-modal').html(content);
 }
 if (jq('div#popup-modal.show').length){
   jq('div#popup-modal').css({top:'100%', bottom: '100%'});
   jq('div#popup-modal').removeClass('show');
   jq('body').removeClass('lock-screen');
 } else {
   var scrollTop = jq('body').scrollTop();
   jq('div#popup-modal').css({top:scrollTop, bottom: -1*scrollTop});
   jq('body').addClass('lock-screen');
   jq('div#popup-modal').addClass('show');
 }
}

var statusRow = function(statusItems, status, showLabel){
  status = status || '';
  return `

      ${showLabel ?  `
        Status
      ` : ''}
      ${statusItems.reduce(function(target, item){
        var className = ' class="' +
          (item === status.trim().toLowerCase() ? 'selected ' : '') +
          item + '"';
        return target + '<button'+className+'>' + item + '</button>';
      }, '')}

  `;
}

function makeHistoryContent({type, title, field, hijack}){
  var historyContent = jq(`

        ${title} ${field} History

        <button class="button-primary close">Close</button>
        ${hijack ? `<button class="button-primary cancel">Back</button>` : ''}

  `);

  historyContent.find('button.cancel').on('click', function(e){
    jq('div#popup-modal .history').hide();
    jq('div#popup-modal .account').show();
  });

  historyContent.find('button.close').on('click', function(e){
    jq('div#popup-modal .history').hide();
    jq('div#popup-modal').removeClass('show');
    jq('body').removeClass('lock-screen');
  });

  return historyContent;
}

function formatGraphData(json){
  var formattedData = json.map(x => [
    moment(x.date.replace('_', ' ')).valueOf(),
    Number(x.value)
  ]);
  return formattedData;
}

function makeGraph($container, data){
  var chartConfig = {
      chart: {
          renderTo: $container,
          marginTop: 30,
          height: 300
      },
      title:{
          text:''
      },
      legend: {
          enabled: false
      },
      credits: {
          enabled: false
      },
      tooltip: {
        formatter: function() {
          return `
            $${this.y}

${moment(this.x).format('MMM DD YYYY, HH:mm a')}

          `;
        }
      },
      xAxis: {
          type: 'datetime'
      },
      yAxis: {
        title: ''
      },
      series: [{
        name: '',
        data: data
      }]
  };
  var graph = new Highcharts.Chart(chartConfig);
  return graph;
}

function showHistoryPopup(target, h){
  var historyContent = makeHistoryContent(h);
  jq('div#popup-modal .history').html(historyContent);
  if(h.hijack){
    jq('div#popup-modal .account').hide();
  }

  if (!h.hijack){
    var historyPopupContainer = jq(`

    `);
    historyPopupContainer.find('.content.history').html(historyContent);
    popUpModal(target, historyPopupContainer);
  }
  jq('div#popup-modal .history').show();

  var fetchField = h.field.toLowerCase().replace(' ', '_');
  function updateDiffs(){
    const thisFunction = this;
    GLOBAL_FUNCTION_QUEUE.push(thisFunction.bind(thisFunction));

    fetch(`diffs?type=${h.type}&account=${h.title}&field=${fetchField}`, {
      headers: {
        'Accept': 'application/json'
      },
      credentials: 'include'
    })
      .then(function(response) {
        return response.json();
      })
      .then(function(json) {
        if(json.mustLogin || json.error === 'not logged in'){
          return login();
        }

        GLOBAL_FUNCTION_QUEUE.pop();
        historyContent.find('.loading-spinner').hide();
        var graphContainer = historyContent.find('.graph-container')[0];

        if(json.error === "offline"){
          graphContainer.innerHTML = 'offline';
          graphContainer.className = "offline"
          return;
        }

        var graphData = formatGraphData(json);
        var chart = makeGraph(graphContainer, graphData);
      })
      .catch(function(error) {
        console.log("Error making graph", error);
      });
  }
  updateDiffs.bind(updateDiffs)();
}

function statusHandler(content, originalStatus, originalDateString, getStatus){
  content.find('.status.row button').on('click', function (e){
    var currentSelectedStatus = getStatus(content.find('.selected'));
    var clickedStatus = getStatus(jq(this));

    if(clickedStatus.toLowerCase() === 'paid' && originalStatus.toLowerCase() !== 'paid'){
      var day = Number(originalDateString.replace(/.*-/g,''));
      var month = Number(originalDateString.replace(/-..$/g,'').replace(/.*-/g,''));
      var year = Number(originalDateString.replace(/-.*/g,''));
      if (month === 12) {
        year += 1;
        month = 1;
      } else {
        month += 1;
      }
      day = (day < 10) ? '0'+day : day;
      month = (month < 10) ? '0'+month : month;
      content.find('input[type="date"]').val(year + '-' + month + '-' + day)
    } else {
      content.find('input[type="date"]').val(originalDateString);
    }
    content.find('.status.row button').removeClass('selected');
    jq(this).addClass('selected');
  });
  return content;
}

function saveHandler(content, getStatus){
  var getCurrentItem = function(item){
    var status = getStatus(item.find('.selected'));
    var currentItem = {
      name: (item.find('#title').val() || item.find('h2').text() || '').trim(),
      status,
      website: (item.find('#website').val() || '').trim(),
      amount: item.find('.amount').val(),
      occurence: item.find('#occurence').val(),
      total: item.find('#total').val(),
      date: item.find('input[type="date"]').val(),
      notes: item.find('textarea#notes').val(),
      auto: item.find('#auto-checkbox').is(":checked")
    };
    var popupHeadingText = item.find('.popup-heading').text();
    if(popupHeadingText.toLowerCase().includes('group')){
      currentItem.type='group';
      currentItem.items=jq('.form-group:contains(Items) tr').get().map(tr => {
        var item = {
       title: tr.children[0].innerText,
         amount: Number(tr.children[1].innerText.replace('$','').replace(',',''))
        };
        return item;
     });
    }
    return currentItem;
  };

  content.find('button.save').on('click', function (e){
    var currentItem = getCurrentItem(jq(this).parent().parent());
    //TODO: are we writing to liab or assets?
    var previousVersion = MAIN_DATA.liabilities.getByName(currentItem.name.toLowerCase())
      || MAIN_DATA.assets.getByName(currentItem.name.toLowerCase());
    if (!previousVersion){
      previousVersion = {};
      MAIN_DATA.liabilities.push(previousVersion);
      previousVersion.occurence = currentItem.occurence;
      previousVersion.website = currentItem.website;
      previousVersion.hidden = false;
    }
    previousVersion.title = currentItem.name;
    previousVersion.status = currentItem.status;
    previousVersion.amount = currentItem.amount;
    previousVersion.total_owed = currentItem.total || '0.00';
    previousVersion.date = currentItem.date;
    previousVersion.note = currentItem.notes.replace(/</g, "<").replace(/>/g, ">");
    previousVersion.auto = currentItem.auto;
    if(currentItem.type){
      previousVersion.type = currentItem.type;
    }
    if(currentItem.items){
      previousVersion.items = currentItem.items;
    }
    jq.ajax({
      url: "./accounts",
      type: 'POST',
      contentType: 'application/json',
      data: JSON.stringify(MAIN_DATA),
      success: function( data ) {
        console.log( "SERVER RESPONSE", data );
        location.reload();
      }
    });
  });
  return content;
}

function accountUI({
  isNewItem, isGroup, items, statusItems,
  originalDateString, website, title, originalStatus, notes, autoIsChecked, amount, total
}){
  var content = jq(`

        ${ isNewItem
          ? `

New ${ isGroup ? 'Group' : 'Item'}

              Title
              <input class="u-full-width form-control" id="title" type="text"/>

            `
          : `

              ${title}

            `
          }
        ${statusRow(statusItems, originalStatus, isNewItem)}
        ${isNewItem ? `

            Website
            <input class="u-full-width form-control" type="text" id="website"/>

        ` : ''}

        Notes
        <textarea class="u-max-full-width u-full-width form-control" rows="5" id="notes">${notes}</textarea>

          AUTO
          <input type="checkbox" id="auto-checkbox" ${autoIsChecked ? 'checked' : ''}>

        ${isGroup ? `

            Items

${items}

`
        : ''}

          Payment Amount
          <input class="amount" type="number" step="0.01" value="${amount}" ${isGroup ? 'disabled' : ''}/>
          ${!isNewItem ? `
            <button class="graph" data-title="Amount"></button>
          ` : ''}

          Total Owed
          <input  class="total" type="number" value="${total}" id="total" ${isGroup ? 'disabled' : ''}/>
          ${!isNewItem ? `
            <button class="graph" data-title="Total Owed"></button>
          ` : ''}

          Date Due
          <input type="date" value="${originalDateString}"/>

        ${isNewItem ?  `

            Occurence
            <select class="u-full-width" id="occurence">
              <option value="once">Once</option>
              <option value="week">Weekly</option>
              <option value="bi-week">Bi-weekly</option>
              <option value="month" selected="selected">Monthly</option>
            </select>

        ` : ''}

          <button class="button-primary cancel" onClick="">Cancel</button>
          <button class="button-primary save" onClick="">${isNewItem ? 'Add' : 'Save'}</button>

  `);

  var getStatus = function($item){
    var status = ($item.attr('class') || '').replace(/selected/g, '').trim();
    status = status.substring( 0, 1 ).toUpperCase() + status.substring(1).trim();
    return status;
  };

  content = statusHandler(content, originalStatus, originalDateString, getStatus);
  content = saveHandler(content, getStatus);

  content.find('button.cancel').on('click', function (e){
    jq('#popup-modal').click();
  });

  //graph click handler
  content.find('button.graph').on('click', function(e){
    var h = {
      type: 'liabilities',
      title: title.trim(),
      field: jq(this).data('title'),
      hijack: true
    };
    showHistoryPopup(null, h);
  });

  return content;
}

function makeAccountContent($clickedRow){
  var statusItems = ['due', 'pending', 'paid'];
  var dueDate = new Date(Date.now());
  dueDate.setMonth(dueDate.getMonth()+1);
  var defaultDateString = dueDate.toISOString().substring(0, 10);
  var originalDateString = $clickedRow.find('.date').text() || defaultDateString;
  var originalStatus = $clickedRow.find('.status').text();
  var notes = $clickedRow.find('.notes').text();
  var website = $clickedRow.find('.website').text();
  var title = $clickedRow.find('.title').text();
  var amount = $clickedRow.find('.amount').text().replace(/[$,]+/g,"");
  var total = $clickedRow.find('.total').text().replace(/[$,]+/g,"");
  var isNewItem = !title; //TODO: better condition
  var autoIsChecked = JSON.parse($clickedRow.find('.auto').text() || 'false');

  // potential bug when title of asset and liability the same
  var account = MAIN_DATA.liabilities.getByName(title.trim().toLowerCase())
    || MAIN_DATA.assets.getByName(title.trim().toLowerCase());
  var isGroup = account.type === "group";
  var items = (account.items || []).reduce((all, item) => {
    all += `

      ${item.title}
      ${formatMoney(item.amount)}

`;
    return all;
  }, '')

  var content = accountUI({
    isNewItem, isGroup, items, statusItems,
    originalDateString, website, title, originalStatus, notes, autoIsChecked, amount, total
  });

  return content;
}

function makeNewGroup(selected){
  var group = {
    type: "group",
    hidden: false,
    title: "New Group",
    note: "",
    items: selected.map(g => {
      var { title, amount, date, status } = g;
      return { title, amount, date, status };
     }),
    status: "paid",
    date: "2017-10-18",
    amount: selected.reduce((all, g) => { return all+Number(g.amount); }, 0),
    total_owed: selected.reduce((all, g) => { return all+Number(g.total_owed||0); }, 0),
    auto: false
  };
  return group;
}

function makeGroupContent($selected){
  const selectedTitles = $selected.toArray().map(
    x => jq(x).find('.title').text().trim()
  );
  const selectedAccounts = selectedTitles.map(
    x =>  MAIN_DATA.liabilities.getByName(x.toLowerCase())
  ).filter(x => !!x);

  //TODO: add to group here
  var newGroup = makeNewGroup(selectedAccounts);

  var isNewItem = true;
  var isGroup = true;
  var autoIsChecked = false;
  var items = (newGroup.items || []).reduce((all, item) => {
    all += `

      ${item.title}
      ${formatMoney(item.amount)}

`;
    return all;
  }, '');
  var statusItems = ['due', 'pending', 'paid'];
  var originalDateString = newGroup.date;
  var website = '';
  var { title, note, total_owed, amount } = newGroup;

  var content = accountUI({
    isNewItem, isGroup, items, statusItems,
    originalDateString, website, title, originalStatus:status, notes: note, autoIsChecked, amount, total: total_owed
  });

  content.find('.form-group:contains(AUTO)').hide();
  content.find('.form-group:contains(Website)').hide();
  content.find('.container.content.account h2').hide();

  return content;
}

<commit_msg>remove button on group popup<commit_after>function popUpModal(target, content){
 if(content){
  jq('div#popup-modal').html(content);
 }
 if (jq('div#popup-modal.show').length){
   jq('div#popup-modal').css({top:'100%', bottom: '100%'});
   jq('div#popup-modal').removeClass('show');
   jq('body').removeClass('lock-screen');
 } else {
   var scrollTop = jq('body').scrollTop();
   jq('div#popup-modal').css({top:scrollTop, bottom: -1*scrollTop});
   jq('body').addClass('lock-screen');
   jq('div#popup-modal').addClass('show');
 }
}

var statusRow = function(statusItems, status, showLabel){
  status = status || '';
  return `

      ${showLabel ?  `
        Status
      ` : ''}
      ${statusItems.reduce(function(target, item){
        var className = ' class="' +
          (item === status.trim().toLowerCase() ? 'selected ' : '') +
          item + '"';
        return target + '<button'+className+'>' + item + '</button>';
      }, '')}

  `;
}

function makeHistoryContent({type, title, field, hijack}){
  var historyContent = jq(`

        ${title} ${field} History

        <button class="button-primary close">Close</button>
        ${hijack ? `<button class="button-primary cancel">Back</button>` : ''}

  `);

  historyContent.find('button.cancel').on('click', function(e){
    jq('div#popup-modal .history').hide();
    jq('div#popup-modal .account').show();
  });

  historyContent.find('button.close').on('click', function(e){
    jq('div#popup-modal .history').hide();
    jq('div#popup-modal').removeClass('show');
    jq('body').removeClass('lock-screen');
  });

  return historyContent;
}

function formatGraphData(json){
  var formattedData = json.map(x => [
    moment(x.date.replace('_', ' ')).valueOf(),
    Number(x.value)
  ]);
  return formattedData;
}

function makeGraph($container, data){
  var chartConfig = {
      chart: {
          renderTo: $container,
          marginTop: 30,
          height: 300
      },
      title:{
          text:''
      },
      legend: {
          enabled: false
      },
      credits: {
          enabled: false
      },
      tooltip: {
        formatter: function() {
          return `
            $${this.y}

${moment(this.x).format('MMM DD YYYY, HH:mm a')}

          `;
        }
      },
      xAxis: {
          type: 'datetime'
      },
      yAxis: {
        title: ''
      },
      series: [{
        name: '',
        data: data
      }]
  };
  var graph = new Highcharts.Chart(chartConfig);
  return graph;
}

function showHistoryPopup(target, h){
  var historyContent = makeHistoryContent(h);
  jq('div#popup-modal .history').html(historyContent);
  if(h.hijack){
    jq('div#popup-modal .account').hide();
  }

  if (!h.hijack){
    var historyPopupContainer = jq(`

    `);
    historyPopupContainer.find('.content.history').html(historyContent);
    popUpModal(target, historyPopupContainer);
  }
  jq('div#popup-modal .history').show();

  var fetchField = h.field.toLowerCase().replace(' ', '_');
  function updateDiffs(){
    const thisFunction = this;
    GLOBAL_FUNCTION_QUEUE.push(thisFunction.bind(thisFunction));

    fetch(`diffs?type=${h.type}&account=${h.title}&field=${fetchField}`, {
      headers: {
        'Accept': 'application/json'
      },
      credentials: 'include'
    })
      .then(function(response) {
        return response.json();
      })
      .then(function(json) {
        if(json.mustLogin || json.error === 'not logged in'){
          return login();
        }

        GLOBAL_FUNCTION_QUEUE.pop();
        historyContent.find('.loading-spinner').hide();
        var graphContainer = historyContent.find('.graph-container')[0];

        if(json.error === "offline"){
          graphContainer.innerHTML = 'offline';
          graphContainer.className = "offline"
          return;
        }

        var graphData = formatGraphData(json);
        var chart = makeGraph(graphContainer, graphData);
      })
      .catch(function(error) {
        console.log("Error making graph", error);
      });
  }
  updateDiffs.bind(updateDiffs)();
}

function statusHandler(content, originalStatus, originalDateString, getStatus){
  content.find('.status.row button').on('click', function (e){
    var currentSelectedStatus = getStatus(content.find('.selected'));
    var clickedStatus = getStatus(jq(this));

    if(clickedStatus.toLowerCase() === 'paid' && originalStatus.toLowerCase() !== 'paid'){
      var day = Number(originalDateString.replace(/.*-/g,''));
      var month = Number(originalDateString.replace(/-..$/g,'').replace(/.*-/g,''));
      var year = Number(originalDateString.replace(/-.*/g,''));
      if (month === 12) {
        year += 1;
        month = 1;
      } else {
        month += 1;
      }
      day = (day < 10) ? '0'+day : day;
      month = (month < 10) ? '0'+month : month;
      content.find('input[type="date"]').val(year + '-' + month + '-' + day)
    } else {
      content.find('input[type="date"]').val(originalDateString);
    }
    content.find('.status.row button').removeClass('selected');
    jq(this).addClass('selected');
  });
  return content;
}

function saveHandler(content, getStatus){
  var getCurrentItem = function(item){
    var status = getStatus(item.find('.selected'));
    var currentItem = {
      name: (item.find('#title').val() || item.find('h2').text() || '').trim(),
      status,
      website: (item.find('#website').val() || '').trim(),
      amount: item.find('.amount').val(),
      occurence: item.find('#occurence').val(),
      total: item.find('#total').val(),
      date: item.find('input[type="date"]').val(),
      notes: item.find('textarea#notes').val(),
      auto: item.find('#auto-checkbox').is(":checked")
    };
    var popupHeadingText = item.find('.popup-heading').text();
    if(popupHeadingText.toLowerCase().includes('group')){
      currentItem.type='group';
      currentItem.items=jq('.form-group:contains(Items) tr').get().map(tr => {
        var item = {
       title: tr.children[0].innerText,
         amount: Number(tr.children[1].innerText.replace('$','').replace(',',''))
        };
        return item;
     });
    }
    return currentItem;
  };

  content.find('button.save').on('click', function (e){
    var currentItem = getCurrentItem(jq(this).parent().parent());
    //TODO: are we writing to liab or assets?
    var previousVersion = MAIN_DATA.liabilities.getByName(currentItem.name.toLowerCase())
      || MAIN_DATA.assets.getByName(currentItem.name.toLowerCase());
    if (!previousVersion){
      previousVersion = {};
      MAIN_DATA.liabilities.push(previousVersion);
      previousVersion.occurence = currentItem.occurence;
      previousVersion.website = currentItem.website;
      previousVersion.hidden = false;
    }
    previousVersion.title = currentItem.name;
    previousVersion.status = currentItem.status;
    previousVersion.amount = currentItem.amount;
    previousVersion.total_owed = currentItem.total || '0.00';
    previousVersion.date = currentItem.date;
    previousVersion.note = currentItem.notes.replace(/</g, "<").replace(/>/g, ">");
    previousVersion.auto = currentItem.auto;
    if(currentItem.type){
      previousVersion.type = currentItem.type;
    }
    if(currentItem.items){
      previousVersion.items = currentItem.items;
    }
    jq.ajax({
      url: "./accounts",
      type: 'POST',
      contentType: 'application/json',
      data: JSON.stringify(MAIN_DATA),
      success: function( data ) {
        console.log( "SERVER RESPONSE", data );
        location.reload();
      }
    });
  });
  return content;
}

function accountUI({
  isNewItem, isGroup, items, statusItems,
  originalDateString, website, title, originalStatus, notes, autoIsChecked, amount, total
}){
  var content = jq(`

        ${ isNewItem
          ? `

New ${ isGroup ? 'Group' : 'Item'}

              Title
              <input class="u-full-width form-control" id="title" type="text"/>

            `
          : `

              ${title}

            `
          }
        ${statusRow(statusItems, originalStatus, isNewItem)}
        ${isNewItem ? `

            Website
            <input class="u-full-width form-control" type="text" id="website"/>

        ` : ''}

        Notes
        <textarea class="u-max-full-width u-full-width form-control" rows="5" id="notes">${notes}</textarea>

          AUTO
          <input type="checkbox" id="auto-checkbox" ${autoIsChecked ? 'checked' : ''}>

        ${isGroup ? `

            Items

${items}

`
        : ''}

          Payment Amount
          <input class="amount" type="number" step="0.01" value="${amount}" ${isGroup ? 'disabled' : ''}/>
          ${!isNewItem ? `
            <button class="graph" data-title="Amount"></button>
          ` : ''}

          Total Owed
          <input  class="total" type="number" value="${total}" id="total" ${isGroup ? 'disabled' : ''}/>
          ${!isNewItem ? `
            <button class="graph" data-title="Total Owed"></button>
          ` : ''}

          Date Due
          <input type="date" value="${originalDateString}"/>

        ${isNewItem ?  `

            Occurence
            <select class="u-full-width" id="occurence">
              <option value="once">Once</option>
              <option value="week">Weekly</option>
              <option value="bi-week">Bi-weekly</option>
              <option value="month" selected="selected">Monthly</option>
            </select>

        ` : ''}

          <button class="button-primary cancel" onClick="">Cancel</button>
          ${isGroup && !isNewItem ?
            '<button class="button-primary remove" onClick="">Remove</button>'
            : ''}
          <button class="button-primary save" onClick="">${isNewItem ? 'Add' : 'Save'}</button>

  `);

  var getStatus = function($item){
    var status = ($item.attr('class') || '').replace(/selected/g, '').trim();
    status = status.substring( 0, 1 ).toUpperCase() + status.substring(1).trim();
    return status;
  };

  content = statusHandler(content, originalStatus, originalDateString, getStatus);
  content = saveHandler(content, getStatus);

  content.find('button.cancel').on('click', function (e){
    jq('#popup-modal').click();
  });

  //graph click handler
  content.find('button.graph').on('click', function(e){
    var h = {
      type: 'liabilities',
      title: title.trim(),
      field: jq(this).data('title'),
      hijack: true
    };
    showHistoryPopup(null, h);
  });

  return content;
}

function makeAccountContent($clickedRow){
  var statusItems = ['due', 'pending', 'paid'];
  var dueDate = new Date(Date.now());
  dueDate.setMonth(dueDate.getMonth()+1);
  var defaultDateString = dueDate.toISOString().substring(0, 10);
  var originalDateString = $clickedRow.find('.date').text() || defaultDateString;
  var originalStatus = $clickedRow.find('.status').text();
  var notes = $clickedRow.find('.notes').text();
  var website = $clickedRow.find('.website').text();
  var title = $clickedRow.find('.title').text();
  var amount = $clickedRow.find('.amount').text().replace(/[$,]+/g,"");
  var total = $clickedRow.find('.total').text().replace(/[$,]+/g,"");
  var isNewItem = !title; //TODO: better condition
  var autoIsChecked = JSON.parse($clickedRow.find('.auto').text() || 'false');

  // potential bug when title of asset and liability the same
  var account = MAIN_DATA.liabilities.getByName(title.trim().toLowerCase())
    || MAIN_DATA.assets.getByName(title.trim().toLowerCase());
  var isGroup = account.type === "group";
  var items = (account.items || []).reduce((all, item) => {
    all += `

      ${item.title}
      ${formatMoney(item.amount)}

`;
    return all;
  }, '')

  var content = accountUI({
    isNewItem, isGroup, items, statusItems,
    originalDateString, website, title, originalStatus, notes, autoIsChecked, amount, total
  });

  return content;
}

function makeNewGroup(selected){
  var group = {
    type: "group",
    hidden: false,
    title: "New Group",
    note: "",
    items: selected.map(g => {
      var { title, amount, date, status } = g;
      return { title, amount, date, status };
     }),
    status: "paid",
    date: "2017-10-18",
    amount: selected.reduce((all, g) => { return all+Number(g.amount); }, 0),
    total_owed: selected.reduce((all, g) => { return all+Number(g.total_owed||0); }, 0),
    auto: false
  };
  return group;
}

function makeGroupContent($selected){
  const selectedTitles = $selected.toArray().map(
    x => jq(x).find('.title').text().trim()
  );
  const selectedAccounts = selectedTitles.map(
    x =>  MAIN_DATA.liabilities.getByName(x.toLowerCase())
  ).filter(x => !!x);

  //TODO: add to group here
  var newGroup = makeNewGroup(selectedAccounts);

  var isNewItem = true;
  var isGroup = true;
  var autoIsChecked = false;
  var items = (newGroup.items || []).reduce((all, item) => {
    all += `

      ${item.title}
      ${formatMoney(item.amount)}

`;
    return all;
  }, '');
  var statusItems = ['due', 'pending', 'paid'];
  var originalDateString = newGroup.date;
  var website = '';
  var { title, note, total_owed, amount } = newGroup;

  var content = accountUI({
    isNewItem, isGroup, items, statusItems,
    originalDateString, website, title, originalStatus:status, notes: note, autoIsChecked, amount, total: total_owed
  });

  content.find('.form-group:contains(AUTO)').hide();
  content.find('.form-group:contains(Website)').hide();
  content.find('.container.content.account h2').hide();

  return content;
}

<|endoftext|>


<commit_before>import styled, { css } from 'styled-components';
import PropTypes from 'prop-types';
import baseTheme from '../../../style/themes/base';
import FieldHelpStyle from '../field-help/field-help.style';
import HiddenCheckableInputStyle from '../checkable-input/hidden-checkable-input.style';
import LabelStyle from '../label/label.style';
import { StyledCheckableInput } from '../checkable-input/checkable-input.style';
import StyledSwitchSlider from './switch-slider.style';
import StyledValidationIcon from '../../../components/validations/validation-icon.style';
import { FieldLineStyle } from '../form-field/form-field.style';
import ClassicSwitchStyles from './switch-classic.style';

const StyledSwitch = styled.div`
  ${({
    fieldHelpInline, labelInline, labelWidth, reverse, size, theme
  }) => css`
    ${FieldLineStyle} {
      display: block;
    }

    ${StyledCheckableInput}, ${HiddenCheckableInputStyle} {
      border: none;
      box-sizing: border-box;
      height: 24px;
      width: 60px;
      flex-basis: 100%;
      margin-left: 0;
    }

    margin-bottom: 24px;

    ${HiddenCheckableInputStyle}:not([disabled]) {
      &:focus + ${StyledSwitchSlider},
      &:hover + ${StyledSwitchSlider} {
        outline: solid 3px ${theme.colors.focus};
      }
    }

    ${FieldHelpStyle} {
      margin-left: 0;
    }

    ${LabelStyle} {
      padding: 0;
      margin-bottom: 8px;

      ${StyledValidationIcon} {
        position: relative;
        display: inline-block;
      }

      ${labelWidth && css`
        margin-right: ${100 - labelWidth}%;
      `}
    }

    ${fieldHelpInline && css`
      ${FieldHelpStyle} {
        margin-bottom: 10px;
      }
    `}

    ${reverse && css`
      ${!labelInline && css`
        ${LabelStyle} {
          margin-top: 8px;
        }
      `}
    `}

    ${labelInline && css`
      ${StyledCheckableInput} {
        flex-basis: auto;
      }

      ${FieldLineStyle} {
        display: flex;
      }

      ${LabelStyle} {
        margin-bottom: 0;
        margin-right: 32px;
        padding-top: 4px;
        width: auto;
      }

      ${FieldHelpStyle} {
        margin-bottom: 0;
        margin-top: 0;
      }

      ${reverse && css`
        ${StyledCheckableInput} {
          margin-left: 0;
          margin-top: 0;
        }

        ${LabelStyle} {
          margin-left: 10px;
        }

        ${!fieldHelpInline && `
          ${FieldHelpStyle} {
            margin-left: 70px;
          }
        `}
      `}

      ${fieldHelpInline && `
        ${StyledCheckableInput} {
          margin-left: 10px;
        }

        ${LabelStyle} {
          margin-right: 10px;
        }

        ${FieldHelpStyle} {
          margin-left: 0;
          margin-top: -1px;
          align-self: center;
        }
      `}
    `}

    ${size === 'large' && css`
      ${StyledCheckableInput}, ${HiddenCheckableInputStyle}, ${StyledSwitchSlider} {
        height: 40px;
        width: 78px;
      }

      ${fieldHelpInline && `
        ${FieldHelpStyle} {
          padding: 10px 0;
        }
      `}

      ${labelInline && css`
        ${LabelStyle} {
          margin-top: 1px;
          padding: 10px 0;
        }

        ${!fieldHelpInline && reverse && `
          ${FieldHelpStyle} {
            margin-left: 88px;
          }
        `}
      `}
    `}

    ${ClassicSwitchStyles}
  `}
`;

StyledSwitch.propTypes = {
  disabled: PropTypes.bool,
  fieldHelpInline: PropTypes.bool,
  labelInline: PropTypes.bool,
  reverse: PropTypes.bool,
  size: PropTypes.string,
  theme: PropTypes.object
};

StyledSwitch.defaultProps = {
  theme: baseTheme
};

export default StyledSwitch;
<commit_msg>fix(switch): css styling fix for label<commit_after>import styled, { css } from 'styled-components';
import PropTypes from 'prop-types';
import baseTheme from '../../../style/themes/base';
import FieldHelpStyle from '../field-help/field-help.style';
import HiddenCheckableInputStyle from '../checkable-input/hidden-checkable-input.style';
import LabelStyle from '../label/label.style';
import { StyledCheckableInput } from '../checkable-input/checkable-input.style';
import StyledSwitchSlider from './switch-slider.style';
import StyledValidationIcon from '../../../components/validations/validation-icon.style';
import { FieldLineStyle } from '../form-field/form-field.style';
import ClassicSwitchStyles from './switch-classic.style';

const StyledSwitch = styled.div`
  ${({
    fieldHelpInline, labelInline, labelWidth, reverse, size, theme
  }) => css`
    ${FieldLineStyle} {
      display: flex;
      flex-flow: row wrap;
    }

    ${StyledCheckableInput}, ${HiddenCheckableInputStyle} {
      border: none;
      box-sizing: border-box;
      height: 24px;
      width: 60px;
      flex-basis: 100%;
      margin-left: 0;
    }

    margin-bottom: 24px;

    ${HiddenCheckableInputStyle}:not([disabled]) {
      &:focus + ${StyledSwitchSlider},
      &:hover + ${StyledSwitchSlider} {
        outline: solid 3px ${theme.colors.focus};
      }
    }

    ${FieldHelpStyle} {
      margin-left: 0;
    }

    ${LabelStyle} {
      padding: 0;
      margin-bottom: 8px;

      ${StyledValidationIcon} {
        position: relative;
        display: inline-block;
      }

      ${labelWidth && css`
        margin-right: ${100 - labelWidth}%;
      `}
    }

    ${fieldHelpInline && css`
      ${FieldHelpStyle} {
        margin-bottom: 10px;
      }
    `}

    ${reverse && css`
      ${!labelInline && css`
        ${LabelStyle} {
          margin-top: 8px;
        }
      `}
    `}

    ${labelInline && css`
      ${StyledCheckableInput} {
        flex-basis: auto;
      }

      ${FieldLineStyle} {
        display: flex;
      }

      ${LabelStyle} {
        margin-bottom: 0;
        margin-right: 32px;
        padding-top: 4px;
        width: auto;
      }

      ${FieldHelpStyle} {
        margin-bottom: 0;
        margin-top: 0;
      }

      ${reverse && css`
        ${StyledCheckableInput} {
          margin-left: 0;
          margin-top: 0;
        }

        ${LabelStyle} {
          margin-left: 10px;
        }

        ${!fieldHelpInline && `
          ${FieldHelpStyle} {
            margin-left: 70px;
          }
        `}
      `}

      ${fieldHelpInline && `
        ${StyledCheckableInput} {
          margin-left: 10px;
        }

        ${LabelStyle} {
          margin-right: 10px;
        }

        ${FieldHelpStyle} {
          margin-left: 0;
          margin-top: -1px;
          align-self: center;
        }
      `}
    `}

    ${size === 'large' && css`
      ${StyledCheckableInput}, ${HiddenCheckableInputStyle}, ${StyledSwitchSlider} {
        height: 40px;
        width: 78px;
      }

      ${fieldHelpInline && `
        ${FieldHelpStyle} {
          padding: 10px 0;
        }
      `}

      ${labelInline && css`
        ${LabelStyle} {
          margin-top: 1px;
          padding: 10px 0;
        }

        ${!fieldHelpInline && reverse && `
          ${FieldHelpStyle} {
            margin-left: 88px;
          }
        `}
      `}
    `}

    ${ClassicSwitchStyles}
  `}
`;

StyledSwitch.propTypes = {
  disabled: PropTypes.bool,
  fieldHelpInline: PropTypes.bool,
  labelInline: PropTypes.bool,
  reverse: PropTypes.bool,
  size: PropTypes.string,
  theme: PropTypes.object
};

StyledSwitch.defaultProps = {
  theme: baseTheme
};

export default StyledSwitch;
<|endoftext|>


<commit_before>/**
 * Provides findWithCache method that forces a minimum cache time on the find
 * requests.
 *
 * @class Ember Data Store Cache Mixin
 */

import Ember from "ember";

export default Ember.Mixin.create({
    /**
     * Number of seconds to require caching when using findWithCache method.
     *
     * @param cacheSeconds
     * @type {Integer}
     * @default 600
     */
    cacheSeconds: 600,

    /**
     * Customized find method that checks for cache within a certain timeframe.
     *
     * @method findWithCache
     * @param {String} typeKey
     * @param {Mixed|Integer|Object} id
     * @param {Object} payload
     * @param {Integer} cacheTime Amount of time in seconds to cache for
     * (overrides cacheSeconds param per instance)
     */
    findWithCache: function(typeKey, id, payload, cacheTime) {
        if (arguments.length === 1) {
            // Find all.

            // Get last queried time.
            var type = this.modelFor(typeKey);
            var requestedAt = this.typeMapFor(type).metadata.find_all_requested;
            var now = this._getTimeNow();

            cacheTime = cacheTime || this.get('cacheSeconds');
            if (requestedAt && now - requestedAt < cacheTime) {
                // If time is within cacheSeconds, get from store.
                return this.all(typeKey);
            } else {
                // Else, make request.
                return this.findAll(typeKey, id);
            }
        }

        if (Ember.typeOf(id) === 'object') {
            // Find query.
            Ember.assert('findWithCache does not support queries yet. To use cache, request with find and use store.filter instead.');
        }

        // Find record by ID. Already loads from store if present.
        Ember.assert('findWithCache does not support finding by id. Use find since it returns the record from the store if it is present.');
    },

    /**
     * Remove all entries of typeKey from the store and reset the metadata
     * cache time so the next request via findWithCache will make the request
     * to the server.
     *
     * @method clearCache
     * @param {String} typeKey Type to clear
     */
    clearCache: function(typeKey) {
        this.unloadAll(typeKey);
        this.clearCacheTime(typeKey);
    },

    /**
     * Reset the cache time for time to null so the next request via
     * findWithCache will make the request to the server.
     *
     * @method clearCacheTime
     * @param {String} typeKey Type of clear
     */
    clearCacheTime(typeKey) {
        var type = this.modelFor(typeKey);
        this.typeMapFor(type).metadata.find_all_requested = null;
    },

    /**
     * Override findAll method of store to set the find_all_requested metadata
     * for use in determining the last request time in findWithCache
     *
     * @method findAll
     * @param {String} typeKey
     */
    findAll: function(typeKey) {
        var type = this.modelFor(typeKey);
        this.typeMapFor(type).metadata.find_all_requested = this._getTimeNow();

        return this._super.apply(this, arguments);
    },

    /**
     * Return the current timestamp in seconds.
     *
     * @method _getTimeNow
     * @private
     * @return {Integer} Timestamp in seconds.
     */
    _getTimeNow: function() {
        return Math.ceil(new Date() / 1000);
    }
});
<commit_msg>Save cache time to meta data only after successful request<commit_after>/**
 * Provides findWithCache method that forces a minimum cache time on the find
 * requests.
 *
 * @class Ember Data Store Cache Mixin
 */

import Ember from "ember";

export default Ember.Mixin.create({
    /**
     * Number of seconds to require caching when using findWithCache method.
     *
     * @param cacheSeconds
     * @type {Integer}
     * @default 600
     */
    cacheSeconds: 600,

    /**
     * Customized find method that checks for cache within a certain timeframe.
     *
     * @method findWithCache
     * @param {String} typeKey
     * @param {Mixed|Integer|Object} id
     * @param {Object} payload
     * @param {Integer} cacheTime Amount of time in seconds to cache for
     * (overrides cacheSeconds param per instance)
     */
    findWithCache: function(typeKey, id, payload, cacheTime) {
        if (arguments.length === 1) {
            // Find all.

            // Get last queried time.
            var type = this.modelFor(typeKey);
            var requestedAt = this.typeMapFor(type).metadata.find_all_requested;
            var now = this._getTimeNow();

            cacheTime = cacheTime || this.get('cacheSeconds');
            if (requestedAt && now - requestedAt < cacheTime) {
                // If time is within cacheSeconds, get from store.
                return this.all(typeKey);
            } else {
                // Else, make request.
                return this.findAll(typeKey, id);
            }
        }

        if (Ember.typeOf(id) === 'object') {
            // Find query.
            Ember.assert('findWithCache does not support queries yet. To use cache, request with find and use store.filter instead.');
        }

        // Find record by ID. Already loads from store if present.
        Ember.assert('findWithCache does not support finding by id. Use find since it returns the record from the store if it is present.');
    },

    /**
     * Remove all entries of typeKey from the store and reset the metadata
     * cache time so the next request via findWithCache will make the request
     * to the server.
     *
     * @method clearCache
     * @param {String} typeKey Type to clear
     */
    clearCache: function(typeKey) {
        this.unloadAll(typeKey);
        this.clearCacheTime(typeKey);
    },

    /**
     * Reset the cache time for time to null so the next request via
     * findWithCache will make the request to the server.
     *
     * @method clearCacheTime
     * @param {String} typeKey Type of clear
     */
    clearCacheTime(typeKey) {
        var type = this.modelFor(typeKey);
        this.typeMapFor(type).metadata.find_all_requested = null;
    },

    /**
     * Override findAll method of store to set the find_all_requested metadata
     * for use in determining the last request time in findWithCache
     *
     * @method findAll
     * @param {String} typeKey
     */
    findAll: function(typeKey) {
        var type = this.modelFor(typeKey);
        var promise = this._super.apply(this, arguments);
        promise.then(function() {
            this.typeMapFor(type).metadata.find_all_requested = this._getTimeNow();
        }.bind(this));
        return promise;
    },

    /**
     * Return the current timestamp in seconds.
     *
     * @method _getTimeNow
     * @private
     * @return {Integer} Timestamp in seconds.
     */
    _getTimeNow: function() {
        return Math.ceil(new Date() / 1000);
    }
});
<|endoftext|>


<commit_before>import React, {Component, Fragment} from 'react';
import round from 'lodash/round';

import Table from 'src/Table';
import Switcher from 'src/Switcher';
import IconButton from 'src/IconButton';
import Widget from 'src/Widget';
import WidgetHeader from 'src/WidgetHeader';
import RaisedButton from 'src/RaisedButton';

import PropTypeDescTable from 'components/PropTypeDescTable';
import doc from 'assets/propTypes/Table.json';

import 'scss/containers/app/modules/layout/TableExamples.scss';

class TableExamples extends Component {

    constructor(props) {

        super(props);

        this.state = {
            data: this.generateData(),
            sort: null
        };

        this.columns = [{
            fixed: Table.Fixed.LEFT,
            headRenderer: 'ID',
            bodyRenderer: 'id',
            footRenderer: 'Total',
            footSpan: 2,
            sortable: true,
            sortingProp: 'id'
        }, {
            fixed: Table.Fixed.LEFT,
            width: 300,
            headRenderer: 'Name',
            bodyClassName: 'nowrap',
            bodyRenderer: '${firstName} ${lastName}',
            sortable: true,
            sortingProp: 'firstName'
        }, {
            headRenderer: 'Age',
            headAlign: Table.Align.RIGHT,
            bodyRenderer: 'age',
            bodyAlign: Table.Align.RIGHT,
            footRenderer: () => {
                const {data} = this.state;
                return (
                    <Fragment>

Average

{data.reduce((a, b) => a + b.age, 0) / data.length}

                    </Fragment>
                );
            },
            footAlign: Table.Align.RIGHT,
            sortable: true,
            sortingProp: 'age'
        }, {
            width: 300,
            headRenderer: 'Other Column 1',
            bodyRenderer: '${other} 1'
        }, {
            width: 300,
            headRenderer: 'Other Column 2',
            bodyRenderer: '${other} 2'
        }, {
            width: 300,
            headRenderer: 'Other Column 3',
            bodyRenderer: '${other} 3'
        }, {
            width: 300,
            headRenderer: 'Other Column 4',
            bodyRenderer: '${other} 4'
        }, {
            headRenderer: 'Deposit',
            headAlign: Table.Align.RIGHT,
            bodyRenderer: '$${deposit}',
            bodyAlign: Table.Align.RIGHT,
            footRenderer: () =>
                <Fragment>

Sum

${this.state.data.reduce((a, b) => round(a + b.deposit, 2), 0)}

                </Fragment>,
            footAlign: Table.Align.RIGHT,
            sortable: true,
            sortingProp: 'deposit'
        }, {
            fixed: Table.Fixed.RIGHT,
            headRenderer: 'Status',
            bodyRenderer: rowData =>
                <Switcher value={!rowData.disabled}
                          size="small"
                          onClick={e => e.stopPropagation()}/>
        }];

        this.pageSizes = [{
            value: 10,
            text: '10 / page'
        }, {
            value: 20,
            text: '20 / page'
        }, {
            value: 30,
            text: '30 / page'
        }, {
            value: 40,
            text: '40 / page'
        }, {
            value: 50,
            text: '50 / page'
        }];

    }

    generateData = (size = 100) => {

        let data = [];
        for (let i = 0; i < size; i++) {
            data.push({
                id: i,
                firstName: `firstName${i}`,
                lastName: `lastName${i}`,
                age: Math.floor(Math.random() * 100),
                deposit: round(Math.random() * 1000000, 2),
                other: 'Other Content'
            });
        }

        return data;

    };

    deleteRow = id => {

        const {data} = this.state,
            newData = data.filter(item => item.id !== id);

        this.setState({
            data: newData
        });

    };

    handleSortChange = sort => {
        this.setState({
            sort
        });
        console.log('Sort Change Value: ', sort);
    };

    handlePageChange = (page, pageSize) => {
        console.log(`page: ${page}, pageSize: ${pageSize}`);
    };

    handleDataUpdate = currentPageData => {
        console.log('Data Update Value: ', currentPageData);
    };

    selectHandler = (rowData, rowIndex, value) => {
        console.log('Select Value: ', rowData);
    };

    deselectHandler = (rowData, rowIndex, value) => {
        console.log('Deselect Value: ', rowData);
    };

    selectAllHandler = value => {
        console.log('Select All Value: ', value);
    };

    deselectAllHandler = value => {
        console.log('Deselect All Value: ', value);
    };

    handleChange = value => {
        console.log('Changed Value: ', value);
    };

    clearSort = () => {
        this.setState({
            sort: null
        });
    };

    render() {

        const {data, sort} = this.state;

        return (

Table

                    Table
                     are used to display data and to organize it.

Examples

                <Widget>

                    <WidgetHeader className="example-header" title="With isPagging"/>

A simple Table example.

                            <RaisedButton className="table-action"
                                          theme={RaisedButton.Theme.PRIMARY}
                                          value="Clear Table Sort"
                                          onClick={this.clearSort}/>

                                           <IconButton iconCls="fas fa-trash-alt"
                                                       onClick={() => this.deleteRow(rowData.id)}/>
                                   }]}
                                   sort={sort}
                                   selectMode={Table.SelectMode.MULTI_SELECT}
                                   isHeadFixed={true}
                                   isFootFixed={true}
                                   scroll={{
                                       width: 1200,
                                       height: 400
                                   }}
                                   paggingCountRenderer={count => Self Defined Total Count: {count}}
                                   onSortChange={this.handleSortChange}
                                   onPageChange={this.handlePageChange}
                                   onDataUpdate={this.handleDataUpdate}
                                   onChange={this.handleChange}/>

                </Widget>

                {/*<Widget>*/}

                {/*<WidgetHeader className="example-header" title="With hasLineNumber and isMultiSelect"/>*/}

                {/*
*/}
                {/*
*/}

                {/*
A more complex example.Set the hasLineNumber and isMultiSelect*/}
                {/*to true for showLineNumber and checkbox.
*/}

                {/*<Table data={data}*/}
                {/*columns={this.columns}*/}
                {/*selectMode={Table.SelectMode.MULTI_SELECT}*/}
                {/*selectAllMode={Table.SelectAllMode.CURRENT_PAGE}*/}
                {/*paggingSelectedCountVisible={true}*/}
                {/*defaultPageSize={20}*/}
                {/*pageSizes={this.pageSizes}*/}
                {/*useFullPagging={true}*/}
                {/*sortingAscIconCls="fas fa-caret-up"*/}
                {/*sortingDescIconCls="fas fa-caret-down"*/}
                {/*onPageChange={this.handlePageChange}*/}
                {/*onSelect={this.selectHandler}*/}
                {/*onDeselect={this.deselectHandler}*/}
                {/*onSelectAll={this.selectAllHandler}*/}
                {/*onDeselectAll={this.deselectAllHandler}*/}
                {/*onChange={this.changeHandler}/>*/}

                {/*
*/}
                {/*
*/}

                {/*</Widget>*/}

                {/*<Widget>*/}

                {/*<WidgetHeader className="example-header" title="Empty"/>*/}

                {/*
*/}
                {/*
*/}
                {/*
*/}
                {/*
*/}
                {/*
*/}

                {/*</Widget>*/}

Properties

                <PropTypeDescTable data={doc}/>

        );
    }
}

export default TableExamples;
<commit_msg>update TableExamples<commit_after>import React, {Component, Fragment} from 'react';
import round from 'lodash/round';

import Table from 'src/Table';
import Switcher from 'src/Switcher';
import IconButton from 'src/IconButton';
import Widget from 'src/Widget';
import WidgetHeader from 'src/WidgetHeader';
import RaisedButton from 'src/RaisedButton';

import PropTypeDescTable from 'components/PropTypeDescTable';
import doc from 'assets/propTypes/Table.json';

import 'scss/containers/app/modules/layout/TableExamples.scss';

class TableExamples extends Component {

    constructor(props) {

        super(props);

        this.state = {
            data: this.generateData(),
            sort: null
        };

        this.columns = [{
            fixed: Table.Fixed.LEFT,
            headRenderer: 'ID',
            bodyRenderer: 'id',
            footRenderer: 'Total',
            footSpan: 2,
            sortable: true,
            sortingProp: 'id'
        }, {
            fixed: Table.Fixed.LEFT,
            width: 300,
            headRenderer: 'Name',
            bodyClassName: 'nowrap',
            bodyRenderer: '${firstName} ${lastName}',
            sortable: true,
            sortingProp: 'firstName'
        }, {
            headRenderer: 'Age',
            headAlign: Table.Align.RIGHT,
            bodyRenderer: 'age',
            bodyAlign: Table.Align.RIGHT,
            footRenderer: () => {
                const {data} = this.state;
                return (
                    <Fragment>

Average

{data.reduce((a, b) => a + b.age, 0) / data.length}

                    </Fragment>
                );
            },
            footAlign: Table.Align.RIGHT,
            sortable: true,
            sortingProp: 'age'
        }, {
            width: 300,
            headRenderer: 'Other Column 1',
            bodyRenderer: '${other} 1'
        }, {
            width: 300,
            headRenderer: 'Other Column 2',
            bodyRenderer: '${other} 2'
        }, {
            width: 300,
            headRenderer: 'Other Column 3',
            bodyRenderer: '${other} 3'
        }, {
            width: 300,
            headRenderer: 'Other Column 4',
            bodyRenderer: '${other} 4'
        }, {
            headRenderer: 'Deposit',
            headAlign: Table.Align.RIGHT,
            bodyRenderer: '$${deposit}',
            bodyAlign: Table.Align.RIGHT,
            footRenderer: () =>
                <Fragment>

Sum

${this.state.data.reduce((a, b) => round(a + b.deposit, 2), 0)}

                </Fragment>,
            footAlign: Table.Align.RIGHT,
            sortable: true,
            sortingProp: 'deposit'
        }, {
            fixed: Table.Fixed.RIGHT,
            headRenderer: 'Status',
            bodyRenderer: rowData =>
                <Switcher value={!rowData.disabled}
                          size="small"
                          onClick={e => e.stopPropagation()}/>
        }];

        this.pageSizes = [{
            value: 10,
            text: '10 / page'
        }, {
            value: 20,
            text: '20 / page'
        }, {
            value: 30,
            text: '30 / page'
        }, {
            value: 40,
            text: '40 / page'
        }, {
            value: 50,
            text: '50 / page'
        }];

    }

    generateData = (size = 100) => {

        let data = [];
        for (let i = 0; i < size; i++) {
            data.push({
                id: '' + i,
                firstName: `firstName${i}`,
                lastName: `lastName${i}`,
                age: Math.floor(Math.random() * 100),
                deposit: round(Math.random() * 1000000, 2),
                other: 'Other Content'
            });
        }

        data[0].hasChildren = true;
        data[0].children = [];
        for (let i = 0; i < 10; i++) {
            data[0].children.push({
                id: '0-' + i,
                firstName: `firstName${i}`,
                lastName: `lastName${i}`,
                age: Math.floor(Math.random() * 100),
                deposit: round(Math.random() * 1000000, 2),
                other: 'Other Content'
            });
        }

        data[1].hasChildren = true;

        return data;

    };

    deleteRow = id => {

        const {data} = this.state,
            newData = data.filter(item => item.id !== id);

        this.setState({
            data: newData
        });

    };

    handleSortChange = sort => {
        this.setState({
            sort
        });
        console.log('Sort Change Value: ', sort);
    };

    handlePageChange = (page, pageSize) => {
        console.log(`page: ${page}, pageSize: ${pageSize}`);
    };

    handleDataUpdate = currentPageData => {
        console.log('Data Update Value: ', currentPageData);
    };

    selectHandler = (rowData, rowIndex, value) => {
        console.log('Select Value: ', rowData);
    };

    deselectHandler = (rowData, rowIndex, value) => {
        console.log('Deselect Value: ', rowData);
    };

    selectAllHandler = value => {
        console.log('Select All Value: ', value);
    };

    deselectAllHandler = value => {
        console.log('Deselect All Value: ', value);
    };

    handleChange = value => {
        console.log('Changed Value: ', value);
    };

    clearSort = () => {
        this.setState({
            sort: null
        });
    };

    render() {

        const {data, sort} = this.state;

        return (

Table

                    Table
                     are used to display data and to organize it.

Examples

                <Widget>

                    <WidgetHeader className="example-header" title="With isPagging"/>

A simple Table example.

                            <RaisedButton className="table-action"
                                          theme={RaisedButton.Theme.PRIMARY}
                                          value="Clear Table Sort"
                                          onClick={this.clearSort}/>

                                           <IconButton iconCls="fas fa-trash-alt"
                                                       onClick={() => this.deleteRow(rowData.id)}/>
                                   }]}
                                   sort={sort}
                                   selectMode={Table.SelectMode.MULTI_SELECT}
                                   isHeadFixed={true}
                                   isFootFixed={true}
                                   scroll={{
                                       width: 1200,
                                       height: 400
                                   }}
                                   paggingCountRenderer={count => Self Defined Total Count: {count}}
                                   onSortChange={this.handleSortChange}
                                   onPageChange={this.handlePageChange}
                                   onDataUpdate={this.handleDataUpdate}
                                   onChange={this.handleChange}/>

                </Widget>

                {/*<Widget>*/}

                {/*<WidgetHeader className="example-header" title="With hasLineNumber and isMultiSelect"/>*/}

                {/*
*/}
                {/*
*/}

                {/*
A more complex example.Set the hasLineNumber and isMultiSelect*/}
                {/*to true for showLineNumber and checkbox.
*/}

                {/*<Table data={data}*/}
                {/*columns={this.columns}*/}
                {/*selectMode={Table.SelectMode.MULTI_SELECT}*/}
                {/*selectAllMode={Table.SelectAllMode.CURRENT_PAGE}*/}
                {/*paggingSelectedCountVisible={true}*/}
                {/*defaultPageSize={20}*/}
                {/*pageSizes={this.pageSizes}*/}
                {/*useFullPagging={true}*/}
                {/*sortingAscIconCls="fas fa-caret-up"*/}
                {/*sortingDescIconCls="fas fa-caret-down"*/}
                {/*onPageChange={this.handlePageChange}*/}
                {/*onSelect={this.selectHandler}*/}
                {/*onDeselect={this.deselectHandler}*/}
                {/*onSelectAll={this.selectAllHandler}*/}
                {/*onDeselectAll={this.deselectAllHandler}*/}
                {/*onChange={this.changeHandler}/>*/}

                {/*
*/}
                {/*
*/}

                {/*</Widget>*/}

                {/*<Widget>*/}

                {/*<WidgetHeader className="example-header" title="Empty"/>*/}

                {/*
*/}
                {/*
*/}
                {/*
*/}
                {/*
*/}
                {/*
*/}

                {/*</Widget>*/}

Properties

                <PropTypeDescTable data={doc}/>

        );
    }
}

export default TableExamples;
<|endoftext|>


<commit_before>var $document = $(document),
    $source = $('#source');

var editorModes = {
  html: 'htmlmixed',
  javascript: 'javascript',
  css: 'css'
};

var Panel = function (name, settings) {
  var panel = this,
      showPanelButton = true,
      $panel = null,
      splitterSettings = {},
      cmSettings = {};

  panel.settings = settings = settings || {};
  panel.id = panel.name = name;
  $panel = $('.panel.' + name);
  $panel.data('name', name);
  panel.$el = $panel.detach();
  panel.$el.appendTo($source);
  panel.$el.wrapAll('
');
  panel.$el = panel.$el.parent().hide();
  panel.el = document.getElementById(name);
  panel.order = ++Panel.order;

  panel.$el.data('panel', panel);

  // keyboard shortcut (set in keyboardcontrol.js)
  panelShortcuts[panelShortcuts.start + panel.order] = panel.id;

  if (panel.order === 1) {
    settings.nosplitter = true;
  }

  if (settings.editor) {
    cmSettings = {
      parserfile: [],
      tabMode: 'shift',
      readOnly: jsbin.state.embed ? 'nocursor' : false,
      dragDrop: false, // we handle it ourselves
      mode: editorModes[name],
      // lineNumbers: true,
      onChange: function (event) {
        $document.trigger('codeChange', [{ panelId: panel.id, revert: true }]);
        return true;
      },
      lineWrapping: true,
      theme: jsbin.settings.theme || 'jsbin'
    };

    $.extend(cmSettings, jsbin.settings.codemirror || {});

    panel.editor = CodeMirror.fromTextArea(panel.el, cmSettings);

    panel.processor = settings.processor || function (str) { return str; };

    panel._setupEditor(panel.editor, name);
  }

  if (!settings.nosplitter) {
    // console.log(panel.id, wrapper);
    panel.splitter = panel.$el.splitter(splitterSettings).data('splitter');
    panel.splitter.hide();
  } else {
    // create a fake splitter to let the rest of the code work
    panel.splitter = $();
  }

  if (settings.beforeRender) {
    $document.bind('render', $.proxy(settings.beforeRender, panel));
  }

  if (!settings.editor) {
    panel.ready = true;
  }

  // append panel to controls
  if (jsbin.state.embed) {
    // showPanelButton = window.location.search.indexOf(panel.id) !== -1;
  }

  if (showPanelButton) {
    this.controlButton = $('' + (settings.label || name) + '');
    this.controlButton.click(function () {
      panel.toggle();
      return false;
    });
    this.controlButton.appendTo('#panels');
  }

  $panel.focus(function () {
    panel.focus();
  });
  $panel.add(this.$el.find('.label')).click(function () {
    panel.focus();
  });
};

Panel.order = 0;

Panel.prototype = {
  virgin: true,
  visible: false,
  show: function (x) {
    // check to see if there's a panel to the left.
    // if there is, take it's size/2 and make this our
    // width
    var panel = this,
        panelCount = panel.$el.find('.panel').length;

    analytics.showPanel(panel.id);

    // panel.$el.show();
    if (panel.splitter.length) {
      if (panelCount === 0 || panelCount > 1) {
        var $panel = $('.panel.' + panel.id).show();
        // $panel.next().show(); // should be the splitter...
        $panel.closest('.panelwrapper').show();
      } else {
        panel.$el.show();
      }
      panel.splitter.show();
    } else {
      panel.$el.show();
    }

    $body.addClass('panelsVisible');

    if (panel.settings.show) {
      panel.settings.show.call(panel, true);
    }
    panel.controlButton.addClass('active');
    panel.visible = true;

    // update the splitter - but do it on the next tick
    // required to allow the splitter to see it's visible first
    setTimeout(function () {
      if (x !== undefined) {
        panel.splitter.trigger('init', x);
      } else {
        panel.distribute();
      }
      if (panel.editor) {
        // populate the panel for the first time
        if (panel.virgin) {
          $(panel.editor.win).find('.CodeMirror-scroll .CodeMirror-lines').css('padding-top', panel.$el.find('.label').outerHeight());

          populateEditor(panel, panel.name);
        }
        if (!panel.virgin) {
          panel.editor.focus();
          panel.focus();
        }
      }
      // update all splitter positions
      $document.trigger('sizeeditors');

      panel.virgin = false;
  }, 0);

    // TODO save which panels are visible in their profile - but check whether it's their code
  },
  hide: function () {
    var panel = this;
    // panel.$el.hide();
    panel.visible = false;
    analytics.hidePanel(panel.id);

    // update all splitter positions
    // LOGIC: when you go to hide, you need to check if there's
    // other panels inside the panel wrapper - if there are
    // hide the nested panel and any previous visible splitter
    // if there's only one - then hide the whole thing.
    // if (panel.splitter.length) {
    var panelCount = panel.$el.find('.panel').length;
    if (panelCount === 0 || panelCount > 1) {
      var $panel = $('.panel.' + panel.id).hide();
      $panel.prev().hide(); // hide the splitter if there is one

      // TODO trigger a distribute horizontally
      if ($panel.closest('.panelwrapper').find('.panel:visible').length === 0) {
        $panel.closest('.panelwrapper').hide();
        // panel.splitter.hide();
        // TODO FIXME
      }
    } else {
      panel.$el.hide();
      panel.splitter.hide();
    }
    // } else {
    //   panel.$el.hide();
    // }
    panel.controlButton.removeClass('active');
    panel.distribute();

    if (panel.settings.hide) {
      panel.settings.hide.call(panel, true);
    }

    // this.controlButton.show();
    setTimeout(function () {
      $document.trigger('sizeeditors');
    }, 110);
  },
  toggle: function () {
    (this)[this.visible ? 'hide' : 'show']();
  },
  getCode: function () {
    if (this.editor) {
      return this.editor.getCode();
    }
  },
  setCode: function (content) {
    if (this.editor) {
      this.codeSet = true;
      this.editor.setCode(content);
    }
  },
  codeSet: false,
  focus: function () {
    jsbin.panels.focus(this);
  },
  render: function () {
    var panel = this;
    if (panel.editor) {
      return panel.processor(panel.getCode());
    } else if (this.visible && this.settings.render) {
      this.settings.render.apply(this, arguments);
    }
  },
  init: function () {
    if (this.settings.init) this.settings.init.call(this);
  },
  _setupEditor: function () {
    var focusedPanel = sessionStorage.getItem('panel'),
        panel = this,
        editor = panel.editor;

    // overhang from CodeMirror1
    editor.setCode = function (str) {
      //Cannot call method 'chunkSize' of undefined
      try {
        editor.setValue(str);
      } catch(err) {
        // console.error(panel.id, err + '');
      }
    };

    editor.getCode = function () {
      return editor.getValue();
    };

    editor.currentLine = function () {
      var pos = editor.getCursor();
      return pos.line;
    };

    // editor.setOption('onKeyEvent', keycontrol);
    // editor.setOption('onFocus', function () {
      // panel.$el.trigger('focus');
    // });

    editor.id = panel.name;

    editor.win = editor.getWrapperElement();
    editor.scroller = $(editor.getScrollerElement());

    $(editor.win).click(function () {
      editor.focus();
      panel.focus();
    });

    var $label = panel.$el.find('.label');
    if (document.body.className.indexOf('ie6') === -1 && $label.length) {
      editor.setOption('onScroll', function (event) {
        var scrollInfo = editor.getScrollInfo();
        if (scrollInfo.y > 10) {
          $label.stop().animate({ opacity: 0 }, 20, function () {
            $(this).hide();
          });
        } else {
          $label.show().stop().animate({ opacity: 1 }, 150);
        }
      });
    }

    var $error = null;
    $document.bind('sizeeditors', function () {
      if (panel.visible) {
        var height = panel.editor.scroller.closest('.panel').outerHeight(),
            offset = 0;
            // offset = panel.$el.find('> .label').outerHeight();

        // special case for the javascript panel
        if (panel.name === 'javascript') {
          if ($error === null) { // it wasn't there right away, so we populate
            $error = panel.$el.find('details');
          }
          offset += ($error.filter(':visible').height() || 0);
        }

        editor.scroller.height(height - offset);
        try { editor.refresh(); } catch (e) {}
      }
    });

    // required because the populate looks at the height, and at
    // this point in the code, the editor isn't visible, the browser
    // needs one more tick and it'll be there.
    setTimeout(function () {
      // if the panel isn't visible this only has the effect of putting
      // the code in the textarea (though probably costs us a lot more)
      // it has to be re-populated upon show for the first time because
      // it appears that CM2 uses the visible height to work out what
      // should be shown.
      panel.ready = true;
      populateEditor(panel, panel.name);

      if (focusedPanel == panel.name) {
        if (panel.visible) {
          // another fracking timeout to avoid conflict with other panels firing up
          setTimeout(function () {
            editor.focus();
            panel.focus();
            editor.setCursor({ line: (sessionStorage.getItem('line') || 0) * 1, ch: (sessionStorage.getItem('character') || 0) * 1 });
          }, 0);
        }
      }
    }, 0);
  },
  populateEditor: function () {
    populateEditor(this, this.name);
  }
};

function populateEditor(editor, panel) {
  if (!editor.codeSet) {
    // populate - should eventually use: session, saved data, local storage
    var cached = sessionStorage.getItem('jsbin.content.' + panel), // session code
        saved = localStorage.getItem('saved-' + panel), // user template
        sessionURL = sessionStorage.getItem('url'),
        changed = false;

    if (sessionURL !== template.url) {
      // nuke the live saving checksum
      sessionStorage.removeItem('checksum');
      saveChecksum = false;
    }

    if (template && cached == template[panel]) { // restored from original saved
      editor.setCode(cached);
    } else if (cached && sessionURL == template.url) { // try to restore the session first - only if it matches this url
      editor.setCode(cached);
      // tell the document that it's currently being edited, but check that it doesn't match the saved template
      // because sessionStorage gets set on a reload
      changed = cached != saved && cached != template[panel];
    } else if (saved !== null && !/edit/.test(window.location) && !window.location.search) { // then their saved preference
      editor.setCode(saved);
    } else { // otherwise fall back on the JS Bin default
      editor.setCode(template[panel]);
    }
  } else {
    // this means it was set via the url
    changed = true;
  }

  if (changed) {
    $document.trigger('codeChange', [ { revert: false, onload: true } ]);
  }
}<commit_msg>Tweak for line numbers<commit_after>var $document = $(document),
    $source = $('#source');

var editorModes = {
  html: 'htmlmixed',
  javascript: 'javascript',
  css: 'css'
};

var Panel = function (name, settings) {
  var panel = this,
      showPanelButton = true,
      $panel = null,
      splitterSettings = {},
      cmSettings = {};

  panel.settings = settings = settings || {};
  panel.id = panel.name = name;
  $panel = $('.panel.' + name);
  $panel.data('name', name);
  panel.$el = $panel.detach();
  panel.$el.appendTo($source);
  panel.$el.wrapAll('
');
  panel.$el = panel.$el.parent().hide();
  panel.el = document.getElementById(name);
  panel.order = ++Panel.order;

  panel.$el.data('panel', panel);

  // keyboard shortcut (set in keyboardcontrol.js)
  panelShortcuts[panelShortcuts.start + panel.order] = panel.id;

  if (panel.order === 1) {
    settings.nosplitter = true;
  }

  if (settings.editor) {
    cmSettings = {
      parserfile: [],
      tabMode: 'shift',
      readOnly: jsbin.state.embed ? 'nocursor' : false,
      dragDrop: false, // we handle it ourselves
      mode: editorModes[name],
      // lineNumbers: true,
      onChange: function (event) {
        $document.trigger('codeChange', [{ panelId: panel.id, revert: true }]);
        return true;
      },
      lineWrapping: true,
      theme: jsbin.settings.theme || 'jsbin'
    };

    $.extend(cmSettings, jsbin.settings.codemirror || {});

    panel.editor = CodeMirror.fromTextArea(panel.el, cmSettings);

    panel.processor = settings.processor || function (str) { return str; };

    panel._setupEditor(panel.editor, name);
  }

  if (!settings.nosplitter) {
    // console.log(panel.id, wrapper);
    panel.splitter = panel.$el.splitter(splitterSettings).data('splitter');
    panel.splitter.hide();
  } else {
    // create a fake splitter to let the rest of the code work
    panel.splitter = $();
  }

  if (settings.beforeRender) {
    $document.bind('render', $.proxy(settings.beforeRender, panel));
  }

  if (!settings.editor) {
    panel.ready = true;
  }

  // append panel to controls
  if (jsbin.state.embed) {
    // showPanelButton = window.location.search.indexOf(panel.id) !== -1;
  }

  if (showPanelButton) {
    this.controlButton = $('' + (settings.label || name) + '');
    this.controlButton.click(function () {
      panel.toggle();
      return false;
    });
    this.controlButton.appendTo('#panels');
  }

  $panel.focus(function () {
    panel.focus();
  });
  $panel.add(this.$el.find('.label')).click(function () {
    panel.focus();
  });
};

Panel.order = 0;

Panel.prototype = {
  virgin: true,
  visible: false,
  show: function (x) {
    // check to see if there's a panel to the left.
    // if there is, take it's size/2 and make this our
    // width
    var panel = this,
        panelCount = panel.$el.find('.panel').length;

    analytics.showPanel(panel.id);

    // panel.$el.show();
    if (panel.splitter.length) {
      if (panelCount === 0 || panelCount > 1) {
        var $panel = $('.panel.' + panel.id).show();
        // $panel.next().show(); // should be the splitter...
        $panel.closest('.panelwrapper').show();
      } else {
        panel.$el.show();
      }
      panel.splitter.show();
    } else {
      panel.$el.show();
    }

    $body.addClass('panelsVisible');

    if (panel.settings.show) {
      panel.settings.show.call(panel, true);
    }
    panel.controlButton.addClass('active');
    panel.visible = true;

    // update the splitter - but do it on the next tick
    // required to allow the splitter to see it's visible first
    setTimeout(function () {
      if (x !== undefined) {
        panel.splitter.trigger('init', x);
      } else {
        panel.distribute();
      }
      if (panel.editor) {
        // populate the panel for the first time
        if (panel.virgin) {
          $(panel.editor.win).find('.CodeMirror-scroll .CodeMirror-lines, .CodeMirror-gutter-text').css('padding-top', panel.$el.find('.label').outerHeight());

          populateEditor(panel, panel.name);
        }
        if (!panel.virgin) {
          panel.editor.focus();
          panel.focus();
        }
      }
      // update all splitter positions
      $document.trigger('sizeeditors');

      panel.virgin = false;
  }, 0);

    // TODO save which panels are visible in their profile - but check whether it's their code
  },
  hide: function () {
    var panel = this;
    // panel.$el.hide();
    panel.visible = false;
    analytics.hidePanel(panel.id);

    // update all splitter positions
    // LOGIC: when you go to hide, you need to check if there's
    // other panels inside the panel wrapper - if there are
    // hide the nested panel and any previous visible splitter
    // if there's only one - then hide the whole thing.
    // if (panel.splitter.length) {
    var panelCount = panel.$el.find('.panel').length;
    if (panelCount === 0 || panelCount > 1) {
      var $panel = $('.panel.' + panel.id).hide();
      $panel.prev().hide(); // hide the splitter if there is one

      // TODO trigger a distribute horizontally
      if ($panel.closest('.panelwrapper').find('.panel:visible').length === 0) {
        $panel.closest('.panelwrapper').hide();
        // panel.splitter.hide();
        // TODO FIXME
      }
    } else {
      panel.$el.hide();
      panel.splitter.hide();
    }
    // } else {
    //   panel.$el.hide();
    // }
    panel.controlButton.removeClass('active');
    panel.distribute();

    if (panel.settings.hide) {
      panel.settings.hide.call(panel, true);
    }

    // this.controlButton.show();
    setTimeout(function () {
      $document.trigger('sizeeditors');
    }, 110);
  },
  toggle: function () {
    (this)[this.visible ? 'hide' : 'show']();
  },
  getCode: function () {
    if (this.editor) {
      return this.editor.getCode();
    }
  },
  setCode: function (content) {
    if (this.editor) {
      this.codeSet = true;
      this.editor.setCode(content);
    }
  },
  codeSet: false,
  focus: function () {
    jsbin.panels.focus(this);
  },
  render: function () {
    var panel = this,
        ret = null;
    if (panel.editor) {
      return panel.processor(panel.getCode());
    } else if (this.visible && this.settings.render) {
      this.settings.render.apply(this, arguments);
    }
  },
  init: function () {
    if (this.settings.init) this.settings.init.call(this);
  },
  _setupEditor: function () {
    var focusedPanel = sessionStorage.getItem('panel'),
        panel = this,
        editor = panel.editor;

    // overhang from CodeMirror1
    editor.setCode = function (str) {
      //Cannot call method 'chunkSize' of undefined
      try {
        editor.setValue(str);
      } catch(err) {
        // console.error(panel.id, err + '');
      }
    };

    editor.getCode = function () {
      return editor.getValue();
    };

    editor.currentLine = function () {
      var pos = editor.getCursor();
      return pos.line;
    };

    // editor.setOption('onKeyEvent', keycontrol);
    // editor.setOption('onFocus', function () {
      // panel.$el.trigger('focus');
    // });

    editor.id = panel.name;

    editor.win = editor.getWrapperElement();
    editor.scroller = $(editor.getScrollerElement());

    $(editor.win).click(function () {
      editor.focus();
      panel.focus();
    });

    var $label = panel.$el.find('.label');
    if (document.body.className.indexOf('ie6') === -1 && $label.length) {
      editor.setOption('onScroll', function (event) {
        var scrollInfo = editor.getScrollInfo();
        if (scrollInfo.y > 10) {
          $label.stop().animate({ opacity: 0 }, 20, function () {
            $(this).hide();
          });
        } else {
          $label.show().stop().animate({ opacity: 1 }, 150);
        }
      });
    }

    var $error = null;
    $document.bind('sizeeditors', function () {
      if (panel.visible) {
        var height = panel.editor.scroller.closest('.panel').outerHeight(),
            offset = 0;
            // offset = panel.$el.find('> .label').outerHeight();

        // special case for the javascript panel
        if (panel.name === 'javascript') {
          if ($error === null) { // it wasn't there right away, so we populate
            $error = panel.$el.find('details');
          }
          offset += ($error.filter(':visible').height() || 0);
        }

        editor.scroller.height(height - offset);
        try { editor.refresh(); } catch (e) {}
      }
    });

    // required because the populate looks at the height, and at
    // this point in the code, the editor isn't visible, the browser
    // needs one more tick and it'll be there.
    setTimeout(function () {
      // if the panel isn't visible this only has the effect of putting
      // the code in the textarea (though probably costs us a lot more)
      // it has to be re-populated upon show for the first time because
      // it appears that CM2 uses the visible height to work out what
      // should be shown.
      panel.ready = true;
      populateEditor(panel, panel.name);

      if (focusedPanel == panel.name) {
        if (panel.visible) {
          // another fracking timeout to avoid conflict with other panels firing up
          setTimeout(function () {
            editor.focus();
            panel.focus();
            editor.setCursor({ line: (sessionStorage.getItem('line') || 0) * 1, ch: (sessionStorage.getItem('character') || 0) * 1 });
          }, 0);
        }
      }
    }, 0);
  },
  populateEditor: function () {
    populateEditor(this, this.name);
  }
};

function populateEditor(editor, panel) {
  if (!editor.codeSet) {
    // populate - should eventually use: session, saved data, local storage
    var cached = sessionStorage.getItem('jsbin.content.' + panel), // session code
        saved = localStorage.getItem('saved-' + panel), // user template
        sessionURL = sessionStorage.getItem('url'),
        changed = false;

    if (sessionURL !== template.url) {
      // nuke the live saving checksum
      sessionStorage.removeItem('checksum');
      saveChecksum = false;
    }

    if (template && cached == template[panel]) { // restored from original saved
      editor.setCode(cached);
    } else if (cached && sessionURL == template.url) { // try to restore the session first - only if it matches this url
      editor.setCode(cached);
      // tell the document that it's currently being edited, but check that it doesn't match the saved template
      // because sessionStorage gets set on a reload
      changed = cached != saved && cached != template[panel];
    } else if (saved !== null && !/edit/.test(window.location) && !window.location.search) { // then their saved preference
      editor.setCode(saved);
    } else { // otherwise fall back on the JS Bin default
      editor.setCode(template[panel]);
    }
  } else {
    // this means it was set via the url
    changed = true;
  }

  if (changed) {
    $document.trigger('codeChange', [ { revert: false, onload: true } ]);
  }
}<|endoftext|>


<commit_before>/* global setTimeout */
'use strict';

var _           = require('underscore');
var BaseStore   = require('synapse-common/store/base');
var SyncMachine = require('synapse-common/lib/sync-machine');
var store       = require('store');
var http        = require('http');
var https       = require('https');

var Store = BaseStore.extend({

    namespace : null,

    clientId     : null,
    clientSecret : null,
    hostname     : null,
    port         : 80,
    secure       : false,
    tokenParam   : 'Bearer',
    accessToken  : null,
    tokenType    : null,
    rawData      : null,

    constructor : function(namespace)
    {
        this.namespace = namespace + '-';
        if (store.get(this.namespace + 'oauth')) {
            this.unserializeFromLocalStorage();
        }

        this.on('change', function() {
            this.serializeToLocalStorage();
        });
    },

    setOptions : function(options)
    {
        this.clientId     = options.clientId;
        this.clientSecret = options.clientSecret;
        this.hostname     = options.api.hostname;
        this.port         = options.api.port || 80;
        this.secure       = options.api.secure;
        this.tokenParam   = options.oauth2.tokenParam;
        this.emit('change');
    },

    setToken : function(data)
    {
        this.accessToken = data.accessToken;
        this.tokenType   = data.tokenType;
        this.rawData     = data.rawData;
        this.emit('change');
    },

    _request : function(options, data, cb)
    {
        if (! _.isFunction(cb)) {
            throw "callback must be a function";
        }

        var httpLib = (this.secure === true) ? https : http;

        var req = httpLib.request(options, function (res) {
            var resText = '';

            res.on('data', function(chunk) {
                resText += chunk;
            });

            res.on('end', function() {
                var json;
                try {
                    json = JSON.parse(resText);
                } catch (e) {
                    json = {};
                }

                cb(false, {
                    data    : json,
                    headers : res.headers,
                    status  : res.statusCode
                });
            });
        });

        req.on('error', function(e) {
            console.log(e);
            cb(e);
        });

        if (data) {
            req.write(JSON.stringify(data));
        }

        req.end();

        return {
            uri     : req.uri,
            data    : req.body,
            headers : req._headers
        };
    },

    oauthRequest : function(method, path, data, cb)
    {
        if (! this.accessToken) {
            // Next tick because async callbacks should always be async
            setTimeout(function() {
                cb('Missing access token for OAuth request');
            }, 0);

            return;
        }

        var options = {
            hostname        : this.hostname,
            port            : this.port,
            method          : method,
            path            : path,
            withCredentials : false,
            headers         : {
                'Accept'       : 'application/json',
                'Content-Type' : 'application/json',
                'Authorization': this.tokenParam + ' ' + this.accessToken
            }
        };

        return this._request(options, data, cb);
    },

    request : function(method, path, data, cb)
    {
        var options = {
            hostname        : this.hostname,
            port            : this.port,
            method          : method,
            path            : path,
            withCredentials : false,
            headers         : {
                'Accept'       : 'application/json',
                'Content-Type' : 'application/json'
            }
        };

        return this._request(options, data, cb);
    },

    serializeToLocalStorage : function()
    {
        store.set(this.namespace + 'oauth', {
            clientId     : this.clientId,
            clientSecret : this.clientSecret,
            hostname     : this.hostname,
            port         : this.port,
            authorizeUrl : this.authorizeUrl,
            tokenUrl     : this.tokenUrl,
            accessToken  : this.accessToken,
            tokenType    : this.tokenType,
            rawData      : this.rawData
        });
    },

    unserializeFromLocalStorage : function()
    {
        var data = store.get(this.namespace + 'oauth');

        this.clientId     = data.clientId;
        this.clientSecret = data.clientSecret;
        this.hostname     = data.hostname;
        this.port         = data.port;
        this.authorizeUrl = data.authorizeUrl;
        this.tokenUrl     = data.tokenUrl;
        this.accessToken  = data.accessToken;
        this.tokenType    = data.tokenType;
        this.rawData      = data.rawData;
    }
});

_.extend(Store.prototype, SyncMachine);

module.exports = Store;
<commit_msg>fix serialization to local storage<commit_after>/* global setTimeout */
'use strict';

var _           = require('underscore');
var BaseStore   = require('synapse-common/store/base');
var SyncMachine = require('synapse-common/lib/sync-machine');
var store       = require('store');
var http        = require('http');
var https       = require('https');

var Store = BaseStore.extend({

    namespace : null,

    clientId     : null,
    clientSecret : null,
    hostname     : null,
    port         : 80,
    secure       : false,
    tokenParam   : 'Bearer',
    accessToken  : null,
    tokenType    : null,
    rawData      : null,

    constructor : function(namespace)
    {
        this.namespace = namespace + '-';
        if (store.get(this.namespace + 'oauth')) {
            this.unserializeFromLocalStorage();
        }

        this.on('change', function() {
            this.serializeToLocalStorage();
        });
    },

    setOptions : function(options)
    {
        this.clientId     = options.clientId;
        this.clientSecret = options.clientSecret;
        this.hostname     = options.api.hostname;
        this.port         = options.api.port || 80;
        this.secure       = options.api.secure;
        this.tokenParam   = options.oauth2.tokenParam;
        this.emit('change');
    },

    setToken : function(data)
    {
        this.accessToken = data.accessToken;
        this.tokenType   = data.tokenType;
        this.rawData     = data.rawData;
        this.emit('change');
    },

    _request : function(options, data, cb)
    {
        if (! _.isFunction(cb)) {
            throw "callback must be a function";
        }

        var httpLib = (this.secure === true) ? https : http;

        var req = httpLib.request(options, function (res) {
            var resText = '';

            res.on('data', function(chunk) {
                resText += chunk;
            });

            res.on('end', function() {
                var json;
                try {
                    json = JSON.parse(resText);
                } catch (e) {
                    json = {};
                }

                cb(false, {
                    data    : json,
                    headers : res.headers,
                    status  : res.statusCode
                });
            });
        });

        req.on('error', function(e) {
            console.log(e);
            cb(e);
        });

        if (data) {
            req.write(JSON.stringify(data));
        }

        req.end();

        return {
            uri     : req.uri,
            data    : req.body,
            headers : req._headers
        };
    },

    oauthRequest : function(method, path, data, cb)
    {
        if (! this.accessToken) {
            // Next tick because async callbacks should always be async
            setTimeout(function() {
                cb('Missing access token for OAuth request');
            }, 0);

            return;
        }

        var options = {
            hostname        : this.hostname,
            port            : this.port,
            method          : method,
            path            : path,
            withCredentials : false,
            headers         : {
                'Accept'       : 'application/json',
                'Content-Type' : 'application/json',
                'Authorization': this.tokenParam + ' ' + this.accessToken
            }
        };

        return this._request(options, data, cb);
    },

    request : function(method, path, data, cb)
    {
        var options = {
            hostname        : this.hostname,
            port            : this.port,
            method          : method,
            path            : path,
            withCredentials : false,
            headers         : {
                'Accept'       : 'application/json',
                'Content-Type' : 'application/json'
            }
        };

        return this._request(options, data, cb);
    },

    serializeToLocalStorage : function()
    {
        store.set(this.namespace + 'oauth', {
            clientId     : this.clientId,
            clientSecret : this.clientSecret,
            hostname     : this.hostname,
            port         : this.port,
            secure       : this.secure,
            tokenParam   : this.tokenParam,
            accessToken  : this.accessToken,
            tokenType    : this.tokenType,
            rawData      : this.rawData
        });
    },

    unserializeFromLocalStorage : function()
    {
        var data = store.get(this.namespace + 'oauth');

        this.clientId     = data.clientId;
        this.clientSecret = data.clientSecret;
        this.hostname     = data.hostname;
        this.port         = data.port;
        this.secure       = data.secure;
        this.tokenParam   = data.tokenParam;
        this.accessToken  = data.accessToken;
        this.tokenType    = data.tokenType;
        this.rawData      = data.rawData;
    }
});

_.extend(Store.prototype, SyncMachine);

module.exports = Store;
<|endoftext|>