Search Titles of Safari or Chrome Tabs in Multiple Windows and Bring Match to Front

Or a version which works with Safari and or Chrome:

Find and activate specific tab (Chrome and:or Safari).kmmacros (22.4 KB)

// Rob Trew MIT license 2015
// Ver 0.2: Works with Safari and or Google 
//      (searches all tabs of both, if both open)
(function (blnTypeString) {
  'use strict';

  // s -> [window, tab]
  function tabsMatching(s, lstBrowsers) {
    return mb(lstBrowsers,                  function (b) { // Each browser,
      var blnChrome = b.name()[0] === "G";

    return mb(browserWindows(b, blnChrome), function (w) { // each window,
    return mb(w.tabs(),                     function (t) { // each tab.

      return ([t.name(), t.url()].reduce(function (acc, x) {
        return acc ? acc : (x.toLowerCase().indexOf(s) !== -1);
      }, false)) ? [[b, w, t]] : [];
      
    })})});
  }

  // () -> [app]
  function browserNames() {
    return Application("System Events").applicationProcesses.whose({
      _or: [{
        name: "Safari"
      }, {
        name: "Google Chrome"
      }]
    })().map(function (a) {
      return a.name();
    });
  }

  // app -> Bool -> [window]
  function browserWindows(a, blnChrome) {
    return blnChrome ? a.windows() : a.windows.whose({
      _not: [{
        'document': null
      }]
    })();
  }

  // Monadic bind (chain) for lists
  // [a] -> (a -> [b]) -> [b]
  function mb(xs, f) {
    return [].concat.apply([], xs.map(f));
  }

  // Int -> Int -> String
  function padNum(n, lngDigits) {
    return Array(
      lngDigits - n.toString().length + 1
    ).join('0') + n;
  }

  // CHROME AND/OR SAFARI ?
  var a = Application.currentApplication(),
    sa = (a.includeStandardAdditions = true, a),
    lstBrowserNames = browserNames(),
    lstBrowsers = lstBrowserNames.map(function (x) {
      return Application(x);
    }),
    strBrowsers = lstBrowserNames.join(' or '),
    strTitle = "Find and activate " + strBrowsers + " tab";
    
  sa.activate();

  //  DIALOG INVITING SEARCH STRING (CLICK ON OK TO LIST ALL TABS)
  //  OR STRAIGHT TO LIST OF ALL TABS ?
  var s = blnTypeString ? sa.displayDialog("Search:", {
    withTitle: strTitle,
    defaultAnswer: '',
    defaultButton: "OK"
  }).textReturned.toLowerCase() : '';

  var lstFound = tabsMatching(s, lstBrowsers),
    lstChosen = [],
    lngFound = lstFound.length;

  // MULTIPLE MATCHES ? OFFER CHOICE
  if (lngFound > 1) {
    var lngDigits = lngFound.toString().length,
      lstNames = lstFound.map(function (x, i) {
        var strName = x[2].name();
        return padNum(i, lngDigits) + '\t' + (strName || x[2].url());
      }).concat('').concat(lstFound.map(function (x, i) {
        return padNum(i, lngDigits) + '\t' + x[2].url();
      }));

    sa.activate();

    var varChosen = sa.chooseFromList(lstNames, {
      withTitle: strTitle,
      withPrompt: "Choose a " + strBrowsers + " tab:",
      defaultItems: [''],
      multipleSelectionsAllowed: false
    });
    if (varChosen && varChosen[0].length) {
      lstChosen = [lstFound[parseInt(varChosen[0].split('\t')[0], 10)]];
    };
  } else lstChosen = lstFound;

  // ACTIVATE WINDOW AND TAB, RETURNING NAME & URL
  return lstChosen.map(function (oTab) {
    var b = (oTab[0]),
      w = (oTab[1]),
      t = (oTab[2]);

    b.activate();
    w.visible = false;

    if (b.name()[0] === "G") {
      var idTab = t.id();
      
      w.activeTabIndex = w.tabs().reduce(function (acc, x, i) {
        return idTab === x.id() ? i : acc;
      }, 0) + 1;
    } else w.currentTab = t;
    
    w.visible = true;

    return '[' + t.name() + '](' + t.url() + ')';
  }).join('\n');

})(false);
4 Likes