<commit_before>'use strict';

module.exports = function (aplazame) {

  var _ = aplazame._,
      api = require('../core/api'),
      isMobile = window.matchMedia('( max-width: 767px )');

  function parsePrice (price) {
     var priceParts = ( '' + price ).match(/(\d+)([,.](\d+))?/);
     var amount = Number(priceParts[1])*100 + Number(priceParts[3]);
     return amount;
  }

  function getQty (qtySelector) {
    if( !_.isString(qtySelector) ) {
      console.warn('warning: data-qty should be an string. pe: form#article .final-price ');
      return 1;
    }
    var qtyElement;
    try {
      qtyElement = document.querySelector(qtySelector);
    } catch(err) {
      console.warn(err.message + '\ndata-qty should be an string. pe: form#article .final-price ');
      return 1;
    }

    switch( qtyElement.nodeName.toLowerCase() ) {
      case 'input':
        return Number( qtyElement.value );
      case 'select':
        return Number( qtyElement.querySelector('option[selected]').value );
      default:
        return Number( qtyElement.textContent.trim() );
    }
  }

  var cmsPriceSelector = [
        'form#product_addtocart_form .special-price .price', // magento
        'form#product_addtocart_form .regular-price .price', // magento
        '#product-info .special-price .price', // magento
        '#product-info .regular-price .price', // magento
        'form#buy_block #our_price_display', // prestashop
        '#main [itemtype="http://schema.org/Product"] [itemtype="http://schema.org/Offer"] .price .amount' // woocommerce
      ],
      cmsQtySelector = [
        'form#product_addtocart_form input[name="qty"]', // magento
        'form#buy_block input[name="qty"]', // prestashop
        'form#product-options-form button[data-id=qty]', // custom
        '#main [itemtype="http://schema.org/Product"] form.cart input[name="quantity"]' // woocommerce
      ];

  function matchSelector (selector) {
    return document.querySelector(selector);
  }

  function readPrice (element) {
    var addDot = undefined,
        price = element.firstElementChild ? [].reduce.call(element.querySelectorAll('*'), function (prev, elem) {
          var value = elem.textContent.replace(/[^0-9.]/g,'');
          if( addDot === undefined && prev && !/\./.test(prev) ) {
            addDot = true;
          }
          console.log('part', elem.textContent);
          return prev + ( addDot ? '.' : '' ) + value;
        }, '') : element.textContent;

    return price;
  }

  function amountGetter (widgetElement) {
    var priceSelector = widgetElement.getAttribute('data-price'),
        qtySelector = widgetElement.getAttribute('data-qty');

    if( priceSelector ) {
      try{
        document.querySelector(priceSelector);
      } catch(err) {
        priceSelector = null;
        console.warn(err.message);
      }
      if( qtySelector ) {
        try{
          document.querySelector(qtySelector);
        } catch(err) {
          qtySelector = null;
          console.warn(err.message);
        }
      }
    } else {
      priceSelector = cmsPriceSelector.find(matchSelector);

      if( priceSelector ) {
        qtySelector = cmsQtySelector.find(matchSelector);
      }
    }

    var getter = priceSelector ? function () {
      var qty = qtySelector ? getQty( qtySelector ) : 1,
          priceElement = document.querySelector( priceSelector );

      return qty * parsePrice( priceElement.value !== undefined ? priceElement.value : readPrice(priceElement) );
    } : function () {
      return Number( widgetElement.getAttribute('data-amount') );
    };

    getter.priceSelector = priceSelector;
    getter.qtySelector = qtySelector;

    return getter;
  }

  function widgetsLookup (element) {
    if( !element.querySelectorAll ) {
      return;
    }

    var simulators = element.querySelectorAll('[data-aplazame-simulator]');

    if( simulators.length ) {

      var iframes = [],
          choices = [],
          currentAmount;

      _.listen(window, 'message', function (e) {
        var message = e.data;

        if( !e.used && message.aplazame === 'simulator' ) {
          e.used = true;

          switch (message.event) {
            case 'resize':
              iframes.forEach(function (iframe) {
                if( iframe.contentWindow === e.source ) {
                  iframe.style.height = message.data.height + 'px';
                }
              });
              break;
            case 'require:choices':
              e.source.postMessage({
                aplazame: 'simulator',
                event: 'choices',
                choices: choices,
                amount: currentAmount,
                mobile: isMobile.matches
              }, '*');
              break;
          }
        }
      });

      _.listen(window, 'resize', function (e) {

        iframes.forEach(function (iframe) {

          iframe.contentWindow.postMessage({
            aplazame: 'simulator',
            event: 'mobile',
            mobile: isMobile.matches
          }, '*');

        });

      });

      [].forEach.call(simulators, function (simulator) {

        if( _.elementData(simulator, 'checked') ) {
          return;
        }

        _.elementData(simulator, 'checked', true);

        var getAmount = amountGetter(simulator);
        currentAmount = Number( simulator.getAttribute('data-amount') ) || getAmount();

        var simulatorParams = {
              simulator: '[data-aplazame-simulator]',
              amount: currentAmount,
              publicKey: simulator.getAttribute('data-public-key')
            },
            iframe,
            choicesCache = {};

        simulator.innerHTML = '
comprobando financiación...
';

        aplazame.simulator(simulatorParams.amount, function (_choices) {
          var child = simulator.firstChild,
              now = new Date().getTime();

          choices = _choices;
          _choices.$amount = simulatorParams.amount;
          choicesCache[simulatorParams.amount] = _choices;

          while( child ) {
            simulator.removeChild(child);
            child = simulator.firstChild;
          }

          _.http( api.baseUrl + 'widgets/simulator/simulator.html?' + now ).then(function (response) {
            iframe = _.getIFrame({
              width: '100%'
            });

            iframes.push(iframe);
            iframe.src = api.baseUrl + 'widgets/simulator/simulator.html?' + now;
            simulator.appendChild(iframe);
          }, function () {
            simulator.innerHTML = '';
          });
        }, function () {
          simulator.innerHTML = '';
        });

        if( getAmount.priceSelector ) {
          var updateWidgetChoices = function (choices) {
                iframe.contentWindow.postMessage({
                  aplazame: 'simulator',
                  event: 'choices',
                  choices: choices,
                  amount: currentAmount,
                  mobile: isMobile.matches
                }, '*');
              },
              onPriceChange = function (e) {
                if( choicesCache[currentAmount] ) {
                  updateWidgetChoices( choicesCache[currentAmount] );
                } else {
                  if(iframe) {
                    iframe.contentWindow.postMessage({
                      aplazame: 'simulator',
                      event: 'loading'
                    }, '*');
                  }
                  aplazame.simulator( currentAmount, function (_choices) {
                    choices = _choices;
                    choicesCache[currentAmount] = _choices;
                    updateWidgetChoices(_choices);
                  });
                }
              };

          var previousQty = getAmount.qtySelector ? getQty(getAmount.qtySelector) : 1;

          setInterval(function () {
            var amount = getAmount(),
                qty = getAmount.qtySelector ? getQty(getAmount.qtySelector) : 1;

            console.log('amount', amount);

            if( amount && !_.isNumber(amount) && amount !== currentAmount || qty !== previousQty ) {
              currentAmount = amount;
              previousQty = qty;
              onPriceChange();
            }
          }, 200);
        }

      });
    }
  }

  _.liveDOM.subscribe(widgetsLookup);

  _.ready(function () {
    widgetsLookup(document);
  });

};
<commit_msg>removing unnecessary initialization to undefined<commit_after>'use strict';

module.exports = function (aplazame) {

  var _ = aplazame._,
      api = require('../core/api'),
      isMobile = window.matchMedia('( max-width: 767px )');

  function parsePrice (price) {
     var priceParts = ( '' + price ).match(/(\d+)([,.](\d+))?/);
     var amount = Number(priceParts[1])*100 + Number(priceParts[3]);
     return amount;
  }

  function getQty (qtySelector) {
    if( !_.isString(qtySelector) ) {
      console.warn('warning: data-qty should be an string. pe: form#article .final-price ');
      return 1;
    }
    var qtyElement;
    try {
      qtyElement = document.querySelector(qtySelector);
    } catch(err) {
      console.warn(err.message + '\ndata-qty should be an string. pe: form#article .final-price ');
      return 1;
    }

    switch( qtyElement.nodeName.toLowerCase() ) {
      case 'input':
        return Number( qtyElement.value );
      case 'select':
        return Number( qtyElement.querySelector('option[selected]').value );
      default:
        return Number( qtyElement.textContent.trim() );
    }
  }

  var cmsPriceSelector = [
        'form#product_addtocart_form .special-price .price', // magento
        'form#product_addtocart_form .regular-price .price', // magento
        '#product-info .special-price .price', // magento
        '#product-info .regular-price .price', // magento
        'form#buy_block #our_price_display', // prestashop
        '#main [itemtype="http://schema.org/Product"] [itemtype="http://schema.org/Offer"] .price .amount' // woocommerce
      ],
      cmsQtySelector = [
        'form#product_addtocart_form input[name="qty"]', // magento
        'form#buy_block input[name="qty"]', // prestashop
        'form#product-options-form button[data-id=qty]', // custom
        '#main [itemtype="http://schema.org/Product"] form.cart input[name="quantity"]' // woocommerce
      ];

  function matchSelector (selector) {
    return document.querySelector(selector);
  }

  function readPrice (element) {
    var addDot,
        price = element.firstElementChild ? [].reduce.call(element.querySelectorAll('*'), function (prev, elem) {
          var value = elem.textContent.replace(/[^0-9.]/g,'');
          if( addDot === undefined && prev && !/\./.test(prev) ) {
            addDot = true;
          }
          console.log('part', elem.textContent);
          return prev + ( addDot ? '.' : '' ) + value;
        }, '') : element.textContent;

    return price;
  }

  function amountGetter (widgetElement) {
    var priceSelector = widgetElement.getAttribute('data-price'),
        qtySelector = widgetElement.getAttribute('data-qty');

    if( priceSelector ) {
      try{
        document.querySelector(priceSelector);
      } catch(err) {
        priceSelector = null;
        console.warn(err.message);
      }
      if( qtySelector ) {
        try{
          document.querySelector(qtySelector);
        } catch(err) {
          qtySelector = null;
          console.warn(err.message);
        }
      }
    } else {
      priceSelector = cmsPriceSelector.find(matchSelector);

      if( priceSelector ) {
        qtySelector = cmsQtySelector.find(matchSelector);
      }
    }

    var getter = priceSelector ? function () {
      var qty = qtySelector ? getQty( qtySelector ) : 1,
          priceElement = document.querySelector( priceSelector );

      return qty * parsePrice( priceElement.value !== undefined ? priceElement.value : readPrice(priceElement) );
    } : function () {
      return Number( widgetElement.getAttribute('data-amount') );
    };

    getter.priceSelector = priceSelector;
    getter.qtySelector = qtySelector;

    return getter;
  }

  function widgetsLookup (element) {
    if( !element.querySelectorAll ) {
      return;
    }

    var simulators = element.querySelectorAll('[data-aplazame-simulator]');

    if( simulators.length ) {

      var iframes = [],
          choices = [],
          currentAmount;

      _.listen(window, 'message', function (e) {
        var message = e.data;

        if( !e.used && message.aplazame === 'simulator' ) {
          e.used = true;

          switch (message.event) {
            case 'resize':
              iframes.forEach(function (iframe) {
                if( iframe.contentWindow === e.source ) {
                  iframe.style.height = message.data.height + 'px';
                }
              });
              break;
            case 'require:choices':
              e.source.postMessage({
                aplazame: 'simulator',
                event: 'choices',
                choices: choices,
                amount: currentAmount,
                mobile: isMobile.matches
              }, '*');
              break;
          }
        }
      });

      _.listen(window, 'resize', function (e) {

        iframes.forEach(function (iframe) {

          iframe.contentWindow.postMessage({
            aplazame: 'simulator',
            event: 'mobile',
            mobile: isMobile.matches
          }, '*');

        });

      });

      [].forEach.call(simulators, function (simulator) {

        if( _.elementData(simulator, 'checked') ) {
          return;
        }

        _.elementData(simulator, 'checked', true);

        var getAmount = amountGetter(simulator);
        currentAmount = Number( simulator.getAttribute('data-amount') ) || getAmount();

        var simulatorParams = {
              simulator: '[data-aplazame-simulator]',
              amount: currentAmount,
              publicKey: simulator.getAttribute('data-public-key')
            },
            iframe,
            choicesCache = {};

        simulator.innerHTML = '
comprobando financiación...
';

        aplazame.simulator(simulatorParams.amount, function (_choices) {
          var child = simulator.firstChild,
              now = new Date().getTime();

          choices = _choices;
          _choices.$amount = simulatorParams.amount;
          choicesCache[simulatorParams.amount] = _choices;

          while( child ) {
            simulator.removeChild(child);
            child = simulator.firstChild;
          }

          _.http( api.baseUrl + 'widgets/simulator/simulator.html?' + now ).then(function (response) {
            iframe = _.getIFrame({
              width: '100%'
            });

            iframes.push(iframe);
            iframe.src = api.baseUrl + 'widgets/simulator/simulator.html?' + now;
            simulator.appendChild(iframe);
          }, function () {
            simulator.innerHTML = '';
          });
        }, function () {
          simulator.innerHTML = '';
        });

        if( getAmount.priceSelector ) {
          var updateWidgetChoices = function (choices) {
                iframe.contentWindow.postMessage({
                  aplazame: 'simulator',
                  event: 'choices',
                  choices: choices,
                  amount: currentAmount,
                  mobile: isMobile.matches
                }, '*');
              },
              onPriceChange = function (e) {
                if( choicesCache[currentAmount] ) {
                  updateWidgetChoices( choicesCache[currentAmount] );
                } else {
                  if(iframe) {
                    iframe.contentWindow.postMessage({
                      aplazame: 'simulator',
                      event: 'loading'
                    }, '*');
                  }
                  aplazame.simulator( currentAmount, function (_choices) {
                    choices = _choices;
                    choicesCache[currentAmount] = _choices;
                    updateWidgetChoices(_choices);
                  });
                }
              };

          var previousQty = getAmount.qtySelector ? getQty(getAmount.qtySelector) : 1;

          setInterval(function () {
            var amount = getAmount(),
                qty = getAmount.qtySelector ? getQty(getAmount.qtySelector) : 1;

            console.log('amount', amount);

            if( amount && !_.isNumber(amount) && amount !== currentAmount || qty !== previousQty ) {
              currentAmount = amount;
              previousQty = qty;
              onPriceChange();
            }
          }, 200);
        }

      });
    }
  }

  _.liveDOM.subscribe(widgetsLookup);

  _.ready(function () {
    widgetsLookup(document);
  });

};
<|endoftext|>


<commit_before>var path = require('path'),
    fs = require('fs');

// Prep for recursive dive of the directories
function getFilesFromDirectory(basePath, dirName, tree) {
  var dirPath = path.join(basePath, dirName),
      treeType = typeof tree,
      files = [],
      keys,
      key,
      i,
      len,
      currentPath,
      pathStats;

  // TODO: Use async lib and don't do sync
  // If the tree is not a tree/object
  if (treeType !== 'object') {
    // and is a boolean
    if (treeType === 'boolean') {
      // TODO: Handle black listing? (via false)
      if (tree === true) {
        keys = fs.readdirSync(dirPath);

        for (i = 0, len = keys.length; i < len; i++) {
          key = keys[i];
          currentPath = path.join(dirPath, key);
          pathStats = fs.statSync(currentPath);

          // If the item is a directory
          if (pathStats.isDirectory()) {
            // TODO: Recurse its files
            // getFilesFromDirectory(currentPath,
          } else {
            // Otherwise push on the new item
            files.push( currentPath );
          }
        }
      }
    }
  } else {
  // Otherwise, keep on diving in the tree
    keys = Object.getOwnPropertyNames(tree);
    for (i = 0, len = keys.length; i < len; i++) {
      key = keys[i];
      files = files.concat(getFilesFromDirectory(dirPath, key, tree[key]));
    }
  }

  return files;
}

function FileFinder(conf) {
  this.baseDir = conf.baseDir || process.cwd();
  this.directories = conf.directories || {};
  this.humanMap = {};

  // Scan for files
  this.scan();
}
FileFinder.prototype = {
  'open': function (name) {
    var exec = require('child_process').exec;
    exec('start ' + this.humanMap[name], function () {});
  },
  'query': function (query) {
    // Grab the keys for quick looping
    var humanMap = this.humanMap,
        humanNames = Object.getOwnPropertyNames(humanMap),

    // Collect all items that match
        regexpArr = query.split(/\s+/),
        j,
        matches = [],
        matchesAll;
    for (i = 0, len = humanNames.length; i < len; i++) {
      humanName = humanNames[i];
      matchesAll = true;
      for (j = regexpArr.length; j--;) {
        if (humanName.indexOf(regexpArr[j]) === -1) {
          matchesAll = false;
          break;
        }
      }

      if (matchesAll === true) {
        matches.push(humanName);
      }
    }

    // Return the matches
    return matches;
  },
  'scan': function () {
    var fullFilenames = this.scanFullFilenames();
    this.mapFilenamesToHuman(fullFilenames);
  },
  'scanFullFilenames': function () {
    var retArr = this.fullFilenames = getFilesFromDirectory(this.baseDir, '.', this.directories);
    return retArr;
  },
  'mapFilenamesToHuman': function (fullFilenames) {
    // Recusively dive and collect all files
    var i,
        len,
        humanToFullFilenameMap = this.humanMap,
        baseDir = this.baseDir,
        filename,
        humanName;

    // Loop through the files
    for (i = 0, len = fullFilenames.length; i < len; i++) {
      // Get each filename sans base_dir
      filename = fullFilenames[i];
      humanName = filename.replace(baseDir, '');

      // Add the file name to the map
      humanToFullFilenameMap[humanName] = filename;
    }

    return this;
  }
};

// Grab our config and create our fileFinder
var conf = require('./finder.conf.js'),
    fileFinder = new FileFinder(conf),
// Generate the interface
    rl = require('readline'),
    iface = rl.createInterface(process.stdin, process.stdout, null);

// Set up startSearch for calling later
function startSearch() {
  iface.question('Enter search: ', function (query) {
    // Get the results of our query
    var matches = fileFinder.query(query),
        len = matches.length;

    // If no results were found
    if (len === 0) {
      console.log('No results found for: ' + query);
      startSearch();
    } else {
    // Otherwise, list options
      for (i = 0; i < len; i++) {
        console.log(i + ': ' + matches[i]);
      }

      // Ask for a number
      iface.question('Which item would you like to open? ', function (numStr) {
        var num = +numStr,
            item;

        // If the number is not NaN
        if (num === num) {
          // and if it is in our result set
          if (numStr !== '' && num >= 0 && num < len) {
            // Open it
            item = matches[num];
            console.log('Opening: ' + item);
            fileFinder.open(item);
          }
        } else {
        // Otherwise, if there was a word in there so we are assuming it was 'rescan'
          // Rescan
          console.log('Rescanning...');
          fileFinder.scan();
        }

        // Begin the search again
        startSearch();
      });
    }
  });
}

startSearch();

// TODO: Eventually...
// // TEST: tty inputting
// var sentence = {
  // 'charArr': [],
  // 'push': function (letter) {
    // val += letter;
    // // TODO: Move the cursor
  // },
  // 'delete': function (letter) {

    // // TODO: Rewrite sentence
  // }
// };
// process.stdin.resume();
// process.stdin.setEncoding('utf8');

// require('tty').setRawMode(true);

// function ontype(letter) {
  // switch (letter) {
  // // If the command is to terminate, terminate
    // case '\u0003':
      // return process.exit();
      // break;
  // // If a carriage return (enter) was hit
    // case '\r':
    // case '\n':
      // // TODO: Open the highlighted item
      // console.log('Opening: ', sentence);

      // // and retype the selected item
      // console.log('Select a file: ', sentence);
      // break;
    // default:
      // // Otherwise, append the item to the sentence
      // sentence

      // // Get unicode
      // // console.log(arguments);
  // }
// }
// process.stdin.on('data', ontype);<commit_msg>Updated to accept uppercase filtering and recurse<commit_after>var path = require('path'),
    fs = require('fs');

// Prep for recursive dive of the directories
function getFilesFromDirectory(basePath, dirName, tree) {
  var dirPath = path.join(basePath, dirName),
      treeType = typeof tree,
      files = [],
      keys,
      key,
      i,
      len,
      currentPath,
      pathStats;

  // TODO: Use async lib and don't do sync
  // If the tree is not a tree/object
  if (treeType !== 'object') {
    // and is a boolean
    if (treeType === 'boolean') {
      // TODO: Handle black listing? (via false)
      if (tree === true) {
        keys = fs.readdirSync(dirPath);

        for (i = 0, len = keys.length; i < len; i++) {
          key = keys[i];
          currentPath = path.join(dirPath, key);
          pathStats = fs.statSync(currentPath);

          // If the item is a directory
          if (pathStats.isDirectory()) {
            files = files.concat(getFilesFromDirectory(dirPath, key, true));
          } else {
            // Otherwise push on the new item
            files.push( currentPath );
          }
        }
      }
    }
  } else {
  // Otherwise, keep on diving in the tree
    keys = Object.getOwnPropertyNames(tree);
    for (i = 0, len = keys.length; i < len; i++) {
      key = keys[i];
      files = files.concat(getFilesFromDirectory(dirPath, key, tree[key]));
    }
  }

  return files;
}

function FileFinder(conf) {
  this.baseDir = conf.baseDir || process.cwd();
  this.directories = conf.directories || {};
  this.humanMap = {};

  // Scan for files
  this.scan();
}
FileFinder.prototype = {
  'open': function (name) {
    var exec = require('child_process').exec;
    exec('start ' + this.humanMap[name], function () {});
  },
  'query': function (query) {
    // Grab the keys for quick looping
    var humanMap = this.humanMap,
        humanNames = Object.getOwnPropertyNames(humanMap),

    // Collect all items that match
        queryParts = query.split(/\s+/),
        queryPart,
        hasUppercase,
        regexpFlags,
        regexpArr = [],
        regexp,
        j,
        matches = [],
        matchesAll;

    // Create the regexp items
    for (i = 0, len = queryParts.length; i < len; i++) {
      queryPart = queryParts[i];

      // If the queryPart uses upper case, be case sensitive. Otherwise, don't.
      hasUppercase = !!queryPart.match(/[A-Z]/),
      regexpFlags = hasUppercase ? '' : 'i';
      regexp = new RegExp(queryPart, regexpFlags)

      // Generate the filter and push it onto the array
      regexpArr.push(regexp);
    }

    // Iterate the names
    for (i = 0, len = humanNames.length; i < len; i++) {
      humanName = humanNames[i];
      matchesAll = true;

      // Check each name against a regular expression
      for (j = regexpArr.length; j--;) {

        // If it does not match, fail the loop
        if (!humanName.match(regexpArr[j])) {
          matchesAll = false;
          break;
        }
      }

      // If there were no failures
      if (matchesAll === true) {
        // Push the match on the list
        matches.push(humanName);
      }
    }

    // Return the matches
    return matches;
  },
  'scan': function () {
    var fullFilenames = this.scanFullFilenames();
    this.mapFilenamesToHuman(fullFilenames);
  },
  'scanFullFilenames': function () {
    var retArr = this.fullFilenames = getFilesFromDirectory(this.baseDir, '.', this.directories);
    return retArr;
  },
  'mapFilenamesToHuman': function (fullFilenames) {
    // Recusively dive and collect all files
    var i,
        len,
        humanToFullFilenameMap = this.humanMap,
        baseDir = this.baseDir,
        filename,
        humanName;

    // Loop through the files
    for (i = 0, len = fullFilenames.length; i < len; i++) {
      // Get each filename sans base_dir
      filename = fullFilenames[i];
      humanName = filename.replace(baseDir, '');

      // Add the file name to the map
      humanToFullFilenameMap[humanName] = filename;
    }

    return this;
  }
};

// Grab our config and create our fileFinder
var conf = require('./finder.conf.js'),
    fileFinder = new FileFinder(conf),
// Generate the interface
    rl = require('readline'),
    iface = rl.createInterface(process.stdin, process.stdout, null);

// Set up startSearch for calling later
function startSearch() {
  iface.question('Enter search: ', function (query) {
    // Get the results of our query
    var matches = fileFinder.query(query),
        len = matches.length;

    // If no results were found
    if (len === 0) {
      console.log('No results found for: ' + query);
      startSearch();
    } else {
    // Otherwise, list options
      for (i = 0; i < len; i++) {
        console.log(i + ': ' + matches[i]);
      }

      // Ask for a number
      iface.question('Which item would you like to open? ', function (numStr) {
        var num = +numStr,
            item;

        // If the number is not NaN
        if (num === num) {
          // and if it is in our result set
          if (numStr !== '' && num >= 0 && num < len) {
            // Open it
            item = matches[num];
            console.log('Opening: ' + item);
            fileFinder.open(item);
          }
        } else {
        // Otherwise, if there was a word in there so we are assuming it was 'rescan'
          // Rescan
          console.log('Rescanning...');
          fileFinder.scan();
        }

        // Begin the search again
        startSearch();
      });
    }
  });
}

startSearch();

// TODO: Eventually...
// // TEST: tty inputting
// var sentence = {
  // 'charArr': [],
  // 'push': function (letter) {
    // val += letter;
    // // TODO: Move the cursor
  // },
  // 'delete': function (letter) {

    // // TODO: Rewrite sentence
  // }
// };
// process.stdin.resume();
// process.stdin.setEncoding('utf8');

// require('tty').setRawMode(true);

// function ontype(letter) {
  // switch (letter) {
  // // If the command is to terminate, terminate
    // case '\u0003':
      // return process.exit();
      // break;
  // // If a carriage return (enter) was hit
    // case '\r':
    // case '\n':
      // // TODO: Open the highlighted item
      // console.log('Opening: ', sentence);

      // // and retype the selected item
      // console.log('Select a file: ', sentence);
      // break;
    // default:
      // // Otherwise, append the item to the sentence
      // sentence

      // // Get unicode
      // // console.log(arguments);
  // }
// }
// process.stdin.on('data', ontype);<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2014 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

function factorial(n) {
  if ( n > 170 ) return 1/0;
  var r = 1;
  while ( n > 0 ) r *= n--;
  return r;
};
function permutation(n, r) { return factorial(n) / factorial(n-r); };
function combination(n, r) { return permutation(n, r) / factorial(r); };

function trigFn(f) {
  return function(a) {
    return f(this.degreesMode ? a * Math.PI / 180 : a);
  };
}

function invTrigFn(f) {
  return function(a) {
    return this.degreesMode ? f(a) / Math.PI * 180 : f(a);
  };
}

/** Make a Binary Action. **/
function binaryOp(name, keys, f, sym) {
  f.toString = function() { return sym; };
  return {
    name: name,
    label: sym,
    keyboardShortcuts: keys,
    action: function() {
      if ( this.op != DEFAULT_OP ) this.equals();
      this.push('', f);
      this.editable = true;
    }
  };
}

function unaryOp(name, keys, f, opt_sym) {
  var sym = opt_sym || name;
  f.toString = function() { return sym; };

  return {
    name: name,
    label: sym,
    keyboardShortcuts: keys,
    action: function() {
      this.op = f;
      this.push(f.call(this, this.a2));
      this.editable = false;
    }
  };
}

/** Make a 0-9 Number Action. **/
function num(n) {
  return {
    name: n.toString(),
    keyboardShortcuts: [48+n /* 0 */ , 96+n /* keypad-0 */],
    action: function() {
      if ( ! this.editable ) {
        this.push(n);
        this.editable = true;
      } else {
        if ( this.a2 == '0' && ! n ) return;
        this.a2 = this.a2 == '0' ? n : this.a2.toString() + n;
      }
    }
  };
}

var DEFAULT_OP = function(a1, a2) { return a2; };
DEFAULT_OP.toString = function() { return ''; };

/** A subclass of FloatFieldView which doesn't display 0 values. **/
MODEL({
  name:  'CalcFloatFieldView',
  extendsModel: 'FloatFieldView',
  methods: { valueToText: function(v) { return v == 0 ? '' : v.toString(); } }
});

MODEL({ name: 'History', properties: [ 'op', 'a2' ] });

MODEL({
  name: 'Calc',

  requires: [ 'MainButtonsView', 'SecondaryButtonsView', 'TertiaryButtonsView', 'HistoryView', 'CalcView' ],

  templates: [ function CSS() {/*
    body {
      font-family: Roboto, 'Helvetica Neue', Helvetica, Arial;
      font-size: 24px;
      margin: 0;
    }

    * {
      box-sizing: border-box;
    }

    html {
      margin: 0;
      padding: 0;
      width: 100%;
      height: 100%;
      overflow: hidden;
    }

    body {
      margin: 0px;
      padding: 0px;
      width: 100%;
      height: 100%;
      font-weight: 300;
    }

    ::-webkit-scrollbar {
      display: none;
    }

    ::-webkit-scrollbar-thumb {
      display: none;
    }

    .calc {
      background-color: #fff;
      border: 0;
      margin: 0;
      padding: 0px;
      display: flex;
      flex-direction: column;
      height: 100%;
    }

    .calc-display, .calc-display:focus {
      border: none;
      letter-spacing: 1px;
      line-height: 25px;
      margin: 0;
      min-width: 204px;
      overflow: scroll;
      padding: 0 25pt 2pt 25pt;
      width: calc( 100% - 40px );
      text-align: right;
    }

    .edge-top {
      height: 5px;
      width: 100%;
      z-index: 99;
      position: absolute;
      background: #fff;
    }

    .edge {
      background: linear-gradient(to bottom, rgba(255,255,255,1) 0%,
                                             rgba(255,255,255,0) 100%);
      height: 20px;
      position: absolute;
      top: 5px;
      width: 100%;
      z-index: 99;
    }

    .edge2 {
      background: linear-gradient(to bottom, rgba(0,0,0,0.5) 0%,
                                             rgba(0,0,0,0) 100%);
      top: 12px;
      height: 12px;
      position: relative;
      width: 100%;
      z-index: 99;
    }

    .calc .buttons {
      flex: 1 1 100%;
      width: 100%;
      height: 350px;
    }

    .button-row {
      display: flex;
      flex-direction: row;
      flex-wrap: nowrap;
      flex: 1 1 100%;
      justify-content: space-between;
      align-items: stretch;
    }

    .button {
      flex-grow: 1;
      justify-content: center;
      display: flex;
      align-items: center;
      background-color: #4b4b4b;
    }

    .rhs-ops {
      border-left-width: 1px;
      border-left-style: solid;
      border-left-color: rgb(68, 68, 68);
    }

    .rhs-ops .button {
      background-color: #777;
    }

    .button-column {
      display: flex;
      flex-direction: column;
      flex-wrap: nowrap;
    }

    .inner-calc-display {
      position: absolute;
      right: 20pt;
      top: 100%;
      transition: top 0.3s ease;
      width: 85%;
    }

    .calc-display {
      flex-grow: 5;
      position: relative;
    }

    .secondaryButtons {
      padding-left: 10px;
      background: rgb(64, 189, 158);
    }

    .secondaryButtons .button {
      background: rgb(64, 189, 158);
    }

    .tertiaryButtons {
      padding-left: 10px;
      background: rgb(29, 233, 182);
    }

    .tertiaryButtons .button {
      background: rgb(29, 233, 182);
    }

    .keypad {
      flex-grow: 0;
      flex-shrink: 0;
      margin-bottom: -4px;
    }

    // Copied from foam.css.
    .SliderPanel .shadow {
      background: linear-gradient(to left, rgba(0,0,0,0.3) 0%,
                                         rgba(0,0,0,0) 100%);
      height: 100%;
      left: -8px;
      position: absolute;
      width: 8px;
    }
  */}],

  properties: [
    { name: 'degreesMode', defaultValue: false },
    { name: 'a1', defaultValue: 0 },
    { name: 'a2', defaultValue: '' },
    { name: 'editable', defaultValue: true },
    {
      name: 'op',
      defaultValue: DEFAULT_OP
    },
    {
      model_: 'ArrayProperty',
      name: 'history',
      view: { factory_: 'DAOListView', rowView: 'HistoryView' },
      factory: function() { return [].sink; }
    },
    {
      model_: 'StringProperty',
      name: 'row1',
      view: 'ALabel'
    },
  ],

  methods: {
    init: function() {
      this.SUPER();

      Events.dynamic(function() { this.op; this.a2; }.bind(this), EventService.framed(function() {
        this.row1 = this.op + ( this.a2 != '' ? ' ' + this.a2 : '' );
      }.bind(this)));
    },
    push: function(a2, opt_op) {
      this.history.put(History.create(this));
      this.a1 = this.a2;
      this.a2 = a2;
      this.op = opt_op || DEFAULT_OP;
    }
  },

  actions: [
    num(1), num(2), num(3),
    num(4), num(5), num(6),
    num(7), num(8), num(9), num(0),
    binaryOp('div',   [111, 191],         function(a1, a2) { return a1 / a2; }, '\u00F7'),
    binaryOp('mult',  [106, 'shift-56'],  function(a1, a2) { return a1 * a2; }, '\u00D7'),
    binaryOp('plus',  [107, 'shift-187'], function(a1, a2) { return a1 + a2; }, '+'),
    binaryOp('minus', [109, 189],         function(a1, a2) { return a1 - a2; }, '–'),
    binaryOp('pow',   [],                 Math.pow,                             'yⁿ'),
    binaryOp('p',     [],                 permutation,                          'nPr'),
    binaryOp('c',     [],                 combination,                          'nCr'),
    binaryOp('root',  [],                 function(a1, a2) { return Math.pow(a2, 1/a1); }, '\u207F \u221AY'),
    {
      name: 'ac',
      label: 'AC',
      help: 'All Clear.',
      keyboardShortcuts: [ 65 /* a */, 67 /* c */ ],
      action: function() {
        this.a2 = '0';
        this.editable = true;
        this.op = DEFAULT_OP;
        this.history = [].sink;
      }
    },
    {
      name: 'sign',
      label: '+/-',
      keyboardShortcuts: [ 78 /* n */ , 83 /* s */],
      action: function() { this.a2 = - this.a2; }
    },
    {
      name: 'point',
      label: '.',
      keyboardShortcuts: [ 110, 190 ],
      action: function() {
        if ( this.a2.toString().indexOf('.') == -1 ) this.a2 = this.a2 + '.';
      }
    },
    {
      name: 'equals',
      label: '=',
      keyboardShortcuts: [ 187 /* '=' */, 13 /* <enter> */ ],
      action: function() {
        this.push(this.op(parseFloat(this.a1), parseFloat(this.a2)));
        this.editable = false;
      }
    },
    {
      name: 'backspace',
      keyboardShortcuts: [ 8 /* backspace */ ],
      action: function() {
        this.a2 = this.a2.toString.length == 1 ?
          '0' :
          this.a2.toString().substring(0, this.a2.length-1) ;
      }
    },
    {
      name: 'pi',
      label: 'π',
      keyboardShortcuts: [80 /* p */],
      action: function() { this.a2 = Math.PI; }
    },
    {
      name: 'e',
      label: 'E',
      keyboardShortcuts: [69 /* e */],
      action: function() { this.a2 = Math.E; }
    },
    {
      name: 'percent',
      label: '%',
      action: function() { this.a2 = this.a2 / 100.0; }
    },
    {
      name: 'deg',
      action: function() { this.degreesMode = true; }
    },
    {
      name: 'rad',
      action: function() { this.degreesMode = false; }
    },
    unaryOp('fact',   ['shift-49' /* ! */], factorial,             'x!'),
    unaryOp('inv',    [73 /* i */], function(a) { return 1.0/a; }, '1/x'),
    unaryOp('sin',    [], trigFn(Math.sin)),
    unaryOp('cos',    [], trigFn(Math.cos)),
    unaryOp('tan',    [], trigFn(Math.tan)),
    unaryOp('asin',   [], invTrigFn(Math.asin)),
    unaryOp('acos',   [], invTrigFn(Math.acos)),
    unaryOp('atan',   [], invTrigFn(Math.atan)),
    unaryOp('square', [], function(a) { return a*a; }, 'x²'),
    unaryOp('sqroot', [82 /* r */], Math.sqrt, '√'),
    unaryOp('log',    [], function(a) { return Math.log(a) / Math.log(10); }),
    unaryOp('ln',     [], Math.log),
    unaryOp('exp',    [], Math.exp, 'eⁿ'),
  ]
});

// HACK: The buttons don't draw using the Roboto font because it isn't loaded yet.
// So we wait a second, to give the font time to load, then redraw all the buttons.
// TODO: Something better.
MODEL({
  name: 'ActionButtonCView2',
  extendsModel: 'ActionButtonCView',
  methods: {
    init: function() {
      this.SUPER();
      setTimeout(function() { this.view.paint(); }.bind(this), 1000);
    }
  }
});

var CalcButton = ActionButtonCView2.xbind({
  color:      'white',
  background: '#4b4b4b',
  width:      95,
  height:     85,
  font:       '24px Roboto'
});
X.registerModel(CalcButton, 'ActionButton');

MODEL({ name: 'HistoryView',          extendsModel: 'DetailView', templates: [ { name: 'toHTML' } ] });
MODEL({ name: 'CalcView',             extendsModel: 'DetailView', templates: [ { name: 'toHTML' } ] });
<commit_msg>ACalc: removed some no longer required requires.<commit_after>/**
 * @license
 * Copyright 2014 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

function factorial(n) {
  if ( n > 170 ) return 1/0;
  var r = 1;
  while ( n > 0 ) r *= n--;
  return r;
};
function permutation(n, r) { return factorial(n) / factorial(n-r); };
function combination(n, r) { return permutation(n, r) / factorial(r); };

function trigFn(f) {
  return function(a) {
    return f(this.degreesMode ? a * Math.PI / 180 : a);
  };
}

function invTrigFn(f) {
  return function(a) {
    return this.degreesMode ? f(a) / Math.PI * 180 : f(a);
  };
}

/** Make a Binary Action. **/
function binaryOp(name, keys, f, sym) {
  f.toString = function() { return sym; };
  return {
    name: name,
    label: sym,
    keyboardShortcuts: keys,
    action: function() {
      if ( this.op != DEFAULT_OP ) this.equals();
      this.push('', f);
      this.editable = true;
    }
  };
}

function unaryOp(name, keys, f, opt_sym) {
  var sym = opt_sym || name;
  f.toString = function() { return sym; };

  return {
    name: name,
    label: sym,
    keyboardShortcuts: keys,
    action: function() {
      this.op = f;
      this.push(f.call(this, this.a2));
      this.editable = false;
    }
  };
}

/** Make a 0-9 Number Action. **/
function num(n) {
  return {
    name: n.toString(),
    keyboardShortcuts: [48+n /* 0 */ , 96+n /* keypad-0 */],
    action: function() {
      if ( ! this.editable ) {
        this.push(n);
        this.editable = true;
      } else {
        if ( this.a2 == '0' && ! n ) return;
        this.a2 = this.a2 == '0' ? n : this.a2.toString() + n;
      }
    }
  };
}

var DEFAULT_OP = function(a1, a2) { return a2; };
DEFAULT_OP.toString = function() { return ''; };

/** A subclass of FloatFieldView which doesn't display 0 values. **/
MODEL({
  name:  'CalcFloatFieldView',
  extendsModel: 'FloatFieldView',
  methods: { valueToText: function(v) { return v == 0 ? '' : v.toString(); } }
});

MODEL({ name: 'History', properties: [ 'op', 'a2' ] });

MODEL({
  name: 'Calc',

  requires: [ 'HistoryView', 'CalcView' ],

  templates: [ function CSS() {/*
    body {
      font-family: Roboto, 'Helvetica Neue', Helvetica, Arial;
      font-size: 24px;
      margin: 0;
    }

    * {
      box-sizing: border-box;
    }

    html {
      margin: 0;
      padding: 0;
      width: 100%;
      height: 100%;
      overflow: hidden;
    }

    body {
      margin: 0px;
      padding: 0px;
      width: 100%;
      height: 100%;
      font-weight: 300;
    }

    ::-webkit-scrollbar {
      display: none;
    }

    ::-webkit-scrollbar-thumb {
      display: none;
    }

    .calc {
      background-color: #fff;
      border: 0;
      margin: 0;
      padding: 0px;
      display: flex;
      flex-direction: column;
      height: 100%;
    }

    .calc-display, .calc-display:focus {
      border: none;
      letter-spacing: 1px;
      line-height: 25px;
      margin: 0;
      min-width: 204px;
      overflow: scroll;
      padding: 0 25pt 2pt 25pt;
      width: calc( 100% - 40px );
      text-align: right;
    }

    .edge-top {
      height: 5px;
      width: 100%;
      z-index: 99;
      position: absolute;
      background: #fff;
    }

    .edge {
      background: linear-gradient(to bottom, rgba(255,255,255,1) 0%,
                                             rgba(255,255,255,0) 100%);
      height: 20px;
      position: absolute;
      top: 5px;
      width: 100%;
      z-index: 99;
    }

    .edge2 {
      background: linear-gradient(to bottom, rgba(0,0,0,0.5) 0%,
                                             rgba(0,0,0,0) 100%);
      top: 12px;
      height: 12px;
      position: relative;
      width: 100%;
      z-index: 99;
    }

    .calc .buttons {
      flex: 1 1 100%;
      width: 100%;
      height: 350px;
    }

    .button-row {
      display: flex;
      flex-direction: row;
      flex-wrap: nowrap;
      flex: 1 1 100%;
      justify-content: space-between;
      align-items: stretch;
    }

    .button {
      flex-grow: 1;
      justify-content: center;
      display: flex;
      align-items: center;
      background-color: #4b4b4b;
    }

    .rhs-ops {
      border-left-width: 1px;
      border-left-style: solid;
      border-left-color: rgb(68, 68, 68);
    }

    .rhs-ops .button {
      background-color: #777;
    }

    .button-column {
      display: flex;
      flex-direction: column;
      flex-wrap: nowrap;
    }

    .inner-calc-display {
      position: absolute;
      right: 20pt;
      top: 100%;
      transition: top 0.3s ease;
      width: 85%;
    }

    .calc-display {
      flex-grow: 5;
      position: relative;
    }

    .secondaryButtons {
      padding-left: 10px;
      background: rgb(64, 189, 158);
    }

    .secondaryButtons .button {
      background: rgb(64, 189, 158);
    }

    .tertiaryButtons {
      padding-left: 10px;
      background: rgb(29, 233, 182);
    }

    .tertiaryButtons .button {
      background: rgb(29, 233, 182);
    }

    .keypad {
      flex-grow: 0;
      flex-shrink: 0;
      margin-bottom: -4px;
    }

    // Copied from foam.css.
    .SliderPanel .shadow {
      background: linear-gradient(to left, rgba(0,0,0,0.3) 0%,
                                         rgba(0,0,0,0) 100%);
      height: 100%;
      left: -8px;
      position: absolute;
      width: 8px;
    }
  */}],

  properties: [
    { name: 'degreesMode', defaultValue: false },
    { name: 'a1', defaultValue: 0 },
    { name: 'a2', defaultValue: '' },
    { name: 'editable', defaultValue: true },
    {
      name: 'op',
      defaultValue: DEFAULT_OP
    },
    {
      model_: 'ArrayProperty',
      name: 'history',
      view: { factory_: 'DAOListView', rowView: 'HistoryView' },
      factory: function() { return [].sink; }
    },
    {
      model_: 'StringProperty',
      name: 'row1',
      view: 'ALabel'
    },
  ],

  methods: {
    init: function() {
      this.SUPER();

      Events.dynamic(function() { this.op; this.a2; }.bind(this), EventService.framed(function() {
        this.row1 = this.op + ( this.a2 != '' ? ' ' + this.a2 : '' );
      }.bind(this)));
    },
    push: function(a2, opt_op) {
      this.history.put(History.create(this));
      this.a1 = this.a2;
      this.a2 = a2;
      this.op = opt_op || DEFAULT_OP;
    }
  },

  actions: [
    num(1), num(2), num(3),
    num(4), num(5), num(6),
    num(7), num(8), num(9), num(0),
    binaryOp('div',   [111, 191],         function(a1, a2) { return a1 / a2; }, '\u00F7'),
    binaryOp('mult',  [106, 'shift-56'],  function(a1, a2) { return a1 * a2; }, '\u00D7'),
    binaryOp('plus',  [107, 'shift-187'], function(a1, a2) { return a1 + a2; }, '+'),
    binaryOp('minus', [109, 189],         function(a1, a2) { return a1 - a2; }, '–'),
    binaryOp('pow',   [],                 Math.pow,                             'yⁿ'),
    binaryOp('p',     [],                 permutation,                          'nPr'),
    binaryOp('c',     [],                 combination,                          'nCr'),
    binaryOp('root',  [],                 function(a1, a2) { return Math.pow(a2, 1/a1); }, '\u207F \u221AY'),
    {
      name: 'ac',
      label: 'AC',
      help: 'All Clear.',
      keyboardShortcuts: [ 65 /* a */, 67 /* c */ ],
      action: function() {
        this.a2 = '0';
        this.editable = true;
        this.op = DEFAULT_OP;
        this.history = [].sink;
      }
    },
    {
      name: 'sign',
      label: '+/-',
      keyboardShortcuts: [ 78 /* n */ , 83 /* s */],
      action: function() { this.a2 = - this.a2; }
    },
    {
      name: 'point',
      label: '.',
      keyboardShortcuts: [ 110, 190 ],
      action: function() {
        if ( this.a2.toString().indexOf('.') == -1 ) this.a2 = this.a2 + '.';
      }
    },
    {
      name: 'equals',
      label: '=',
      keyboardShortcuts: [ 187 /* '=' */, 13 /* <enter> */ ],
      action: function() {
        this.push(this.op(parseFloat(this.a1), parseFloat(this.a2)));
        this.editable = false;
      }
    },
    {
      name: 'backspace',
      keyboardShortcuts: [ 8 /* backspace */ ],
      action: function() {
        this.a2 = this.a2.toString.length == 1 ?
          '0' :
          this.a2.toString().substring(0, this.a2.length-1) ;
      }
    },
    {
      name: 'pi',
      label: 'π',
      keyboardShortcuts: [80 /* p */],
      action: function() { this.a2 = Math.PI; }
    },
    {
      name: 'e',
      label: 'E',
      keyboardShortcuts: [69 /* e */],
      action: function() { this.a2 = Math.E; }
    },
    {
      name: 'percent',
      label: '%',
      action: function() { this.a2 = this.a2 / 100.0; }
    },
    {
      name: 'deg',
      action: function() { this.degreesMode = true; }
    },
    {
      name: 'rad',
      action: function() { this.degreesMode = false; }
    },
    unaryOp('fact',   ['shift-49' /* ! */], factorial,             'x!'),
    unaryOp('inv',    [73 /* i */], function(a) { return 1.0/a; }, '1/x'),
    unaryOp('sin',    [], trigFn(Math.sin)),
    unaryOp('cos',    [], trigFn(Math.cos)),
    unaryOp('tan',    [], trigFn(Math.tan)),
    unaryOp('asin',   [], invTrigFn(Math.asin)),
    unaryOp('acos',   [], invTrigFn(Math.acos)),
    unaryOp('atan',   [], invTrigFn(Math.atan)),
    unaryOp('square', [], function(a) { return a*a; }, 'x²'),
    unaryOp('sqroot', [82 /* r */], Math.sqrt, '√'),
    unaryOp('log',    [], function(a) { return Math.log(a) / Math.log(10); }),
    unaryOp('ln',     [], Math.log),
    unaryOp('exp',    [], Math.exp, 'eⁿ'),
  ]
});

// HACK: The buttons don't draw using the Roboto font because it isn't loaded yet.
// So we wait a second, to give the font time to load, then redraw all the buttons.
// TODO: Something better.
MODEL({
  name: 'ActionButtonCView2',
  extendsModel: 'ActionButtonCView',
  methods: {
    init: function() {
      this.SUPER();
      setTimeout(function() { this.view.paint(); }.bind(this), 1000);
    }
  }
});

var CalcButton = ActionButtonCView2.xbind({
  color:      'white',
  background: '#4b4b4b',
  width:      95,
  height:     85,
  font:       '24px Roboto'
});
X.registerModel(CalcButton, 'ActionButton');

MODEL({ name: 'HistoryView',          extendsModel: 'DetailView', templates: [ { name: 'toHTML' } ] });
MODEL({ name: 'CalcView',             extendsModel: 'DetailView', templates: [ { name: 'toHTML' } ] });
<|endoftext|>


<commit_before>/* Final Score MC Ban Manager
 *
 */
// TODO add datepicker to incident date field in add incident
// TODO add field verification
(function($){

    // General Variables
    var info,
        DataStructure,
        incident,
        attachNewUser = false;

    /* ----------------------------- *
     *   DATA STRUCTURE OBJECT       *
     * ----------------------------- */

    /**
     * Convenience constructor for a DataStructure.
     * @param {Object} options The options/settings for the DataStructure.
     * Options:
     * type {String} Type of the DataStructure valid type strings: text, date, textarea, select, int, checkbox. Default is text.
     * disabled {boolean} Whether this field should be disabled. Default is false.
     * name {String} The name of the Data Stucture. Used when ouptuing it's form label.
     * after {Mixed} The element to insert after the DataStructure when it is generated. Default is "
"
     * options {Array} An array of Strings or objects to use as the options when the type is select. Objects need label and value properties.
     * showEmpty {Mixed} Indicates if this DataStructure should be generated when it has no value. Accepts boolean or a function that returns true. The function is passed the id number of the html field.
     */
    info = function(options) {
        return new DataStructure(options);
    };

    // DataStructure Constructor
    DataStructure = function(options) {
        var datum, i;

        datum = $.extend({
            // Default Options
            type:"text",
            disabled: false,
            name:null,
            after:"
",
            options:[],
            showEmpty:true
        }, options);

        // Attach each option to the data structure
        for ( i in datum ) {
            this[i] = datum[i];
        }

        return this;
    };

    // Define the data structure API
    info.fn = DataStructure.prototype = {

        // Data Structure Functions

        /**
         * Takes a data structre and turns into into a set of HTML tags.
         * @parm {String} value The value of the data structure.
         * @parm {String} name The name of the data structure.
         * @parm {int} idNum An ID number to attach to the html tags.
         * @return A jQuery object containing the HTML nodes for the data structure.
         */
        toHTML : function(value, name, idNum) {
            /* Types:
             * - text
             * - date
             * - textarea
             * - select
             * - int
             * - checkbox
             */
            var showEmpty, label, field, id = name + "_" + idNum;

            // See if this field should be shown when empty
            if(typeof(this.showEmpty) === 'function') {
                showEmpty = this.showEmpty(idNum);
            } else {
                showEmpty = this.showEmpty;
            }

            if( ! showEmpty ){
                if(value == null){
                    // Don't show empty fields
                    return "";
                }
            }

            value = this.formatValue(value);

            label = $("").text(this.name).attr("for", id);

            if(this.type == "textarea"){
                // Text area
                field = $("<textarea>").text(value);

            } else if(this.type == "select"){
                // Drop Down
                field = $("<select>")

                var i;
                for(i in this.options){
                    i = this.options[i];
                    if(i.label == null){
                        field.append($("<option>").text(i));
                    } else {
                        field.append($("<option>").attr("value", i.value).text(i.label));
                    }
                }
                field.val(value);

            } else if(this.type == "text" || this.type == "int" || this.type == "date"){
                // Text, date, and int types
                field = $("<input>").attr('type', 'text').val(value);

                if(this.type == "int"){
                    field.addClass("int");
                }

            } else if(this.type == "checkbox"){
                // Checkbox
                field = $("<input>").attr({
                    'type' : 'checkbox'
                });

            } else {
                // Unknown
                console.log("Unkown Type: " + this.type);
                return "";
            }

            // Add common attributes to the field
            field.attr({
                "name": name,
                "id"  : id
            });

            // Attach the date picker to dates
            if( this.disabled ) {
                // Disabled field
                field.prop('disabled', true);

                // Date check part of this if else so that disabled fields don't have the datpicker attached.
            } else if(this.type == "date") {
                field.datepicker({
                   showOn: "both",
                   // TODO get my own calendar icon
                   buttonImage: "http://jqueryui.com/resources/demos/datepicker/images/calendar.gif",
                   buttonImageOnly : true,
                   dateFormat : "yy-mm-dd"
                });
            }

            return label.add(field).add(this.after);
        },

        formatValue : function(value) {
            // Null should be empty strings
            if(value == null)
                return "";

            if(this.type == "date"){
                // Do date formating (change from yy-mm-dd hh:mm:ss to yy-mm-dd)
                value = value.substring(0, value.indexOf(" "));
                return value;
            }

            // No formating needed, return the value
            return value;
        }
    };

    /* ----------------------------- *
     *      DATA STRUCTURES          *
     * ----------------------------- */

    /**
     * Contains the Data Structures for incidents.
     */
    incident = {
        moderator : info({
            name:"Moderator",
            disabled: true
        }),
        created_date : info({
            type:"date",
            disabled: true,
            name:"Created Date",
            after:""
        }),
        incident_date : info({
            type:"date",
            name:"Incident Date"
        }),
        incident_type : info({
            name: "Incident Type"
        }),
        notes : info({
            name: "Notes",
            type: "textarea"
        }),
        action_taken : info({
            type:"textarea",
            name:"Action Taken",
            after:"
Key Location
"
        }),
        world : info({
            name: "World",
            type: "select",
            options:[{
                        value:"",
                        label:""
                    },
                    {
                        value:"world",
                        label:"Alpha"
                    },
                    {
                        value:"world3",
                        label:"Delta"
                    },
                    {
                        value:"world4",
                        label:"Gamma"
                    }],
            after: ""
        }),
        coord_x : info({
            type: "int",
            name: "X",
            after:""
        }),
        coord_y : info({
            type: "int",
            name: "Y",
            after:""
        }),
        coord_z : info({
            type: "int",
            name: "Z"
        }),
        appeal_date : info({
            type    : "date",
            disabled: true,
            name:  "Appeal Date",
            showEmpty:false
        }),
        appeal : info({
            name: "Appeal",
            type: "textarea",
            disabled: true,
            showEmpty:false
        }),
        appeal_response : info({
            type: "textarea",
            name: "Appeal Response",
            showEmpty: function(idNum){
                return $("#appeal_" + idNum).length > 0;
            }
        })
    };

    /* ----------------------------- *
     *          FUNCTIONS            *
     * ----------------------------- */

    /**
     * Opens the add user dialog, and after the new user is saved, adds them to the incident.
     */
    function attachNewUserToIncident() {
        attachNewUser = true;
        $("#user-add-username").val($("#user_name").val());
        openAddUser();
    }

    /**
     * Displays a message to a user in a jQuery UI highlight box.
     * @param {String} message The message to display.
     */
    function displayMessage(message) {
        // Display the message
        $("#highlight-msg").text(message);
        $("#highlight").slideDown();

        // Display for four seconds
        setTimeout(function(){$("#highlight").slideUp();}, 4000);
    }

    /**
     *  Retrieves the user information, and then displays it into the manage
     *  users tab.
     */
    function getInformation() {
        $.get(
            "fsmcbm.php",
            { 'lookup': $("#lookup-user_id").val() },
            function(data){
                if(data.error == null){

                    // Empty out any previous incidents
                    var incidents = $("#incident-info").empty();

                    // Fill in the fields
                    $.each(data.user, function(index, value){
                        var field = $("#user-info-" + index);
                        if(field.attr("type") == "checkbox"){
                            field.prop("checked", value == "1");
                        } else {
                            field.val(value);
                        }
                    });

                    if(data.incident != null){
                        // Attach all the incidents
                        for(var i=0; i<data.incident.length; i++){
                            var datum = data.incident[i];

                            var div = $("
").addClass("form").attr("id", "i-" + datum.id);
                            div.appendTo(incidents);

                            $.each(incident, function(index, value){
                                div.append(value.toHTML(datum[index], index, datum.id));
                            });

                            // Add the save and cancel buttons
                            div.append($("<button>").text("Save").attr("id","i-s-" + datum.id).button().click(function(){
                                // TODO save incident button code here
                                // Get the ID
                                var id = $(this).button("option", "disabled", true).attr('id').substring(4);

                                // Save the fields
                                var datum = {
                                    "id" : id
                                };

                                $.each(incident, function(index, value){
                                    datum[index] = $("#" + index + "_" + id).val();
                                });

                                $.post("fsmcbm.php?update=incident",
                                    datum,
                                    function(data){
                                        // Re-enable the button
                                        $("#i-s-" + id).button("option", "disabled", false);
                                        if(data.error == null){
                                            // Success
                                            displayMessage("Incident updated.");
                                        } else {
                                            // Error occured
                                            handleError(data.error);
                                        }
                                    },
                                    'json');
                            }));
                            div.append($("<button>").text("Cancel").attr("id","i-c-" + datum.id).button().click(function(){
                                // TODO cancel incident save button code here
                            }));
                        }
                    }

                    // Switch to the manage tab
                    $("#tabs").tabs("option", "active", 0);

                } else {
                    // Error
                    handleError(data.error);
                }
            },
            'json'
        );
    }

    /**
     * Handles errors.
     * @param {String} error The error message. Optional.
     */
    function handleError(error) {
        // Log the error message
        console.error(error);

        // Display the error message
        $("#error-msg").text(error);
        $("#error").slideDown();

        // Display for six seconds
        setTimeout(function(){$("#error").slideUp();}, 6000);
    }

    /**
     * Sets up an field to be an jQuery UI AutoComplete enabled field.
     * @param {String} input The jQuery selector to apply the autocomplete to.
     * @param {String} value The jQuery selector for the element to set the
     * autocompletes value to.
     * @param {Function} callback A function to call after the a value has been
     * selected from the autocomplete options. Can be null.
     * @param {String} emptyLabel The option text to display when no results are
     * found.
     * @param {Function} emptyCallback A function to call if the no result option
     * is selected. Can be null.
     */
    function lookup(input, value, callback, emptyLabel, emptyCallback) {
        $(input).autocomplete({
            source : function (request, response) {
                $.get("fsmcbm.php",{
                        term: request.term
                    }, function (data) {
                        if (data.length == 0) {
                            data.push({
                                'value': 0,
                                'label': emptyLabel
                            });
                        }
                        response(data);
                    }, 'json');
            },
            minLength : 2,
            select : function( event, ui ){
                if(ui.item.value == 0){
                    if(emptyCallback != null){
                        emptyCallback();
                    }
                } else {
                    $(this).val(ui.item.label);
                    $(value).val(ui.item.value);

                    if(callback != null){
                        callback();
                    }
                }
                return false;
            }
        });
    }

    /**
     * Opens the add user jQuery UI dialog.
     */
    function openAddUser() {
        $("#dialog-add-user").dialog("open");
    }

    /**
     * Performs a lookup on a user based on which table row was clicked.
     */
    function rowLookup(){
        $("#lookup-user_id").val($(this).attr("id").substring(3));
        getInformation();
    }

    /* ----------------------------- *
     *           INITALIZE           *
     * ----------------------------- */

    // Runs on document ready.
    $( function($) {

        // Set up the tabs
        $("#tabs").tabs({
            beforeLoad: function(event, ui){
                // Set up error handling
                ui.jqXHR.error(function(){
                   ui.panel.html("Couldn't load this tab.");
                });
            },
            load: function(event, ui){
                $(ui.panel).find("tr").click(rowLookup);
            },
            disabled: [3]// Search tab is disabled by default
        });

        // Make buttons jQuery UI buttons
        $("button").button();

        // Set up the dialogs
        $("#dialog-add-user").dialog({
            autoOpen: false,
            modal: true,
            height: 400,
            width: 510,
            buttons: {
                Save : function(){
                    // TODO add verification
                    // Save the user
                    $.post(
                        "fsmcbm.php?add_user=true",
                        $("#add-user-form").serialize(),
                        function(data){
                            if(data.error == null){
                                // Success
                                displayMessage("User added succesfully.");

                                // See if the user needs to be attached to an incident
                                if(attachNewUser){
                                    $("#user_name").val($("#user-add-username").val());
                                    $("#user_id").val(data.user_id);
                                    attachNewUser = false;
                                }

                            } else {
                                // Error occured
                                handleError(data.error);
                            }
                        }, 'json'
                    );

                    $(this).dialog("close");
                },

                Cancel : function(){
                    $(this).dialog("close");
                }
            }
        });
        $("#dialog-add-incident").dialog({
            autoOpen: false,
            modal: true,
            buttons: {
                Save : function(){
                    // TODO add verification
                    // Save the incident.
                    $.post(
                        "fsmcbm.php?add_incident=true",
                        $("#add-incident-form").serialize(),
                        function(data){
                            if(data.error == null){
                                // Success
                                displayMessage("Incident added.");
                            } else {
                                // Error occured
                                handleError(data.error);
                            }
                        }, 'json'
                    );

                    $(this).dialog("close");
                },
                Cancel : function(){
                    $(this).dialog("close");
                }
            }
        });

        // Set up the autocomplete lookup fields
        lookup("#lookup", "#lookup-user_id", getInformation, "No users found");
        lookup("#user_name", "#user_id", null, "Not Found - Add New", attachNewUserToIncident);

        // Attach events \\

        // Add user button
        $("#add-user").click(openAddUser);

        // Add incident button
        $("#add-incident").click(function(){
            $("#dialog-add-incident").dialog("open");
        });

        // Save user information button
        $("#user-info-save").click(function(){

            // Verify that there is a user
            var user_id = $("#lookup-user_id").val();
            if(user_id == null || user_id == ""){
                displayMessage("Please select a user.");
                return;
            }

            // Serialize the user information

            var data = {};

            data.id = user_id;
            data.rank = $("#user-info-rank").val();
            data.banned = $("#user-info-banned").is(":checked");
            data.permanent = $("#user-info-permanent").is(":checked");
            data.relations = $("#user-info-relations").val();
            data.notes = $("#user-info-notes").val();

            // Send in the changes
            $.post("fsmcbm.php?update=user", data, function(data){
                if(data.error == null){
                    displayMessage("User updated.");
                } else {
                    handleError(data.error);
                }
            }, 'json');

        });

        // User information cancel button
        $("#user-info-cancel").click(function(){
            // TODO
        });

        // Search box
        $("#search").change(function(){
            $.get("fsmcbm.php",
                { search : $(this).val() },
                function(data) {
                    // Check for error with the search
                    try {
                        $.parseJSON(data);
                        if(data.error != null){
                            handleError(data.error);
                            return;
                        }
                    // Catch and ignore any errors thrown by parseJSON (since it HTML is returned it will error out).
                    } catch(ignore){}

                    // Set the tab contents
                    $("#search-tab").html(data);

                    // Attach the row lookup event
                    $("#search-tab tr").click(rowLookup)

                    // Re-enable the search tab, and switch to it.
                    $("#tabs").tabs("enable", 3).tabs("option", "active", 3);
                },
                'html'
            );
        });

    });

})(jQuery);<commit_msg>Search is only performed when two or more characters are entered.<commit_after>/* Final Score MC Ban Manager
 *
 */
// TODO add datepicker to incident date field in add incident
// TODO add field verification
(function($){

    // General Variables
    var info,
        DataStructure,
        incident,
        attachNewUser = false;

    /* ----------------------------- *
     *   DATA STRUCTURE OBJECT       *
     * ----------------------------- */

    /**
     * Convenience constructor for a DataStructure.
     * @param {Object} options The options/settings for the DataStructure.
     * Options:
     * type {String} Type of the DataStructure valid type strings: text, date, textarea, select, int, checkbox. Default is text.
     * disabled {boolean} Whether this field should be disabled. Default is false.
     * name {String} The name of the Data Stucture. Used when ouptuing it's form label.
     * after {Mixed} The element to insert after the DataStructure when it is generated. Default is "
"
     * options {Array} An array of Strings or objects to use as the options when the type is select. Objects need label and value properties.
     * showEmpty {Mixed} Indicates if this DataStructure should be generated when it has no value. Accepts boolean or a function that returns true. The function is passed the id number of the html field.
     */
    info = function(options) {
        return new DataStructure(options);
    };

    // DataStructure Constructor
    DataStructure = function(options) {
        var datum, i;

        datum = $.extend({
            // Default Options
            type:"text",
            disabled: false,
            name:null,
            after:"
",
            options:[],
            showEmpty:true
        }, options);

        // Attach each option to the data structure
        for ( i in datum ) {
            this[i] = datum[i];
        }

        return this;
    };

    // Define the data structure API
    info.fn = DataStructure.prototype = {

        // Data Structure Functions

        /**
         * Takes a data structre and turns into into a set of HTML tags.
         * @parm {String} value The value of the data structure.
         * @parm {String} name The name of the data structure.
         * @parm {int} idNum An ID number to attach to the html tags.
         * @return A jQuery object containing the HTML nodes for the data structure.
         */
        toHTML : function(value, name, idNum) {
            /* Types:
             * - text
             * - date
             * - textarea
             * - select
             * - int
             * - checkbox
             */
            var showEmpty, label, field, id = name + "_" + idNum;

            // See if this field should be shown when empty
            if(typeof(this.showEmpty) === 'function') {
                showEmpty = this.showEmpty(idNum);
            } else {
                showEmpty = this.showEmpty;
            }

            if( ! showEmpty ){
                if(value == null){
                    // Don't show empty fields
                    return "";
                }
            }

            value = this.formatValue(value);

            label = $("").text(this.name).attr("for", id);

            if(this.type == "textarea"){
                // Text area
                field = $("<textarea>").text(value);

            } else if(this.type == "select"){
                // Drop Down
                field = $("<select>")

                var i;
                for(i in this.options){
                    i = this.options[i];
                    if(i.label == null){
                        field.append($("<option>").text(i));
                    } else {
                        field.append($("<option>").attr("value", i.value).text(i.label));
                    }
                }
                field.val(value);

            } else if(this.type == "text" || this.type == "int" || this.type == "date"){
                // Text, date, and int types
                field = $("<input>").attr('type', 'text').val(value);

                if(this.type == "int"){
                    field.addClass("int");
                }

            } else if(this.type == "checkbox"){
                // Checkbox
                field = $("<input>").attr({
                    'type' : 'checkbox'
                });

            } else {
                // Unknown
                console.log("Unkown Type: " + this.type);
                return "";
            }

            // Add common attributes to the field
            field.attr({
                "name": name,
                "id"  : id
            });

            // Attach the date picker to dates
            if( this.disabled ) {
                // Disabled field
                field.prop('disabled', true);

                // Date check part of this if else so that disabled fields don't have the datpicker attached.
            } else if(this.type == "date") {
                field.datepicker({
                   showOn: "both",
                   // TODO get my own calendar icon
                   buttonImage: "http://jqueryui.com/resources/demos/datepicker/images/calendar.gif",
                   buttonImageOnly : true,
                   dateFormat : "yy-mm-dd"
                });
            }

            return label.add(field).add(this.after);
        },

        formatValue : function(value) {
            // Null should be empty strings
            if(value == null)
                return "";

            if(this.type == "date"){
                // Do date formating (change from yy-mm-dd hh:mm:ss to yy-mm-dd)
                value = value.substring(0, value.indexOf(" "));
                return value;
            }

            // No formating needed, return the value
            return value;
        }
    };

    /* ----------------------------- *
     *      DATA STRUCTURES          *
     * ----------------------------- */

    /**
     * Contains the Data Structures for incidents.
     */
    incident = {
        moderator : info({
            name:"Moderator",
            disabled: true
        }),
        created_date : info({
            type:"date",
            disabled: true,
            name:"Created Date",
            after:""
        }),
        incident_date : info({
            type:"date",
            name:"Incident Date"
        }),
        incident_type : info({
            name: "Incident Type"
        }),
        notes : info({
            name: "Notes",
            type: "textarea"
        }),
        action_taken : info({
            type:"textarea",
            name:"Action Taken",
            after:"
Key Location
"
        }),
        world : info({
            name: "World",
            type: "select",
            options:[{
                        value:"",
                        label:""
                    },
                    {
                        value:"world",
                        label:"Alpha"
                    },
                    {
                        value:"world3",
                        label:"Delta"
                    },
                    {
                        value:"world4",
                        label:"Gamma"
                    }],
            after: ""
        }),
        coord_x : info({
            type: "int",
            name: "X",
            after:""
        }),
        coord_y : info({
            type: "int",
            name: "Y",
            after:""
        }),
        coord_z : info({
            type: "int",
            name: "Z"
        }),
        appeal_date : info({
            type    : "date",
            disabled: true,
            name:  "Appeal Date",
            showEmpty:false
        }),
        appeal : info({
            name: "Appeal",
            type: "textarea",
            disabled: true,
            showEmpty:false
        }),
        appeal_response : info({
            type: "textarea",
            name: "Appeal Response",
            showEmpty: function(idNum){
                return $("#appeal_" + idNum).length > 0;
            }
        })
    };

    /* ----------------------------- *
     *          FUNCTIONS            *
     * ----------------------------- */

    /**
     * Opens the add user dialog, and after the new user is saved, adds them to the incident.
     */
    function attachNewUserToIncident() {
        attachNewUser = true;
        $("#user-add-username").val($("#user_name").val());
        openAddUser();
    }

    /**
     * Displays a message to a user in a jQuery UI highlight box.
     * @param {String} message The message to display.
     */
    function displayMessage(message) {
        // Display the message
        $("#highlight-msg").text(message);
        $("#highlight").slideDown();

        // Display for four seconds
        setTimeout(function(){$("#highlight").slideUp();}, 4000);
    }

    /**
     *  Retrieves the user information, and then displays it into the manage
     *  users tab.
     */
    function getInformation() {
        $.get(
            "fsmcbm.php",
            { 'lookup': $("#lookup-user_id").val() },
            function(data){
                if(data.error == null){

                    // Empty out any previous incidents
                    var incidents = $("#incident-info").empty();

                    // Fill in the fields
                    $.each(data.user, function(index, value){
                        var field = $("#user-info-" + index);
                        if(field.attr("type") == "checkbox"){
                            field.prop("checked", value == "1");
                        } else {
                            field.val(value);
                        }
                    });

                    if(data.incident != null){
                        // Attach all the incidents
                        for(var i=0; i<data.incident.length; i++){
                            var datum = data.incident[i];

                            var div = $("
").addClass("form").attr("id", "i-" + datum.id);
                            div.appendTo(incidents);

                            $.each(incident, function(index, value){
                                div.append(value.toHTML(datum[index], index, datum.id));
                            });

                            // Add the save and cancel buttons
                            div.append($("<button>").text("Save").attr("id","i-s-" + datum.id).button().click(function(){
                                // TODO save incident button code here
                                // Get the ID
                                var id = $(this).button("option", "disabled", true).attr('id').substring(4);

                                // Save the fields
                                var datum = {
                                    "id" : id
                                };

                                $.each(incident, function(index, value){
                                    datum[index] = $("#" + index + "_" + id).val();
                                });

                                $.post("fsmcbm.php?update=incident",
                                    datum,
                                    function(data){
                                        // Re-enable the button
                                        $("#i-s-" + id).button("option", "disabled", false);
                                        if(data.error == null){
                                            // Success
                                            displayMessage("Incident updated.");
                                        } else {
                                            // Error occured
                                            handleError(data.error);
                                        }
                                    },
                                    'json');
                            }));
                            div.append($("<button>").text("Cancel").attr("id","i-c-" + datum.id).button().click(function(){
                                // TODO cancel incident save button code here
                            }));
                        }
                    }

                    // Switch to the manage tab
                    $("#tabs").tabs("option", "active", 0);

                } else {
                    // Error
                    handleError(data.error);
                }
            },
            'json'
        );
    }

    /**
     * Handles errors.
     * @param {String} error The error message. Optional.
     */
    function handleError(error) {
        // Log the error message
        console.error(error);

        // Display the error message
        $("#error-msg").text(error);
        $("#error").slideDown();

        // Display for six seconds
        setTimeout(function(){$("#error").slideUp();}, 6000);
    }

    /**
     * Sets up an field to be an jQuery UI AutoComplete enabled field.
     * @param {String} input The jQuery selector to apply the autocomplete to.
     * @param {String} value The jQuery selector for the element to set the
     * autocompletes value to.
     * @param {Function} callback A function to call after the a value has been
     * selected from the autocomplete options. Can be null.
     * @param {String} emptyLabel The option text to display when no results are
     * found.
     * @param {Function} emptyCallback A function to call if the no result option
     * is selected. Can be null.
     */
    function lookup(input, value, callback, emptyLabel, emptyCallback) {
        $(input).autocomplete({
            source : function (request, response) {
                $.get("fsmcbm.php",{
                        term: request.term
                    }, function (data) {
                        if (data.length == 0) {
                            data.push({
                                'value': 0,
                                'label': emptyLabel
                            });
                        }
                        response(data);
                    }, 'json');
            },
            minLength : 2,
            select : function( event, ui ){
                if(ui.item.value == 0){
                    if(emptyCallback != null){
                        emptyCallback();
                    }
                } else {
                    $(this).val(ui.item.label);
                    $(value).val(ui.item.value);

                    if(callback != null){
                        callback();
                    }
                }
                return false;
            }
        });
    }

    /**
     * Opens the add user jQuery UI dialog.
     */
    function openAddUser() {
        $("#dialog-add-user").dialog("open");
    }

    /**
     * Performs a lookup on a user based on which table row was clicked.
     */
    function rowLookup(){
        $("#lookup-user_id").val($(this).attr("id").substring(3));
        getInformation();
    }

    /* ----------------------------- *
     *           INITALIZE           *
     * ----------------------------- */

    // Runs on document ready.
    $( function($) {

        // Set up the tabs
        $("#tabs").tabs({
            beforeLoad: function(event, ui){
                // Set up error handling
                ui.jqXHR.error(function(){
                   ui.panel.html("Couldn't load this tab.");
                });
            },
            load: function(event, ui){
                $(ui.panel).find("tr").click(rowLookup);
            },
            disabled: [3]// Search tab is disabled by default
        });

        // Make buttons jQuery UI buttons
        $("button").button();

        // Set up the dialogs
        $("#dialog-add-user").dialog({
            autoOpen: false,
            modal: true,
            height: 400,
            width: 510,
            buttons: {
                Save : function(){
                    // TODO add verification
                    // Save the user
                    $.post(
                        "fsmcbm.php?add_user=true",
                        $("#add-user-form").serialize(),
                        function(data){
                            if(data.error == null){
                                // Success
                                displayMessage("User added succesfully.");

                                // See if the user needs to be attached to an incident
                                if(attachNewUser){
                                    $("#user_name").val($("#user-add-username").val());
                                    $("#user_id").val(data.user_id);
                                    attachNewUser = false;
                                }

                            } else {
                                // Error occured
                                handleError(data.error);
                            }
                        }, 'json'
                    );

                    $(this).dialog("close");
                },

                Cancel : function(){
                    $(this).dialog("close");
                }
            }
        });
        $("#dialog-add-incident").dialog({
            autoOpen: false,
            modal: true,
            buttons: {
                Save : function(){
                    // TODO add verification
                    // Save the incident.
                    $.post(
                        "fsmcbm.php?add_incident=true",
                        $("#add-incident-form").serialize(),
                        function(data){
                            if(data.error == null){
                                // Success
                                displayMessage("Incident added.");
                            } else {
                                // Error occured
                                handleError(data.error);
                            }
                        }, 'json'
                    );

                    $(this).dialog("close");
                },
                Cancel : function(){
                    $(this).dialog("close");
                }
            }
        });

        // Set up the autocomplete lookup fields
        lookup("#lookup", "#lookup-user_id", getInformation, "No users found");
        lookup("#user_name", "#user_id", null, "Not Found - Add New", attachNewUserToIncident);

        // Attach events \\

        // Add user button
        $("#add-user").click(openAddUser);

        // Add incident button
        $("#add-incident").click(function(){
            $("#dialog-add-incident").dialog("open");
        });

        // Save user information button
        $("#user-info-save").click(function(){

            // Verify that there is a user
            var user_id = $("#lookup-user_id").val();
            if(user_id == null || user_id == ""){
                displayMessage("Please select a user.");
                return;
            }

            // Serialize the user information

            var data = {};

            data.id = user_id;
            data.rank = $("#user-info-rank").val();
            data.banned = $("#user-info-banned").is(":checked");
            data.permanent = $("#user-info-permanent").is(":checked");
            data.relations = $("#user-info-relations").val();
            data.notes = $("#user-info-notes").val();

            // Send in the changes
            $.post("fsmcbm.php?update=user", data, function(data){
                if(data.error == null){
                    displayMessage("User updated.");
                } else {
                    handleError(data.error);
                }
            }, 'json');

        });

        // User information cancel button
        $("#user-info-cancel").click(function(){
            // TODO
        });

        // Search box
        $("#search").change(function(){// TODO change from the onChange event (only trigger when enter is pressed)
            if( $(this).val().length < 2) {

                displayMessage("Search must be two or more characters long.");

            } else {
                $.get("fsmcbm.php",
                    { search : $(this).val() },
                    function(data) {
                        // Check for error with the search
                        try {
                            $.parseJSON(data);
                            if(data.error != null){
                                handleError(data.error);
                                return;
                            }
                        // Catch and ignore any errors thrown by parseJSON (since it HTML is returned it will error out).
                        } catch(ignore){}

                        // Set the tab contents
                        $("#search-tab").html(data);

                        // Attach the row lookup event
                        $("#search-tab tr").click(rowLookup)

                        // Re-enable the search tab, and switch to it.
                        $("#tabs").tabs("enable", 3).tabs("option", "active", 3);
                    },
                    'html' );
            }
        });

    });

})(jQuery);<|endoftext|>