User:Elominius/diff2.js

From Wikipedia!

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
// history-core 


var history = {
  getVisits(details) {
    return new Promise(resolve => {
      chrome.history.getVisits(details, function(visitItems) {
        resolve(visitItems)
      })
    })
  },
 
  search(query) {
    return new Promise(resolve => {
      chrome.history.search(query, function(historyItems) {
        resolve(historyItems)
      })
    })
  },
 
  unlimitedSearch(query) {
    var now = (new Date).getTime()
    Object.assign(query, {
      endTime: now,
      maxResults: 100,
    })
 
    var data = {
      visitItemsHash: {},
      historyItems: [],
    }
 
    function recursiveSearch(query) {
      return history.search(query).then((historyItems) => {
        historyItems = historyItems.filter(historyItem => {
          if (data.visitItemsHash[historyItem.id]) {
            return false
          } else {
            data.visitItemsHash[historyItem.id] = true
            return true
          }
        })
 
        if (historyItems.length == 0) {
          return data.visitItemsHash
        } else {
          var promises = []
          for (var historyItem of historyItems) {
            var details = {url: historyItem.url}
            var promise = history.getVisits(details)
            promises.push(promise)
          }
          return Promise.all(promises).then((allVisitItems) => {
            var oldestLastVisitTime = now
 
            for (var i = 0; i < historyItems.length; i++) {
              var historyItem = historyItems[i]
              var visitItems = allVisitItems[i]
              data.visitItemsHash[historyItem.id] = visitItems
 
              for (visitItem of visitItems) {
                visitItem.title = ''
                Object.assign(visitItem, historyItem)
              }
 
              if (oldestLastVisitTime > historyItem.lastVisitTime) {
                oldestLastVisitTime = historyItem.lastVisitTime
              }
            }
 
            query.endTime = oldestLastVisitTime
            return recursiveSearch(query)
          })
        }
      })
    }
 
    return recursiveSearch(query).then((visitItemsHash) => {
      var allVisitItems = []
      for (visitItems of Object.keys(visitItemsHash)) {
        allVisitItems = allVisitItems.concat(visitItemsHash[visitItems])
      }
      allVisitItems.sort((a, b) => {
        return b.visitTime - a.visitTime
      })
      allVisitItems = allVisitItems.filter(a => {
        return a.visitTime > query.startTime
      })
      return allVisitItems
    })
  }
}
 
function downloadJson(historyItems) {
  var historyItemsString = JSON.stringify(historyItems, null, 2)
  var blob = new Blob([historyItemsString], {type: 'application/json'})
  var url = URL.createObjectURL(blob)
  var filename = 'history.json'
  chrome.downloads.download({
    filename,
    url,
  })
}
 
function csvDate(date) {
  return `${date.getMonth()+1}/${date.getDate()}/${date.getFullYear()}`
}
 
function csvTime(date) {
  var minutes = date.getMinutes()
  var minutesString = minutes < 10 ? '0' + minutes : '' + minutes
  var seconds = date.getSeconds()
  var secondsString = seconds < 10 ? '0' + seconds : '' + seconds
  return `${date.getHours()}:${minutesString}:${secondsString}`
}
 
function csvEscapify(str) {
  var escapeChars = [',', '"', '\r', '\n']
  var needsEscaping = false
  for (var escapeChar of escapeChars) {
    needsEscaping = needsEscaping || str.indexOf(escapeChar) > -1
  }
  if (!needsEscaping) return str
  return `"${str.replace(/"/g, '""')}"`
}
 
function downloadCsv(historyItems) {
  var raw = '\ufeff'
  raw += 'order,id,date,time,title,url,visitCount,typedCount,transition\r\n'
 
  for (var i = 0; i < historyItems.length; i++) {
    historyItem = historyItems[i]
 
    var order = i
    var {id, visitCount, typedCount, transition} = historyItem
    var visitTime = new Date(historyItem.visitTime)
    var date = csvDate(visitTime)
    var time = csvTime(visitTime)
    var title = csvEscapify(historyItem.title)
    var url = csvEscapify(historyItem.url)
 
    var entry = [
      order,
      id,
      date,
      time,
      title,
      url,
      visitCount,
      typedCount,
      transition,
    ]
 
    var entryString = entry.join(',')
    raw += entryString + '\r\n'
  }
 
  var blob = new Blob([raw], {type: 'text/csv;charset=UTF-16LE;'})
  var url = URL.createObjectURL(blob)
  var filename = 'history.csv'
  chrome.downloads.download({
    filename,
    url,
  })
}

// history-popup


function downloadHistory() {
  var timeSelect = document.getElementById('timeSelect')
  var millisecondsPerDay = 1000 * 60 * 60 * 24
  var back
 
  var query = {
    text: '',
  }
 
  switch (timeSelect.value) {
    case 'day':
      query.startTime = (new Date).getTime() - millisecondsPerDay
      break
    case 'week':
      query.startTime = (new Date).getTime() - 7 * millisecondsPerDay
      break
    case 'month':
      query.startTime = (new Date).getTime() - 31 * millisecondsPerDay
      break
    case 'forever':
      query.startTime = 0
      break
    default:
  }
 
  return history.unlimitedSearch(query)
}
 
 
window.addEventListener('load', function() {
  var timeSelect = document.getElementById('timeSelect')
  var cache = false
 
  timeSelect.onchange = function(element) {
    cache = false
 
    var msg
 
    switch (timeSelect.value) {
      case 'month':
      case 'forever':
        msg = 'This may take a while...\r\n\r\nChrome only saves 3 months (90 days) of history.'
        break
      case 'day':
      case 'week':
      default:
        msg = '\xa0'
    }
 
    var msgDiv = document.getElementById('msgDiv')
    msgDiv.innerText = msg
  }
 
  var jsonButton = document.getElementById('jsonButton')
  jsonButton.onclick = function(element) {
    if (cache) {
      downloadJson(cache)
      return
    }
 
    downloadHistory().then((historyItems) => {
      cache = historyItems
      downloadJson(historyItems)
    })
  }
 
  var csvButton = document.getElementById('csvButton')
  csvButton.onclick = function(element) {
    if (cache) {
      downloadCsv(cache)
      return
    }
 
    downloadHistory().then((historyItems) => {
      cache = historyItems
      downloadCsv(historyItems)
    })
  }
})

// tab-export

var
  popupButtonSettings, popupCounter, popupTextarea, popupTextareaContainer, popupFilterTabs, popupFilterTabsContainer,
  popupButtonCopy, popupButtonExport,
  popupFormat, popupLabelFormatTitles, popupLabelFormatCustom, popupLimitWindow,
  currentWindowId, os,
  optionsIgnoreNonHTTP, optionsIgnorePinned, optionsFormatCustom, optionsFilterTabs, optionsCustomHeader
 
var defaultPopupStates = {
  'states': {
    format: false,
    popupLimitWindow: false
  }
}
 
browser.runtime.getPlatformInfo(function (info) {
  os = info.os
})
 
browser.windows.getLastFocused(function (currentWindow) {
  currentWindowId = currentWindow.id
})
 
w.addEventListener('load', function () {
  popupCounter = d.getElementsByClassName('popup-counter')[0]
  popupFilterTabs = d.getElementsByClassName('popup-filter-tabs')[0]
  popupFilterTabsContainer = d.getElementsByClassName('popup-filter-tabs-container')[0]
  popupTextarea = d.getElementsByClassName('popup-textarea')[0]
  popupTextareaContainer = d.getElementsByClassName('popup-textarea-container')[0]
  popupFormat = d.getElementById('popup-format')
  popupLabelFormatTitles = d.getElementsByClassName('popup-label-format-titles')[0]
  popupLabelFormatCustom = d.getElementsByClassName('popup-label-format-custom')[0]
  popupLimitWindow = d.getElementById('popup-limit-window')
  popupButtonCopy = d.getElementsByClassName('popup-button-copy')[0]
  popupButtonExport = d.getElementsByClassName('popup-button-export')[0]
  popupButtonSettings = d.getElementsByClassName('popup-button-settings')[0]
 
  setLimitWindowVisibility()
 
  popupFormat.addEventListener('change', function () {
    savePopupStates()
    updatePopup()
  })
 
  popupButtonSettings.addEventListener('click', function () {
    browser.runtime.openOptionsPage()
  })
 
  popupLimitWindow.addEventListener('change', function () {
    savePopupStates()
    updatePopup()
  })
 
  popupFilterTabs.addEventListener('input', function () {
    updatePopup()
  })
 
  popupButtonCopy.addEventListener('click', function () {
    copyToClipboard()
  })
 
  popupButtonExport.addEventListener('click', function () {
    download()
  })
 
  getOptions()
  restorePopupStates()
 
  localization()
})
 
function updatePopup () {
  browser.tabs.query(
    {},
    function (tabs) {
      var list = ''
      var header = ''
      var format = '{url}\r\n'
      var actualNbTabs = 0
      var totalNbTabs = tabs.length
      var nbFilterMatch = 0
      var userInput = popupFilterTabs.value
 
      if (popupFormat.checked) format = '{title}\r\n{url}\r\n\r\n'
 
      if (optionsFormatCustom) {
        popupLabelFormatTitles.classList.add('hidden')
        popupLabelFormatCustom.classList.remove('hidden')
 
        if (popupFormat.checked) format = optionsFormatCustom.replace(/\\n/g, '\n').replace(/\\r/g, '\r')
      }
 
      if (optionsFilterTabs) popupFilterTabsContainer.classList.remove('hidden')
 
      for (var i = 0; i < totalNbTabs; i++) {
        var tabWindowId = tabs[i].windowId
        var tabPinned = tabs[i].pinned
        var tabURL = tabs[i].url
        var tabTitle = tabs[i].title
 
        if (optionsIgnorePinned && tabPinned) continue
        if (popupLimitWindow.checked && tabWindowId !== currentWindowId) continue
 
        if ((optionsIgnoreNonHTTP && tabURL.startsWith('http')) || !optionsIgnoreNonHTTP) {
          actualNbTabs += 1
 
          if (filterMatch(userInput, [tabTitle, tabURL]) || userInput === '') {
            nbFilterMatch += 1
 
            if (/<\/?[a-zA-Z]+\/?>/.test(format)) tabTitle = tabTitle.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;')
 
            list += format.replace(/{title}/g, tabTitle).replace(/{url}/g, tabURL).replace(/{window-id}/g, tabWindowId)
          }
        }
      }
 
      popupTextarea.value = ''
 
      if (optionsCustomHeader) {
        var nbTabs = (userInput !== '') ? nbFilterMatch : actualNbTabs
 
        header = optionsCustomHeader.replace(/\\n/g, '\n').replace(/\\r/g, '\r').replace(/{num-tabs}/g, nbTabs)
 
        popupTextarea.value += header + '\r\n\r\n'
      }
 
      popupTextarea.value += list
      popupCounter.textContent = (userInput !== '') ? nbFilterMatch + ' / ' + actualNbTabs : actualNbTabs
 
      setSeparatorStyle()
      popupFilterTabs.focus()
    }
  )
}
 
function filterMatch (needle, haystack) {
  var regex = new RegExp(needle, 'i')
  var match = false
 
  haystack.forEach(function (element) {
    if (regex.test(element)) match = true
  })
 
  return match
}
 
function setSeparatorStyle () {
  if (hasScrollbar(popupTextarea)) {
    popupTextareaContainer.classList.add('has-scrollbar')
  } else {
    popupTextareaContainer.classList.remove('has-scrollbar')
  }
}
 
function setLimitWindowVisibility () {
  var getting = browser.windows.getAll()
 
  getting.then(function (windowInfoArray) {
    if (windowInfoArray.length > 1) {
      popupLimitWindow.parentNode.classList.remove('hidden')
    }
  })
}
 
function copyToClipboard () {
  if (popupButtonCopy.classList.contains('disabled')) return
 
  popupTextarea.select()
 
  var message = d.execCommand('copy') ? 'copiedToClipboard' : 'notCopiedToClipboard'
 
  browser.notifications.create('ExportTabsURLs', {
    'type': 'basic',
    'title': browser.i18n.getMessage('appName'),
    'iconUrl': '../img/icon.svg',
    'message': browser.i18n.getMessage(message)
  })
 
  popupButtonCopy.classList.add('disabled')
 
  setTimeout(function () {
    browser.notifications.clear('ExportTabsURLs')
    popupButtonCopy.classList.remove('disabled')
  }, 3000)
}
 
function download () {
  var list = popupTextarea.value
 
  // fix inconsistent behaviour on Windows, see https://github.com/alct/export-tabs-urls/issues/2
  if (os === 'win') list = list.replace(/\r?\n/g, '\r\n')
 
  var element = d.createElement('a')
  element.href = 'data:text/plain;charset=utf-8,' + encodeURIComponent(list)
  element.download = moment().format('YYYYMMDDTHHmmssZZ') + '_ExportTabsURLs.txt'
  element.style.display = 'none'
 
  d.body.appendChild(element)
  element.click()
  d.body.removeChild(element)
}
 
function restorePopupStates () {
  var gettingItem = browser.storage.local.get(defaultPopupStates)
 
  gettingItem.then(function (items) {
    popupLimitWindow.checked = items.states.popupLimitWindow
    popupFormat.checked = items.states.format
 
    updatePopup()
  })
}
 
function savePopupStates () {
  browser.storage.local.set({
    'states': {
      format: popupFormat.checked,
      popupLimitWindow: popupLimitWindow.checked
    }
  })
}
 
function getOptions () {
  var gettingItem = browser.storage.local.get(defaultOptions)
 
  gettingItem.then(function (items) {
    optionsIgnoreNonHTTP = items.options.ignoreNonHTTP
    optionsIgnorePinned = items.options.ignorePinned
    optionsFormatCustom = items.options.formatCustom
    optionsFilterTabs = items.options.filterTabs
    optionsCustomHeader = items.options.customHeader
  })
}


// exptabs

    var targetWindow = null;
    var tabCount = 0;
 
    function start(tab) {
      chrome.windows.getCurrent(getWindows);
    }
 
    function getWindows(win) {
      targetWindow = win;
      chrome.tabs.getAllInWindow(targetWindow.id, getTabs);
    }
 
    function getTabs(tabs) {
      tabCount = tabs.length;
      chrome.windows.getAll({"populate" : true}, expTabs);
    }
 
    function expTabs(windows) {
      var numWindows = windows.length;
    var exportAll = document.getElementById('inclAll').checked == true ? 1 : 0;
    document.getElementById('content').value = '';
      for (var i = 0; i < numWindows; i++) {
        var win = windows[i];
        if (targetWindow.id == win.id || exportAll == 1) {
          var numTabs = win.tabs.length;
          for (var j = 0; j < numTabs; j++) {
            var tab = win.tabs[j];
            if (document.getElementById('inclTitle').checked == true) {
                document.getElementById('content').value += tab.title + '\n';
                }
            document.getElementById('content').value += tab.url + '\n\n';
          }
        }
      }
    }
 
  function openTabs() {
    var content = document.getElementById('content').value;
    var rExp = new RegExp(
        "(^|[ \t\r\n])((ftp|http|https|news|file|view-source|chrome):(([A-Za-z0-9$_.+!*(),;/?:@&~=-])|%[A-Fa-f0-9]{2}){2,}(#([a-zA-Z0-9][a-zA-Z0-9$_.+!*(),;/?:@&~=%-]*))?([A-Za-z0-9$_+!*();/?:~-])*)"
        ,"g"
      );
    var newTabs = content.match(rExp);
    if (newTabs != null) {
      var newTabsLen = newTabs.length;
      for (var j = 0; j < newTabsLen; j++) {
        var nt = newTabs[j];
        chrome.tabs.create({url: nt, active: false });
      }
    } else {
      alert('Only fully qualified URLs will be opened.');
    }
  }
 
  function sendMail(gm) {
    var action_url = "mailto:?";
    //action_url += "subject=" + encodeURIComponent(subject) + "&";
    action_url += "body=" + encodeURIComponent(document.getElementById('content').value);
    if (gm == 1) {
      var custom_url = "https://mail.google.com/mail/?extsrc=mailto&url=%s";
      action_url = custom_url.replace("%s", encodeURIComponent(action_url));
      chrome.tabs.create({ url: action_url });
    } else {
      chrome.tabs.update(tab_id, { url: action_url });
    }
  }
  
  function download() {
    
    
    var content = document.getElementById('content').value
    var content_arr = content.split('\n\n');
    var data = '<html><head></head><body>';
    for (var i = 0; i < content_arr.length; i++) {
        var content_url = content_arr[i].split('\n');
        if (document.getElementById('inclTitle').checked == true) {
            data+='<a href="'+content_url[1]+'">'+content_url[0]+'</a><br/>';
            } else {
            data+='<a href="'+content_arr[i]+'">'+content_arr[i]+'</a><br/>';
            }
        }
    data+='</body></html>';
 
    var blob = new Blob([data], {type: "text/html;charset=utf-8"});
    var url = URL.createObjectURL(blob);
    var a = document.createElement('a');
    
    a.download = "tabs.html";
    a.href = url;
    a.click();
 
  }
 
document.addEventListener('DOMContentLoaded', function () {
  document.querySelector('#btOpenTabs').addEventListener('click', openTabs);
  document.querySelector('#inclTitle').addEventListener('click', start);
  document.querySelector('#inclAll').addEventListener('click', start);
  document.querySelector('#sendMail0').addEventListener('click', function(){sendMail(0)});
  document.querySelector('#sendMail1').addEventListener('click', function(){sendMail(1)});
  document.querySelector('#download').addEventListener('click', download);
  start();
});