<commit_before>import React from 'react';
import Portal from 'react-portal';

export default class Modal extends React.Component {
  // add the modal-open class to the body of the page so scrollbars render properly.
  componentWillMount() {
    document.body.classList.add('modal-open');
  }

  // remove the modal-open class
  componentWillUnmount() {
    document.body.classList.remove('modal-open');
  }

  render() {
    return (
      <Portal isOpened>

            <div className={`modal-dialog ${this.props.dialogClasses}`}>

                {this.props.children}

      </Portal>
    );
  }
}

Modal.propTypes = {
  children: React.PropTypes.node,
  dialogClasses: React.PropTypes.string.isRequired,
  show: React.PropTypes.bool.isRequired
};

Modal.defaultProps = {
  dialogClasses: '',
  show: true
};
<commit_msg>Fix overflow scrolling<commit_after>import React from 'react';
import Portal from 'react-portal';

export default class Modal extends React.Component {
  render() {
    return (
      <Portal isOpened={this.props.show}>
        <PortedModal {...this.props} />
      </Portal>
    );
  }
}
Modal.propTypes = {
  show: React.PropTypes.bool.isRequired
};

Modal.defaultProps = {
  show: true
};

// This component is intended for internal use of Modal Component
// It is used to mount Modal only when it should be shown
class PortedModal extends React.Component {
  // add the modal-open class to the body of the page so scrollbars render properly.
  componentWillMount() {
    document.body.classList.add('modal-open');
  }

  // remove the modal-open class
  componentWillUnmount() {
    document.body.classList.remove('modal-open');
  }

  render() {
    return (

          <div className={`modal-dialog ${this.props.dialogClasses}`}>

              {this.props.children}

    );
  }
}
PortedModal.propTypes = {
  children: React.PropTypes.node,
  dialogClasses: React.PropTypes.string.isRequired
};

PortedModal.defaultProps = {
  dialogClasses: ''
};
<|endoftext|>


<commit_before>var x
var y
var width
var height
var drops = []

function setup() {
	createCanvas(windowWidth, windowHeight)
	x = windowWidth / 2
	y = windowHeight / 2
	width = 10
	height = 10
	for (var i = 0; i < 100; i++) {
		drops.push(new Drop());
	}
	// ball = new Ball()
	// ball1 = new Ball()
}

function draw() {
	background('white')
		// ellipse(x, y, width, height)
		// ellipse(y,x,width,height)
		// ellipse(x,x,width,height)
		// ball.display()
		// ball.move()
		// ball1.display()
		// ball1.move()
	textSize(64)
	text("☂", mouseX - 30, mouseY)
	for (var i = 0; i < drops.length; i++) {
		drops[i].move();
		drops[i].display();
	}
	print(drops)
		// this.speed = this.speed * 9.81
}

function Drop() {
	this.x = random(0, windowWidth);
	this.y = random(0, windowHeight);

	this.speed = 20;

	this.move = function() {
		// this.x += random(-this.speed, this.speed);
		// this.y += random(-this.speed, this.speed);

		if (this.y > 0) {
			this.y = this.y - 1 * this.speed
			this.x = this.x + random(-3, 3)

		} else {
			this.y = windowHeight

		}
	};

	this.display = function() {
		textSize(32)
		text("🕷", this.x, this.y)
	};
}<commit_msg>no umbrella<commit_after>var x
var y
var width
var height
var drops = []

function setup() {
	createCanvas(windowWidth, windowHeight)
	x = windowWidth / 2
	y = windowHeight / 2
	width = 10
	height = 10
	for (var i = 0; i < 100; i++) {
		drops.push(new Drop());
	}
	// ball = new Ball()
	// ball1 = new Ball()
}

function draw() {
	background('white')
		// ellipse(x, y, width, height)
		// ellipse(y,x,width,height)
		// ellipse(x,x,width,height)
		// ball.display()
		// ball.move()
		// ball1.display()
		// ball1.move()
	textSize(64)
// 	text("☂", mouseX - 30, mouseY)
	for (var i = 0; i < drops.length; i++) {
		drops[i].move();
		drops[i].display();
	}
	print(drops)
		// this.speed = this.speed * 9.81
}

function Drop() {
	this.x = random(0, windowWidth);
	this.y = random(0, windowHeight);

	this.speed = 20;

	this.move = function() {
		// this.x += random(-this.speed, this.speed);
		// this.y += random(-this.speed, this.speed);

		if (this.y > 0) {
			this.y = this.y - 1 * this.speed
			this.x = this.x + random(-3, 3)

		} else {
			this.y = windowHeight

		}
	};

	this.display = function() {
		textSize(32)
		text("🕷", this.x, this.y)
	};
}<|endoftext|>


<commit_before>/**
 * App constants
 */

export default {
	CHANGE_EVENT: 		'CHANGE_EVENT',
	SWITCH_VIEW:		'SWITCH_VIEW',
	GET_CONFIGURATION: 	'GET_CONFIGURATION',
	SAVE_CONFIGURATION:	'SAVE_CONFIGURATION',
	ADD_FIELD: 			'ADD_FIELD',
	REMOVE_FIELD:		'REMOVE_FIELD',
	ADD_INPUT_VALUE:	'ADD_INPUT_VALUE'
}
<commit_msg>Update constants<commit_after>/**
 * App constants
 */

export default {
	CHANGE_EVENT: 			'CHANGE_EVENT',
	SWITCH_VIEW:			'SWITCH_VIEW',
	GET_CONFIGURATION: 		'GET_CONFIGURATION',
	SAVE_CONFIGURATION:		'SAVE_CONFIGURATION',
	ADD_FIELD: 				'ADD_FIELD',
	REMOVE_FIELD:			'REMOVE_FIELD',
	ADD_INPUT_VALUE:		'ADD_INPUT_VALUE',
	SET_ENABLE:				'SET_ENABLE',
	SET_AUTO_UPDATE:		'SET_AUTO_UPDATE',
	SET_UPDATE_FREQUENCY:	'SET_UPDATE_FREQUENCY'
}
<|endoftext|>


<commit_before>'use strict';

angular.module('copayApp.controllers').controller('confirmController', function($rootScope, $scope, $interval, $filter, $timeout, $ionicScrollDelegate, gettextCatalog, walletService, platformInfo, lodash, configService, rateService, $stateParams, $window, $state, $log, profileService, bitcore, gettext, txFormatService, ongoingProcess, $ionicModal, popupService, $ionicHistory, $ionicConfig) {
  var cachedTxp = {};
  var isChromeApp = platformInfo.isChromeApp;
  var countDown = null;
  $ionicConfig.views.swipeBackEnabled(false);

  $scope.$on("$ionicView.beforeEnter", function(event, data) {
    $scope.isWallet = data.stateParams.isWallet;
    $scope.cardId = data.stateParams.cardId;
    $scope.toAmount = data.stateParams.toAmount;
    $scope.toAddress = data.stateParams.toAddress;
    $scope.toName = data.stateParams.toName;
    $scope.toEmail = data.stateParams.toEmail;
    $scope.description = data.stateParams.description;
    $scope.paypro = data.stateParams.paypro;
    $scope._paypro = $scope.paypro;
    $scope.paymentExpired = {
      value: false
    };
    $scope.remainingTimeStr = {
      value: null
    };
    initConfirm();
  });

  var initConfirm = function() {
    // TODO (URL , etc)
    if (!$scope.toAddress || !$scope.toAmount) {
      $log.error('Bad params at amount');
      throw ('bad params');
    }
    $scope.isCordova = platformInfo.isCordova;
    $scope.hasClick = platformInfo.hasClick;
    $scope.data = {};

    var config = configService.getSync().wallet;
    $scope.feeLevel = config.settings && config.settings.feeLevel ? config.settings.feeLevel : 'normal';

    $scope.toAmount = parseInt($scope.toAmount);
    $scope.amountStr = txFormatService.formatAmountStr($scope.toAmount);
    $scope.displayAmount = getDisplayAmount($scope.amountStr);
    $scope.displayUnit = getDisplayUnit($scope.amountStr);

    var networkName = (new bitcore.Address($scope.toAddress)).network.name;
    $scope.network = networkName;

    $scope.insuffientFunds = false;
    $scope.noMatchingWallet = false;

    var wallets = profileService.getWallets({
      onlyComplete: true,
      network: networkName,
    });

    if (!wallets || !wallets.length) {
      $scope.noMatchingWallet = true;
    }

    var filteredWallets = [];
    var index = 0;
    var enoughFunds = false;

    lodash.each(wallets, function(w) {
      walletService.getStatus(w, {}, function(err, status) {
        if (err || !status) {
          $log.error(err);
        } else {
          w.status = status;
          if (!status.availableBalanceSat) $log.debug('No balance available in: ' + w.name);
          if (status.availableBalanceSat > $scope.toAmount) {
            filteredWallets.push(w);
            enoughFunds = true;
          }
        }

        if (++index == wallets.length) {
          if (!lodash.isEmpty(filteredWallets)) {
            $scope.wallets = lodash.clone(filteredWallets);
            setWallet($scope.wallets[0]);
          } else {

            if (!enoughFunds)
              $scope.insuffientFunds = true;

            $log.warn('No wallet available to make the payment');
          }
        }
      });
    });

    txFormatService.formatAlternativeStr($scope.toAmount, function(v) {
      $scope.alternativeAmountStr = v;
    });

    if($scope.paypro) {
      console.log('$scope.paypro', $scope.paypro);
      _paymentTimeControl($scope.paypro.expires);
    }

    $timeout(function() {
      $scope.$apply();
    }, 100);
  };

  $scope.$on('accepted', function(event) {
    $scope.approve();
  });

  $scope.$on('Wallet/Changed', function(event, wallet) {
    if (lodash.isEmpty(wallet)) {
      $log.debug('No wallet provided');
      return;
    }
    $log.debug('Wallet changed: ' + wallet.name);
    setWallet(wallet, true);
  });

  $scope.showWalletSelector = function() {
    $scope.showWallets = true;
  };

  $scope.onWalletSelect = function(wallet) {
    setWallet(wallet);
  };

  $scope.showDescriptionPopup = function() {
    var message = gettextCatalog.getString('Add description');
    var opts = {
      defaultText: $scope.description
    };

    popupService.showPrompt(null, message, opts, function(res) {
      if (typeof res != 'undefined') $scope.description = res;
      $timeout(function() {
        $scope.$apply();
      }, 100);
    });
  };

  function getDisplayAmount(amountStr) {
    return amountStr.split(' ')[0];
  }

  function getDisplayUnit(amountStr) {
    return amountStr.split(' ')[1];
  }

// <<<<<<< HEAD
// =======
  // var setFromPayPro = function(uri, cb) {
  //   if (!cb) cb = function() {};
  //
  //   var wallet = profileService.getWallets({
  //     onlyComplete: true
  //   })[0];
  //
  //   if (!wallet) return cb();
  //
  //   if (isChromeApp) {
  //     popupService.showAlert(gettextCatalog.getString('Payment Protocol not supported on Chrome App'));
  //     return cb(true);
  //   }
  //
  //   $log.debug('Fetch PayPro Request...', uri);
  //
  //   ongoingProcess.set('fetchingPayPro', true);
  //   wallet.fetchPayPro({
  //     payProUrl: uri,
  //   }, function(err, paypro) {
  //
  //     ongoingProcess.set('fetchingPayPro', false);
  //
  //     if (err) {
  //       $log.warn('Could not fetch payment request:', err);
  //       var msg = err.toString();
  //       if (msg.match('HTTP')) {
  //         msg = gettextCatalog.getString('Could not fetch payment information');
  //       }
  //       popupService.showAlert(msg);
  //       return cb(true);
  //     }
  //
  //     if (!paypro.verified) {
  //       $log.warn('Failed to verify payment protocol signatures');
  //       popupService.showAlert(gettextCatalog.getString('Payment Protocol Invalid'));
  //       return cb(true);
  //     }
  //
  //     $scope.toAmount = paypro.amount;
  //     $scope.toAddress = paypro.toAddress;
  //     $scope.description = paypro.memo;
  //     $scope.paypro = null;
  //
  //     $scope._paypro = paypro;
  //     _paymentTimeControl(paypro.expires);
  //     return initConfirm();
  //   });
  // };

  function _paymentTimeControl(expirationTime) {
    console.log('expirationTime', expirationTime);
    $scope.paymentExpired.value = false;
    setExpirationTime();

    countDown = $interval(function() {
      setExpirationTime();
    }, 1000);

    function setExpirationTime() {
      var now = Math.floor(Date.now() / 1000);

      if (now > expirationTime) {
        setExpiredValues();
        return;
      }

      var totalSecs = expirationTime - now;
      var m = Math.floor(totalSecs / 60);
      var s = totalSecs % 60;
      $scope.remainingTimeStr.value = ('0' + m).slice(-2) + ":" + ('0' + s).slice(-2);
    }

    function setExpiredValues() {
      $scope.paymentExpired.value = true;
      $scope.remainingTimeStr.value = gettextCatalog.getString('Expired');
      if (countDown) $interval.cancel(countDown);
      $timeout(function() {
        $scope.$apply();
      });
    }
  }

// >>>>>>> de248d56393535b819d879d38692af68c9e6e4da
  function setWallet(wallet, delayed) {
    var stop;
    $scope.wallet = wallet;
    $scope.fee = $scope.txp = null;

    $timeout(function() {
      $ionicScrollDelegate.resize();
      $scope.$apply();
    }, 10);

    if (stop) {
      $timeout.cancel(stop);
      stop = null;
    }

    if (cachedTxp[wallet.id]) {
      apply(cachedTxp[wallet.id]);
    } else {
      stop = $timeout(function() {
        createTx(wallet, true, function(err, txp) {
          if (err) return;
          cachedTxp[wallet.id] = txp;
          apply(txp);
        });
      }, delayed ? 2000 : 1);
    }
  }

  var setSendError = function(msg) {
    $scope.sendStatus = '';
    $timeout(function() {
      $scope.$apply();
    });
    popupService.showAlert(gettextCatalog.getString('Error at confirm:'), msg);
  };

  function apply(txp) {
    $scope.fee = txFormatService.formatAmountStr(txp.fee);
    $scope.txp = txp;
    $scope.$apply();
  }

  var createTx = function(wallet, dryRun, cb) {
    var config = configService.getSync().wallet;
    var currentSpendUnconfirmed = config.spendUnconfirmed;
    var outputs = [];

    var paypro = $scope.paypro;
    var toAddress = $scope.toAddress;
    var toAmount = $scope.toAmount;
    var description = $scope.description;

    // ToDo: use a credential's (or fc's) function for this
    if (description && !wallet.credentials.sharedEncryptingKey) {
      var msg = 'Could not add message to imported wallet without shared encrypting key';
      $log.warn(msg);
      return setSendError(msg);
    }

    if (toAmount > Number.MAX_SAFE_INTEGER) {
      var msg = 'Amount too big';
      $log.warn(msg);
      return setSendError(msg);
    }

    outputs.push({
      'toAddress': toAddress,
      'amount': toAmount,
      'message': description
    });

    var txp = {};

    // TODO
    if (!lodash.isEmpty($scope.sendMaxInfo)) {
      txp.sendMax = true;
      txp.inputs = $scope.sendMaxInfo.inputs;
      txp.fee = $scope.sendMaxInfo.fee;
    }

    txp.outputs = outputs;
    txp.message = description;
    txp.payProUrl = paypro.url;
    txp.excludeUnconfirmedUtxos = config.spendUnconfirmed ? false : true;
    txp.feeLevel = config.settings && config.settings.feeLevel ? config.settings.feeLevel : 'normal';
    txp.dryRun = dryRun;

    walletService.createTx(wallet, txp, function(err, ctxp) {
      if (err) {
        console.log('in createTx error', err);
        setSendError(err);
        return cb(err);
      }
      return cb(null, ctxp);
    });
  };

  $scope.openPPModal = function() {
    $ionicModal.fromTemplateUrl('views/modals/paypro.html', {
      scope: $scope
    }).then(function(modal) {
      $scope.payproModal = modal;
      $scope.payproModal.show();
    });
  };

  $scope.approve = function(onSendStatusChange) {
    console.log('$scope._paypro', $scope._paypro);
    console.log('$scope.paymentExpired', $scope.paymentExpired);
    if ($scope._paypro && $scope.paymentExpired.value) {
      popupService.showAlert(null, gettextCatalog.getString('The payment request has expired'));
      $scope.sendStatus = '';
      $timeout(function() {
        $scope.$apply();
      });
      return;
    }

    var wallet = $scope.wallet;
    if (!wallet) {
      return setSendError(gettextCatalog.getString('No wallet selected'));
    };

    if (!wallet.canSign() && !wallet.isPrivKeyExternal()) {
      $log.info('No signing proposal: No private key');

      return walletService.onlyPublish(wallet, txp, function(err, txp) {
        if (err) return setSendError(err);
      });
    }

    ongoingProcess.set('creatingTx', true, onSendStatusChange);
    createTx(wallet, false, function(err, txp) {
      ongoingProcess.set('creatingTx', false, onSendStatusChange);
      if (err) return;

      var config = configService.getSync();
      var spendingPassEnabled = walletService.isEncrypted(wallet);
      var touchIdEnabled = config.touchIdFor && config.touchIdFor[wallet.id];
      var isCordova = $scope.isCordova;
      var bigAmount = parseFloat(txFormatService.formatToUSD(txp.amount)) > 20;
      var message = gettextCatalog.getString('Sending {{amountStr}} from your {{name}} wallet', {
        amountStr: $scope.amountStr,
        name: wallet.name
      });
      var okText = gettextCatalog.getString('Confirm');
      var cancelText = gettextCatalog.getString('Cancel');

      if (!spendingPassEnabled && !touchIdEnabled) {
        if (isCordova) {
          if (bigAmount) {
            popupService.showConfirm(null, message, okText, cancelText, function(ok) {
              if (!ok) {
                $scope.sendStatus = '';
                $timeout(function() {
                  $scope.$apply();
                });
                return;
              }
              publishAndSign(wallet, txp, onSendStatusChange);
            });
          } else publishAndSign(wallet, txp, onSendStatusChange);
        } else {
          popupService.showConfirm(null, message, okText, cancelText, function(ok) {
            if (!ok) {
              $scope.sendStatus = '';
              return;
            }
            publishAndSign(wallet, txp, onSendStatusChange);
          });
        }
      } else publishAndSign(wallet, txp, onSendStatusChange);
    });
  };

  function statusChangeHandler(processName, showName, isOn) {
    $log.debug('statusChangeHandler: ', processName, showName, isOn);
    if ((processName === 'broadcastingTx' || ((processName === 'signingTx') && $scope.wallet.m > 1)) && !isOn) {
      $scope.sendStatus = 'success';
      $scope.$digest();
    } else if (showName) {
      $scope.sendStatus = showName;
    }
  }

  $scope.statusChangeHandler = statusChangeHandler;

  $scope.onConfirm = function() {
    $scope.approve(statusChangeHandler);
  };

  $scope.onSuccessConfirm = function() {
    var previousView = $ionicHistory.viewHistory().backView && $ionicHistory.viewHistory().backView.stateName;
    var fromBitPayCard = previousView.match(/tabs.bitpayCard/) ? true : false;

    $ionicHistory.nextViewOptions({
      disableAnimate: true
    });
    $ionicHistory.removeBackView();
    $scope.sendStatus = '';

    if (fromBitPayCard) {
      $timeout(function() {
        $state.transitionTo('tabs.bitpayCard', {
          id: $stateParams.cardId
        });
      }, 100);
    } else {
      $state.go('tabs.send');
    }
  };

  function publishAndSign(wallet, txp, onSendStatusChange) {
    walletService.publishAndSign(wallet, txp, function(err, txp) {
      if (err) return setSendError(err);
    }, onSendStatusChange);
  }
});
<commit_msg>cleanup<commit_after>'use strict';

angular.module('copayApp.controllers').controller('confirmController', function($rootScope, $scope, $interval, $filter, $timeout, $ionicScrollDelegate, gettextCatalog, walletService, platformInfo, lodash, configService, rateService, $stateParams, $window, $state, $log, profileService, bitcore, gettext, txFormatService, ongoingProcess, $ionicModal, popupService, $ionicHistory, $ionicConfig) {
  var cachedTxp = {};
  var isChromeApp = platformInfo.isChromeApp;
  var countDown = null;
  $ionicConfig.views.swipeBackEnabled(false);

  $scope.$on("$ionicView.beforeEnter", function(event, data) {
    $scope.isWallet = data.stateParams.isWallet;
    $scope.cardId = data.stateParams.cardId;
    $scope.toAmount = data.stateParams.toAmount;
    $scope.toAddress = data.stateParams.toAddress;
    $scope.toName = data.stateParams.toName;
    $scope.toEmail = data.stateParams.toEmail;
    $scope.description = data.stateParams.description;
    $scope.paypro = data.stateParams.paypro;
    $scope._paypro = $scope.paypro;
    $scope.paymentExpired = {
      value: false
    };
    $scope.remainingTimeStr = {
      value: null
    };
    initConfirm();
  });

  var initConfirm = function() {
    // TODO (URL , etc)
    if (!$scope.toAddress || !$scope.toAmount) {
      $log.error('Bad params at amount');
      throw ('bad params');
    }
    $scope.isCordova = platformInfo.isCordova;
    $scope.hasClick = platformInfo.hasClick;
    $scope.data = {};

    var config = configService.getSync().wallet;
    $scope.feeLevel = config.settings && config.settings.feeLevel ? config.settings.feeLevel : 'normal';

    $scope.toAmount = parseInt($scope.toAmount);
    $scope.amountStr = txFormatService.formatAmountStr($scope.toAmount);
    $scope.displayAmount = getDisplayAmount($scope.amountStr);
    $scope.displayUnit = getDisplayUnit($scope.amountStr);

    var networkName = (new bitcore.Address($scope.toAddress)).network.name;
    $scope.network = networkName;

    $scope.insuffientFunds = false;
    $scope.noMatchingWallet = false;

    var wallets = profileService.getWallets({
      onlyComplete: true,
      network: networkName,
    });

    if (!wallets || !wallets.length) {
      $scope.noMatchingWallet = true;
    }

    var filteredWallets = [];
    var index = 0;
    var enoughFunds = false;

    lodash.each(wallets, function(w) {
      walletService.getStatus(w, {}, function(err, status) {
        if (err || !status) {
          $log.error(err);
        } else {
          w.status = status;
          if (!status.availableBalanceSat) $log.debug('No balance available in: ' + w.name);
          if (status.availableBalanceSat > $scope.toAmount) {
            filteredWallets.push(w);
            enoughFunds = true;
          }
        }

        if (++index == wallets.length) {
          if (!lodash.isEmpty(filteredWallets)) {
            $scope.wallets = lodash.clone(filteredWallets);
            setWallet($scope.wallets[0]);
          } else {

            if (!enoughFunds)
              $scope.insuffientFunds = true;

            $log.warn('No wallet available to make the payment');
          }
        }
      });
    });

    txFormatService.formatAlternativeStr($scope.toAmount, function(v) {
      $scope.alternativeAmountStr = v;
    });

    if($scope.paypro) {
      _paymentTimeControl($scope.paypro.expires);
    }

    $timeout(function() {
      $scope.$apply();
    }, 100);
  };

  $scope.$on('accepted', function(event) {
    $scope.approve();
  });

  $scope.$on('Wallet/Changed', function(event, wallet) {
    if (lodash.isEmpty(wallet)) {
      $log.debug('No wallet provided');
      return;
    }
    $log.debug('Wallet changed: ' + wallet.name);
    setWallet(wallet, true);
  });

  $scope.showWalletSelector = function() {
    $scope.showWallets = true;
  };

  $scope.onWalletSelect = function(wallet) {
    setWallet(wallet);
  };

  $scope.showDescriptionPopup = function() {
    var message = gettextCatalog.getString('Add description');
    var opts = {
      defaultText: $scope.description
    };

    popupService.showPrompt(null, message, opts, function(res) {
      if (typeof res != 'undefined') $scope.description = res;
      $timeout(function() {
        $scope.$apply();
      }, 100);
    });
  };

  function getDisplayAmount(amountStr) {
    return amountStr.split(' ')[0];
  }

  function getDisplayUnit(amountStr) {
    return amountStr.split(' ')[1];
  }

  function _paymentTimeControl(expirationTime) {
    $scope.paymentExpired.value = false;
    setExpirationTime();

    countDown = $interval(function() {
      setExpirationTime();
    }, 1000);

    function setExpirationTime() {
      var now = Math.floor(Date.now() / 1000);

      if (now > expirationTime) {
        setExpiredValues();
        return;
      }

      var totalSecs = expirationTime - now;
      var m = Math.floor(totalSecs / 60);
      var s = totalSecs % 60;
      $scope.remainingTimeStr.value = ('0' + m).slice(-2) + ":" + ('0' + s).slice(-2);
    }

    function setExpiredValues() {
      $scope.paymentExpired.value = true;
      $scope.remainingTimeStr.value = gettextCatalog.getString('Expired');
      if (countDown) $interval.cancel(countDown);
      $timeout(function() {
        $scope.$apply();
      });
    }
  }

  function setWallet(wallet, delayed) {
    var stop;
    $scope.wallet = wallet;
    $scope.fee = $scope.txp = null;

    $timeout(function() {
      $ionicScrollDelegate.resize();
      $scope.$apply();
    }, 10);

    if (stop) {
      $timeout.cancel(stop);
      stop = null;
    }

    if (cachedTxp[wallet.id]) {
      apply(cachedTxp[wallet.id]);
    } else {
      stop = $timeout(function() {
        createTx(wallet, true, function(err, txp) {
          if (err) return;
          cachedTxp[wallet.id] = txp;
          apply(txp);
        });
      }, delayed ? 2000 : 1);
    }
  }

  var setSendError = function(msg) {
    $scope.sendStatus = '';
    $timeout(function() {
      $scope.$apply();
    });
    popupService.showAlert(gettextCatalog.getString('Error at confirm:'), msg);
  };

  function apply(txp) {
    $scope.fee = txFormatService.formatAmountStr(txp.fee);
    $scope.txp = txp;
    $scope.$apply();
  }

  var createTx = function(wallet, dryRun, cb) {
    var config = configService.getSync().wallet;
    var currentSpendUnconfirmed = config.spendUnconfirmed;
    var outputs = [];

    var paypro = $scope.paypro;
    var toAddress = $scope.toAddress;
    var toAmount = $scope.toAmount;
    var description = $scope.description;

    // ToDo: use a credential's (or fc's) function for this
    if (description && !wallet.credentials.sharedEncryptingKey) {
      var msg = 'Could not add message to imported wallet without shared encrypting key';
      $log.warn(msg);
      return setSendError(msg);
    }

    if (toAmount > Number.MAX_SAFE_INTEGER) {
      var msg = 'Amount too big';
      $log.warn(msg);
      return setSendError(msg);
    }

    outputs.push({
      'toAddress': toAddress,
      'amount': toAmount,
      'message': description
    });

    var txp = {};

    // TODO
    if (!lodash.isEmpty($scope.sendMaxInfo)) {
      txp.sendMax = true;
      txp.inputs = $scope.sendMaxInfo.inputs;
      txp.fee = $scope.sendMaxInfo.fee;
    }

    txp.outputs = outputs;
    txp.message = description;
    txp.payProUrl = paypro.url;
    txp.excludeUnconfirmedUtxos = config.spendUnconfirmed ? false : true;
    txp.feeLevel = config.settings && config.settings.feeLevel ? config.settings.feeLevel : 'normal';
    txp.dryRun = dryRun;

    walletService.createTx(wallet, txp, function(err, ctxp) {
      if (err) {
        setSendError(err);
        return cb(err);
      }
      return cb(null, ctxp);
    });
  };

  $scope.openPPModal = function() {
    $ionicModal.fromTemplateUrl('views/modals/paypro.html', {
      scope: $scope
    }).then(function(modal) {
      $scope.payproModal = modal;
      $scope.payproModal.show();
    });
  };

  $scope.approve = function(onSendStatusChange) {
    if ($scope._paypro && $scope.paymentExpired.value) {
      popupService.showAlert(null, gettextCatalog.getString('The payment request has expired'));
      $scope.sendStatus = '';
      $timeout(function() {
        $scope.$apply();
      });
      return;
    }

    var wallet = $scope.wallet;
    if (!wallet) {
      return setSendError(gettextCatalog.getString('No wallet selected'));
    }

    if (!wallet.canSign() && !wallet.isPrivKeyExternal()) {
      $log.info('No signing proposal: No private key');

      return walletService.onlyPublish(wallet, txp, function(err, txp) {
        if (err) return setSendError(err);
      });
    }

    ongoingProcess.set('creatingTx', true, onSendStatusChange);
    createTx(wallet, false, function(err, txp) {
      ongoingProcess.set('creatingTx', false, onSendStatusChange);
      if (err) return;

      var config = configService.getSync();
      var spendingPassEnabled = walletService.isEncrypted(wallet);
      var touchIdEnabled = config.touchIdFor && config.touchIdFor[wallet.id];
      var isCordova = $scope.isCordova;
      var bigAmount = parseFloat(txFormatService.formatToUSD(txp.amount)) > 20;
      var message = gettextCatalog.getString('Sending {{amountStr}} from your {{name}} wallet', {
        amountStr: $scope.amountStr,
        name: wallet.name
      });
      var okText = gettextCatalog.getString('Confirm');
      var cancelText = gettextCatalog.getString('Cancel');

      if (!spendingPassEnabled && !touchIdEnabled) {
        if (isCordova) {
          if (bigAmount) {
            popupService.showConfirm(null, message, okText, cancelText, function(ok) {
              if (!ok) {
                $scope.sendStatus = '';
                $timeout(function() {
                  $scope.$apply();
                });
                return;
              }
              publishAndSign(wallet, txp, onSendStatusChange);
            });
          } else publishAndSign(wallet, txp, onSendStatusChange);
        } else {
          popupService.showConfirm(null, message, okText, cancelText, function(ok) {
            if (!ok) {
              $scope.sendStatus = '';
              return;
            }
            publishAndSign(wallet, txp, onSendStatusChange);
          });
        }
      } else publishAndSign(wallet, txp, onSendStatusChange);
    });
  };

  function statusChangeHandler(processName, showName, isOn) {
    $log.debug('statusChangeHandler: ', processName, showName, isOn);
    if ((processName === 'broadcastingTx' || ((processName === 'signingTx') && $scope.wallet.m > 1)) && !isOn) {
      $scope.sendStatus = 'success';
      $scope.$digest();
    } else if (showName) {
      $scope.sendStatus = showName;
    }
  }

  $scope.statusChangeHandler = statusChangeHandler;

  $scope.onConfirm = function() {
    $scope.approve(statusChangeHandler);
  };

  $scope.onSuccessConfirm = function() {
    var previousView = $ionicHistory.viewHistory().backView && $ionicHistory.viewHistory().backView.stateName;
    var fromBitPayCard = previousView.match(/tabs.bitpayCard/) ? true : false;

    $ionicHistory.nextViewOptions({
      disableAnimate: true
    });
    $ionicHistory.removeBackView();
    $scope.sendStatus = '';

    if (fromBitPayCard) {
      $timeout(function() {
        $state.transitionTo('tabs.bitpayCard', {
          id: $stateParams.cardId
        });
      }, 100);
    } else {
      $state.go('tabs.send');
    }
  };

  function publishAndSign(wallet, txp, onSendStatusChange) {
    walletService.publishAndSign(wallet, txp, function(err, txp) {
      if (err) return setSendError(err);
    }, onSendStatusChange);
  }
});
<|endoftext|>


<commit_before>var $ = require('jquery');

var CompactInline = function($inline) {
    this.$inline = $inline;
    this.prefix = $inline.data('inline-prefix');
    this.verboseName = $inline.data('inline-verbose-name');
    this.deleteText = $inline.data('inline-delete-text');
};

CompactInline.prototype = {
    updateLabels: function($inline) {
        var self = this;
        var $navigationItems = $inline.find('.inline-navigation-item');

        $inline.find('.inline-related').each(function(i) {
            var $inlineItem = $(this);
            var $label = $inlineItem.find('.inline_label');
            var label = $label.html().replace(/(#\d+)/g, "#" + (i + 1));
            var $navigationItem = $navigationItems.eq(i);
            var navigationLabel = $inlineItem.hasClass('has_original') ? label : self.verboseName + ' ' + label;

            $label.html(label);
            $navigationItem.html(navigationLabel);
        });
    },
    updateFormIndex: function($form, index) {
        var id_regex = new RegExp('(' + this.prefix + '-(\\d+|__prefix__))');
        var replacement = this.prefix + "-" + index;

        $form.find('*').each(function() {
            var $el = $(this);

            $.each(['for', 'id', 'name'], function() {
                var attr = this;

                if ($el.attr(attr)) {
                    $el.attr(attr, $el.attr(attr).replace(id_regex, replacement));
                }
            });
        });

        if (!$form.hasClass('empty-form')) {
            $form.attr('id', this.prefix + '-' + index);
        }
    },
    updateFormsIndexes: function($inline) {
        var self = this;
        var $navigationItems = $inline.find('.inline-navigation-item');

        $inline.find('.inline-related').each(function(i) {
            var $inlineItem = $(this);

            self.updateFormIndex($inlineItem, i);
            $navigationItems.eq(i).attr('data-inline-related-id', $inlineItem.attr('id'));
        });
    },
    updateTotalForms: function($inline) {
        var $totalFormsInput = $inline.find('[name="' + this.prefix + '-TOTAL_FORMS"]');
        var totalForms = parseInt($inline.find('.inline-related').length);

        $totalFormsInput.val(totalForms);
    },
    addNavigationItem: function($inline, $inlineItem) {
        var $empty = $inline.find('.inline-navigation-item.empty');

        return $empty
            .clone()
            .removeClass('empty')
            .attr('data-inline-related-id', $inlineItem.attr('id'))
            .insertBefore($empty);
    },
    openNavigationItem: function($inline, $item) {
        $inline
            .find('.inline-related')
            .removeClass('selected')
            .filter('#' + $item.attr('data-inline-related-id'))
            .addClass('selected');

        $inline.find('.inline-navigation-item').removeClass('selected');
        $item.addClass('selected');
    },
    removeItem: function($inline, $item) {
        $item.remove();
        $inline.find('.inline-navigation-item[data-inline-related-id="' + $item.attr('id') + '"]').remove();
    },
    openFirstNavigationItem: function($inline) {
        this.openNavigationItem($inline, $inline.find('.inline-navigation-item').first());
    },
    addItemDeleteButton: function($item) {
        $item
            .children(':first')
            .append('' + this.deleteText + "");
    },
    initAdding: function($inline) {
        var self = this;

        $inline.find('.add-row a').on('click', function (e) {
            e.preventDefault();

            var $empty = $inline.find('.inline-related.empty-form');
            var cloneIndex = parseInt($inline.find('.inline-related').length) - 1;
            var $clone = $empty
                .clone(true)
                .removeClass('empty-form')
                .insertBefore($empty);

            self.updateTotalForms($inline);
            self.updateFormIndex($clone, cloneIndex);
            self.updateFormIndex($empty, cloneIndex + 1);

            var navigationItem = self.addNavigationItem($inline, $clone);

            self.updateLabels($inline);
            self.openNavigationItem($inline, navigationItem);
            self.addItemDeleteButton($clone);
        });
    },
    initDeletion: function($inline) {
        var self = this;

        $inline.on('click', '.inline-deletelink', function(e) {
            e.preventDefault();

            var $inlineItem = $(this).closest('.inline-related');

            self.removeItem($inline, $inlineItem);
            self.updateFormsIndexes($inline);
            self.updateLabels($inline);
            self.updateTotalForms($inline);
            self.openFirstNavigationItem($inline);
        });

        $inline.find('.inline-related').each(function() {
            var $inlineItem = $(this);

            $inlineItem.find('.delete input').on('change', function() {
                $inline
                    .find('.inline-navigation-item[data-inline-related-id="' + $inlineItem.attr('id') + '"]')
                    .toggleClass('delete', $(this).is(':checked'));
            });
        });
    },
    initNavigation: function($inline) {
        var self = this;

        $inline.on('click', '.inline-navigation-item', function(e) {
            e.preventDefault();

            self.openNavigationItem($inline, $(this));
        });

        self.openFirstNavigationItem($inline);
    },
    run: function() {
        var $inline = this.$inline;

        try {
            this.initAdding($inline);
            this.initDeletion($inline);
            this.initNavigation($inline);
        } catch (e) {
            console.error(e, e.stack);
        }
    }
};

module.exports = CompactInline;
<commit_msg>Scroll to bottom on inline item adding<commit_after>var $ = require('jquery');

var CompactInline = function($inline) {
    this.$inline = $inline;
    this.prefix = $inline.data('inline-prefix');
    this.verboseName = $inline.data('inline-verbose-name');
    this.deleteText = $inline.data('inline-delete-text');
};

CompactInline.prototype = {
    updateLabels: function($inline) {
        var self = this;
        var $navigationItems = $inline.find('.inline-navigation-item');

        $inline.find('.inline-related').each(function(i) {
            var $inlineItem = $(this);
            var $label = $inlineItem.find('.inline_label');
            var label = $label.html().replace(/(#\d+)/g, "#" + (i + 1));
            var $navigationItem = $navigationItems.eq(i);
            var navigationLabel = $inlineItem.hasClass('has_original') ? label : self.verboseName + ' ' + label;

            $label.html(label);
            $navigationItem.html(navigationLabel);
        });
    },
    updateFormIndex: function($form, index) {
        var id_regex = new RegExp('(' + this.prefix + '-(\\d+|__prefix__))');
        var replacement = this.prefix + "-" + index;

        $form.find('*').each(function() {
            var $el = $(this);

            $.each(['for', 'id', 'name'], function() {
                var attr = this;

                if ($el.attr(attr)) {
                    $el.attr(attr, $el.attr(attr).replace(id_regex, replacement));
                }
            });
        });

        if (!$form.hasClass('empty-form')) {
            $form.attr('id', this.prefix + '-' + index);
        }
    },
    updateFormsIndexes: function($inline) {
        var self = this;
        var $navigationItems = $inline.find('.inline-navigation-item');

        $inline.find('.inline-related').each(function(i) {
            var $inlineItem = $(this);

            self.updateFormIndex($inlineItem, i);
            $navigationItems.eq(i).attr('data-inline-related-id', $inlineItem.attr('id'));
        });
    },
    updateTotalForms: function($inline) {
        var $totalFormsInput = $inline.find('[name="' + this.prefix + '-TOTAL_FORMS"]');
        var totalForms = parseInt($inline.find('.inline-related').length);

        $totalFormsInput.val(totalForms);
    },
    addNavigationItem: function($inline, $inlineItem) {
        var $empty = $inline.find('.inline-navigation-item.empty');

        return $empty
            .clone()
            .removeClass('empty')
            .attr('data-inline-related-id', $inlineItem.attr('id'))
            .insertBefore($empty);
    },
    openNavigationItem: function($inline, $item) {
        $inline
            .find('.inline-related')
            .removeClass('selected')
            .filter('#' + $item.attr('data-inline-related-id'))
            .addClass('selected');

        $inline.find('.inline-navigation-item').removeClass('selected');
        $item.addClass('selected');
    },
    removeItem: function($inline, $item) {
        $item.remove();
        $inline.find('.inline-navigation-item[data-inline-related-id="' + $item.attr('id') + '"]').remove();
    },
    openFirstNavigationItem: function($inline) {
        this.openNavigationItem($inline, $inline.find('.inline-navigation-item').first());
    },
    addItemDeleteButton: function($item) {
        $item
            .children(':first')
            .append('' + this.deleteText + "");
    },
    scrollNavigationToBottom: function($inline) {
        var $navigationItemsContainer = $inline.find('.inline-navigation-content');

        $navigationItemsContainer.stop().animate({
            scrollTop: $navigationItemsContainer.prop('scrollHeight')
        });
    },
    initAdding: function($inline) {
        var self = this;

        $inline.find('.add-row a').on('click', function (e) {
            e.preventDefault();

            var $empty = $inline.find('.inline-related.empty-form');
            var cloneIndex = parseInt($inline.find('.inline-related').length) - 1;
            var $clone = $empty
                .clone(true)
                .removeClass('empty-form')
                .insertBefore($empty);

            self.updateTotalForms($inline);
            self.updateFormIndex($clone, cloneIndex);
            self.updateFormIndex($empty, cloneIndex + 1);

            var navigationItem = self.addNavigationItem($inline, $clone);

            self.updateLabels($inline);
            self.openNavigationItem($inline, navigationItem);
            self.addItemDeleteButton($clone);
            self.scrollNavigationToBottom($inline);
        });
    },
    initDeletion: function($inline) {
        var self = this;

        $inline.on('click', '.inline-deletelink', function(e) {
            e.preventDefault();

            var $inlineItem = $(this).closest('.inline-related');

            self.removeItem($inline, $inlineItem);
            self.updateFormsIndexes($inline);
            self.updateLabels($inline);
            self.updateTotalForms($inline);
            self.openFirstNavigationItem($inline);
        });

        $inline.find('.inline-related').each(function() {
            var $inlineItem = $(this);

            $inlineItem.find('.delete input').on('change', function() {
                $inline
                    .find('.inline-navigation-item[data-inline-related-id="' + $inlineItem.attr('id') + '"]')
                    .toggleClass('delete', $(this).is(':checked'));
            });
        });
    },
    initNavigation: function($inline) {
        var self = this;

        $inline.on('click', '.inline-navigation-item', function(e) {
            e.preventDefault();

            self.openNavigationItem($inline, $(this));
        });

        self.openFirstNavigationItem($inline);
    },
    run: function() {
        var $inline = this.$inline;

        try {
            this.initAdding($inline);
            this.initDeletion($inline);
            this.initNavigation($inline);
        } catch (e) {
            console.error(e, e.stack);
        }
    }
};

module.exports = CompactInline;
<|endoftext|>


<commit_before>/*
 Copyright 2007-2009 WebDriver committers
 Copyright 2007-2009 Google Inc.
 Portions copyright 2011 Software Freedom Conservancy

 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.
 */

goog.provide('WebLoadingListener');
goog.provide('fxdriver.io');

goog.require('fxdriver.Timer');
goog.require('fxdriver.moz');

/**
 * @param {string} current The URL the browser is currently on.
 * @param {?string} future The destination URL, if known.
 * @return {Boolean} Whether a full page load would be expected if future is
 *    followed.
 */
fxdriver.io.isLoadExpected = function(current, future) {
  if (!future) {
    // Assume that we'll go somewhere exciting.
    return true;
  }

  var ioService =
      fxdriver.moz.getService('@mozilla.org/network/io-service;1', 'nsIIOService');
  var currentUri = ioService.newURI(current, '', null);
  var futureUri = ioService.newURI(future, '', currentUri);

  var loadEventExpected = true;
  if (futureUri.scheme == 'javascript') {
    // Assume that we're just modifying the local page.
    return false;
  }

  if (currentUri && futureUri &&
      currentUri.prePath == futureUri.prePath &&
      currentUri.filePath == futureUri.filePath) {
    // Looks like we're at the same url with a ref
    // Being clever and checking the ref was causing me headaches.
    // Brute force for now
    loadEventExpected = futureUri.path.indexOf('#') == -1;
  }

  return loadEventExpected;
};

var STATE_STOP = Components.interfaces.nsIWebProgressListener.STATE_STOP;

function DoNothing(browser, onComplete, opt_window) {
  this.browser = browser;
  this.onComplete = onComplete;
  this.win = opt_window;
  this.active = true;
}
DoNothing.prototype.onLocationChange = function() { return 0; };
DoNothing.prototype.onProgressChange = function() { return 0; };
DoNothing.prototype.onStateChange = function() { return 0; };
DoNothing.prototype.onStatusChange = function() { return 0; };
DoNothing.prototype.onSecurityChange = function() { return 0; };
DoNothing.prototype.onLinkIconAvailable = function() { return 0; };

DoNothing.prototype.QueryInterface = function(iid) {
  if (iid.equals(Components.interfaces.nsIWebProgressListener) ||
      iid.equals(Components.interfaces.nsISupportsWeakReference) ||
      iid.equals(Components.interfaces.nsISupports)) {
    return this;
  }
  throw Components.results.NS_NOINTERFACE;
};

function PatientListener(browser, onComplete, opt_window) {
  this.browser = browser;
  this.onComplete = onComplete;
  this.win = opt_window;
  this.active = true;
}
PatientListener.prototype = new DoNothing();

PatientListener.prototype.onStateChange = function(webProgress, request, flags) {
  if (!this.active) {
    return 0;
  }

  if (flags & STATE_STOP) {
    if (request.URI) {
      this.active = false;

      // On versions of firefox prior to 4 removing a listener may cause
      // subsequent listeners to be skipped. Favouring a memory leak over
      // not working properly.
      if (bot.userAgent.isProductVersion('4')) {
        WebLoadingListener.removeListener(this.browser, this);
      }
      this.onComplete();
    }
  }
  return 0;
};

function ImpatientListener(browser, onComplete, opt_window) {
  this.broser = browser;
  this.browserProgress = browser.webProgress;
  this.active = true;
  this.onComplete = onComplete;
  this.win = opt_window || null;
}
ImpatientListener.prototype = new PatientListener();

ImpatientListener.prototype.onProgressChange = function(webProgress) {
  if (!this.active) {
    return 0;
  }

  // The expected webProgress is not always given to this method:
  // https://bugzilla.mozilla.org/show_bug.cgi?id=693970
  // Consequently, we'll need to iterate over the browser's load group
  // looking for what we want to find. Or do we....

  if (!this.win || this.win.closed) {
    return 0;
  }

  var readyState = this.win.document && this.win.document.readyState;
  var location = this.win.document.location;

  if (('complete' == readyState || 'interactive' == readyState) &&
      (location != 'about:blank')) {
    this.active = false;

    // On versions of firefox prior to 4 removing a listener may cause
    // subsequent listeners to be skipped. Favouring a memory leak over
    // not working properly.
    if (bot.userAgent.isProductVersion('4')) {
      WebLoadingListener.removeListener(this.browser, this);
    }
    this.onComplete();
  }

  return 0;
};

var prefs = Components.classes['@mozilla.org/preferences-service;1'].getService(Components.interfaces['nsIPrefBranch']);

function buildHandler(browser, toCall, opt_window) {
  if (prefs.prefHasUserValue('webdriver.load.strategy')) {
    if ('unstable' == prefs.getCharPref('webdriver.load.strategy')) {
      return new ImpatientListener(browser, toCall, opt_window);
    }
  }
  return new PatientListener(browser, toCall, opt_window);
}

var loadingListenerTimer;

WebLoadingListener = function(browser, toCall, timeout, opt_window) {
  loadingListenerTimer = new fxdriver.Timer();
  var func = function(timedOut) { loadingListenerTimer.cancel(); toCall(timedOut); };

  this.handler = buildHandler(browser, func, opt_window);
  browser.addProgressListener(this.handler);
  var handler = this.handler;

  if (timeout == -1) {
    timeout = 1000 * 60 * 30; // 30 minutes is a loooong time.
  }

  loadingListenerTimer.setTimeout(function() {
      func(true);
      WebLoadingListener.removeListener(browser, handler);
  }, timeout);
};

WebLoadingListener.removeListener = function(browser, listener) {
  browser.removeProgressListener(listener.handler);
};
<commit_msg>AlexeiBarantsev: This bit of code magically fixes PageLoadingTest hanging in FF17<commit_after>/*
 Copyright 2007-2009 WebDriver committers
 Copyright 2007-2009 Google Inc.
 Portions copyright 2011 Software Freedom Conservancy

 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.
 */

goog.provide('WebLoadingListener');
goog.provide('fxdriver.io');

goog.require('fxdriver.Timer');
goog.require('fxdriver.moz');

goog.require('fxdriver.logging');

/**
 * @param {string} current The URL the browser is currently on.
 * @param {?string} future The destination URL, if known.
 * @return {Boolean} Whether a full page load would be expected if future is
 *    followed.
 */
fxdriver.io.isLoadExpected = function(current, future) {
  if (!future) {
    // Assume that we'll go somewhere exciting.
    return true;
  }

  var ioService =
      fxdriver.moz.getService('@mozilla.org/network/io-service;1', 'nsIIOService');
  var currentUri = ioService.newURI(current, '', null);
  var futureUri = ioService.newURI(future, '', currentUri);

  var loadEventExpected = true;
  if (futureUri.scheme == 'javascript') {
    // Assume that we're just modifying the local page.
    return false;
  }

  if (currentUri && futureUri &&
      currentUri.prePath == futureUri.prePath &&
      currentUri.filePath == futureUri.filePath) {
    // Looks like we're at the same url with a ref
    // Being clever and checking the ref was causing me headaches.
    // Brute force for now
    loadEventExpected = futureUri.path.indexOf('#') == -1;
  }

  return loadEventExpected;
};

var STATE_STOP = Components.interfaces.nsIWebProgressListener.STATE_STOP;

function DoNothing(browser, onComplete, opt_window) {
  this.browser = browser;
  this.onComplete = onComplete;
  this.win = opt_window;
  this.active = true;
}
DoNothing.prototype.onLocationChange = function() { return 0; };
DoNothing.prototype.onProgressChange = function() { return 0; };
DoNothing.prototype.onStateChange = function() { return 0; };
DoNothing.prototype.onStatusChange = function() { return 0; };
DoNothing.prototype.onSecurityChange = function() { return 0; };
DoNothing.prototype.onLinkIconAvailable = function() { return 0; };

DoNothing.prototype.QueryInterface = function(iid) {
  if (iid.equals(Components.interfaces.nsIWebProgressListener) ||
      iid.equals(Components.interfaces.nsISupportsWeakReference) ||
      iid.equals(Components.interfaces.nsISupports)) {
    return this;
  }
  throw Components.results.NS_NOINTERFACE;
};

function PatientListener(browser, onComplete, opt_window) {
  this.browser = browser;
  this.onComplete = onComplete;
  this.win = opt_window;
  this.active = true;
}
PatientListener.prototype = new DoNothing();

PatientListener.prototype.onStateChange = function(webProgress, request, flags) {
  if (!this.active) {
    return 0;
  }

  if (flags & STATE_STOP) {
    fxdriver.logging.info('request status is ' + request.status);
    if (request.URI) {
      this.active = false;

      // On versions of firefox prior to 4 removing a listener may cause
      // subsequent listeners to be skipped. Favouring a memory leak over
      // not working properly.
      if (bot.userAgent.isProductVersion('4')) {
        WebLoadingListener.removeListener(this.browser, this);
      }
      this.onComplete();
    }
  }
  return 0;
};

function ImpatientListener(browser, onComplete, opt_window) {
  this.broser = browser;
  this.browserProgress = browser.webProgress;
  this.active = true;
  this.onComplete = onComplete;
  this.win = opt_window || null;
}
ImpatientListener.prototype = new PatientListener();

ImpatientListener.prototype.onProgressChange = function(webProgress) {
  if (!this.active) {
    return 0;
  }

  // The expected webProgress is not always given to this method:
  // https://bugzilla.mozilla.org/show_bug.cgi?id=693970
  // Consequently, we'll need to iterate over the browser's load group
  // looking for what we want to find. Or do we....

  if (!this.win || this.win.closed) {
    return 0;
  }

  var readyState = this.win.document && this.win.document.readyState;
  var location = this.win.document.location;

  if (('complete' == readyState || 'interactive' == readyState) &&
      (location != 'about:blank')) {
    this.active = false;

    // On versions of firefox prior to 4 removing a listener may cause
    // subsequent listeners to be skipped. Favouring a memory leak over
    // not working properly.
    if (bot.userAgent.isProductVersion('4')) {
      WebLoadingListener.removeListener(this.browser, this);
    }
    this.onComplete();
  }

  return 0;
};

var prefs = Components.classes['@mozilla.org/preferences-service;1'].getService(Components.interfaces['nsIPrefBranch']);

function buildHandler(browser, toCall, opt_window) {
  if (prefs.prefHasUserValue('webdriver.load.strategy')) {
    if ('unstable' == prefs.getCharPref('webdriver.load.strategy')) {
      return new ImpatientListener(browser, toCall, opt_window);
    }
  }
  return new PatientListener(browser, toCall, opt_window);
}

var loadingListenerTimer;

WebLoadingListener = function(browser, toCall, timeout, opt_window) {
  loadingListenerTimer = new fxdriver.Timer();
  var func = function(timedOut) { loadingListenerTimer.cancel(); toCall(timedOut); };

  this.handler = buildHandler(browser, func, opt_window);
  browser.addProgressListener(this.handler);
  var handler = this.handler;

  if (timeout == -1) {
    timeout = 1000 * 60 * 30; // 30 minutes is a loooong time.
  }

  loadingListenerTimer.setTimeout(function() {
      func(true);
      WebLoadingListener.removeListener(browser, handler);
  }, timeout);
};

WebLoadingListener.removeListener = function(browser, listener) {
  browser.removeProgressListener(listener.handler);
};
<|endoftext|>


<commit_before>var $ = require('jquery');
var _ = require('lodash');
var waitForImages = require('waitforimages');

module.exports = (function() {

    var identifiers = [];

    $(window).on('resize', _.debounce(function() {
        $('[data-equalheight]').each(function() {
            var id = $(this).data('equalheight');
            if (!_.contains(identifiers, id)) identifiers.push(id);
        });

        _.forEach(identifiers, function(id) {
            var height = 0,
                elements = $('[data-equalheight=' + id + ']');

            elements.waitForImages(function() {
                elements.each(function() {
                    var $this = $(this),
                        currentHeight = 0;

                    $this.css('height', 'auto');
                    currentHeight = $this.outerHeight();
                    height = (currentHeight > height ? currentHeight : height);
                });
                elements.outerHeight(height);
            });
        });
    }, 100)).trigger('resize');

}());
<commit_msg>equalheight helper now support multiple arguments<commit_after>var $ = require('jquery');
var _ = require('lodash');
var waitForImages = require('waitforimages');

module.exports = (function() {

    var identifiers = [];

    $(window).on('resize', _.debounce(function() {
        $('[data-equalheight]').each(function() {
            var ids = $(this).data('equalheight').split(' ');
            _.forEach(ids, function(id) {
                if (!_.contains(identifiers, id)) identifiers.push(id);
            });
        });

        _.forEach(identifiers, function(id) {
            var height = 0,
                elements = $('[data-equalheight~=' + id + ']');

            elements.waitForImages(function() {
                elements.each(function() {
                    var $this = $(this),
                        currentHeight = 0;

                    $this.css('height', 'auto');
                    currentHeight = $this.outerHeight();
                    height = (currentHeight > height ? currentHeight : height);
                });
                elements.outerHeight(height);
            });
        });
    }, 100)).trigger('resize');

}());
<|endoftext|>


<commit_before>(function ($) {
    "use strict";
    var templates = {},
        queue = {},
        formatters = {};

    function loadTemplate(template, data, options) {
        var $that = this,
            $template,
            isFile,
            settings;

        data = data || {};

        settings = $.extend(true, {
            // These are the defaults.
            async: true,
            overwriteCache: false,
            complete: null,
            success: null,
            error: function () {
                $(this).each(function () {
                    $(this).html(settings.errorMessage);
                });
            },
            errorMessage: "There was an error loading the template.",
            paged: false,
            pageNo: 1,
            elemPerPage: 10,
            append: false,
            prepend: false,
            beforeInsert: null,
            afterInsert: null,
            bindingOptions: {
                ignoreUndefined: false,
                ignoreNull: false,
                ignoreEmptyString: false
            }
        }, options);

        if ($.type(data) === "array") {
            return processArray.call(this, template, data, settings);
        }

        if (!containsSlashes(template)) {
            $template = $(template);
            if (typeof template === 'string' && template.indexOf('#') === 0) {
                settings.isFile = false;
            }
        }

        isFile = settings.isFile || (typeof settings.isFile === "undefined" && (typeof $template === "undefined" || $template.length === 0));

        if (isFile && !settings.overwriteCache && templates[template]) {
            prepareTemplateFromCache(template, $that, data, settings);
        } else if (isFile && !settings.overwriteCache && templates.hasOwnProperty(template)) {
            addToQueue(template, $that, data, settings);
        } else if (isFile) {
            loadAndPrepareTemplate(template, $that, data, settings);
        } else {
            loadTemplateFromDocument($template, $that, data, settings);
        }
        return this;
    }

    function addTemplateFormatter(key, formatter) {
        if (formatter) {
            formatters[key] = formatter;
        } else {
            formatters = $.extend(formatters, key);
        }
    }

    function containsSlashes(str) {
        return typeof str === "string" && str.indexOf("/") > -1;
    }

    function processArray(template, data, settings) {
        settings = settings || {};
        var $that = this,
            todo = data.length,
            doPrepend = settings.prepend && !settings.append,
            done = 0,
            success = 0,
            errored = false,
            newOptions;

        if (settings.paged) {
            var startNo = (settings.pageNo - 1) * settings.elemPerPage;
            data = data.slice(startNo, startNo + settings.elemPerPage);
            todo = data.length;
        }

        newOptions = $.extend(
            {},
            settings,
            {
                complete: function () {
                    if (this.html) {
                        if (doPrepend) {
                            $that.prepend(this.html());
                        } else {
                            $that.append(this.html());
                        }
                    }
                    done++;
                    if (done === todo || errored) {
                        if (errored && settings && typeof settings.error === "function") {
                            settings.error.call($that);
                        }
                        if (settings && typeof settings.complete === "function") {
                            settings.complete();
                        }
                    }
                },
                success: function () {
                    success++;
                    if (success === todo) {
                        if (settings && typeof settings.success === "function") {
                            settings.success();
                        }
                    }
                },
                error: function () {
                    errored = true;
                }
            }
        );

        if (!settings.append && !settings.prepend) {
            $that.html("");
        }

        if (doPrepend) data.reverse();
        $(data).each(function () {
            var $div = $("<div/>");
            loadTemplate.call($div, template, this, newOptions);
            if (errored) {
                return false;
            }
        });

        return this;
    }

    function addToQueue(template, selection, data, settings) {
        if (queue[template]) {
            queue[template].push({ data: data, selection: selection, settings: settings });
        } else {
            queue[template] = [{ data: data, selection: selection, settings: settings}];
        }
    }

    function prepareTemplateFromCache(template, selection, data, settings) {
        var $templateContainer = templates[template].clone();

        prepareTemplate.call(selection, $templateContainer, data, settings);
        if (typeof settings.success === "function") {
            settings.success();
        }
    }

    function uniqueId() {
        return new Date().getTime();
    }

    function urlAvoidCache(url) {
        if (url.indexOf('?') !== -1) {
            return url + "&_=" + uniqueId();
        }
        else {
            return url + "?_=" + uniqueId();
        }
    }

    function loadAndPrepareTemplate(template, selection, data, settings) {
        var $templateContainer = $("<div/>");

        templates[template] = null;
        var templateUrl = template;
        if (settings.overwriteCache) {
            templateUrl = urlAvoidCache(templateUrl);
        }
        $.ajax({
            url: templateUrl,
            async: settings.async,
            success: function (templateContent) {
                $templateContainer.html(templateContent);
                handleTemplateLoadingSuccess($templateContainer, template, selection, data, settings);
            },
            error: function () {
                handleTemplateLoadingError(template, selection, data, settings);
            }
        });
    }

    function loadTemplateFromDocument($template, selection, data, settings) {
        var $templateContainer = $("<div/>");

        if ($template.is("script") || $template.is("template")) {
            $template = $.parseHTML($.trim($template.html()));
        }

        $templateContainer.html($template);
        prepareTemplate.call(selection, $templateContainer, data, settings);

        if (typeof settings.success === "function") {
            settings.success();
        }
    }

    function prepareTemplate(template, data, settings) {
        bindData(template, data, settings);

        $(this).each(function () {
            var $templateHtml = $(template.html());
            if (settings.beforeInsert) {
                settings.beforeInsert($templateHtml);
            }
            if (settings.append) {

                $(this).append($templateHtml);
            } else if (settings.prepend) {
                $(this).prepend($templateHtml);
            } else {
                $(this).html($templateHtml);
            }
            if (settings.afterInsert) {
                settings.afterInsert($templateHtml);
            }
        });

        if (typeof settings.complete === "function") {
            settings.complete.call($(this));
        }
    }

    function handleTemplateLoadingError(template, selection, data, settings) {
        var value;

        if (typeof settings.error === "function") {
            settings.error.call(selection);
        }

        $(queue[template]).each(function (key, value) {
            if (typeof value.settings.error === "function") {
                value.settings.error.call(value.selection);
            }
        });

        if (typeof settings.complete === "function") {
            settings.complete.call(selection);
        }

        while (queue[template] && (value = queue[template].shift())) {
            if (typeof value.settings.complete === "function") {
                value.settings.complete.call(value.selection);
            }
        }

        if (typeof queue[template] !== 'undefined' && queue[template].length > 0) {
            queue[template] = [];
        }
    }

    function handleTemplateLoadingSuccess($templateContainer, template, selection, data, settings) {
        var value;

        templates[template] = $templateContainer.clone();
        prepareTemplate.call(selection, $templateContainer, data, settings);

        if (typeof settings.success === "function") {
            settings.success.call(selection);
        }

        while (queue[template] && (value = queue[template].shift())) {
            prepareTemplate.call(value.selection, templates[template].clone(), value.data, value.settings);
            if (typeof value.settings.success === "function") {
                value.settings.success.call(value.selection);
            }
        }
    }

    function bindData(template, data, settings) {
        data = data || {};

        processElements("data-content", template, data, settings, function ($elem, value) {
            $elem.html(applyFormatters($elem, value, "content", settings));
        });

        processElements("data-content-append", template, data, settings, function ($elem, value) {
            $elem.append(applyFormatters($elem, value, "content", settings));
        });

        processElements("data-content-prepend", template, data, settings, function ($elem, value) {
            $elem.prepend(applyFormatters($elem, value, "content", settings));
        });

        processElements("data-content-text", template, data, settings, function ($elem, value) {
            $elem.text(applyFormatters($elem, value, "content", settings));
        });

        processElements("data-src", template, data, settings, function ($elem, value) {
            $elem.attr("src", applyFormatters($elem, value, "src", settings));
        }, function ($elem) {
            $elem.remove();
        });

        processElements("data-alt", template, data, settings, function ($elem, value) {
            $elem.attr("alt", applyFormatters($elem, value, "alt", settings));
        });

        processElements("data-id", template, data, settings, function ($elem, value) {
            $elem.attr("id", applyFormatters($elem, value, "id", settings));
        });

        processElements("data-value", template, data, settings, function ($elem, value) {
            $elem.attr("value", applyFormatters($elem, value, "value", settings));
        });

        processElements("data-link", template, data, settings, function ($elem, value) {
            var $linkElem = $("<a/>");
            $linkElem.attr("href", applyFormatters($elem, value, "link", settings));
            $linkElem.html($elem.html());
            $elem.html($linkElem);
        });

        processElements("data-link-wrap", template, data, settings, function ($elem, value) {
            var $linkElem = $("<a/>");
            $linkElem.attr("href", applyFormatters($elem, value, "link-wrap", settings));
            $elem.wrap($linkElem);
        });

        processElements("data-options", template, data, settings, function ($elem, value) {
            $(value).each(function () {
                var $option = $("<option/>");
                $option.attr('value', this).text(this).appendTo($elem);
            });
        });

        processAllElements(template, data, settings);
    }

    function processElements(attribute, template, data, settings, dataBindFunction, noDataFunction) {
        $("[" + attribute + "]", template).each(function () {
            var $this = $(this),
                param = $this.attr(attribute),
                value = getValue(data, param);

            if (!valueIsAllowedByBindingOptions($this, value, settings)) {
                $this.remove();
                return;
            }

            $this.removeAttr(attribute);

            if (typeof value !== 'undefined' && dataBindFunction) {
                dataBindFunction($this, value);
            } else if (noDataFunction) {
                noDataFunction($this);
            }
        });
        return;
    }

    function valueIsAllowedByBindingOptions(bindingOptionsContainer, value, settings) {

        var bindingOptions = getBindingOptions(bindingOptionsContainer, settings);

        if (bindingOptions.ignoreUndefined && typeof value === "undefined") {
            return false;

        } else if (bindingOptions.ignoreNull && value === null) {
            return false;

        } else if (bindingOptions.ignoreEmptyString && value === "") {
            return false;

        } else {
            return true;
        }
    }

    function getBindingOptions(bindingOptionsContainer, settings) {

        var bindingOptions = {};

        // binding options passed as template attribute, i.e. 'data-binding-options'
        if (bindingOptionsContainer instanceof jQuery && bindingOptionsContainer.attr("data-binding-options")) {

            bindingOptions = $.parseJSON(bindingOptionsContainer.attr("data-binding-options"));
            bindingOptionsContainer.removeAttr("data-binding-options");

            // binding options defined in a "data-template-bind" attribute
        } else if (typeof bindingOptionsContainer === "object" && bindingOptionsContainer.hasOwnProperty('bindingOptions')) {
            bindingOptions = bindingOptionsContainer.bindingOptions;
        }

        // extend general bindingOptions with specific settings
        return $.extend({}, settings.bindingOptions, bindingOptions);
    }

    function processAllElements(template, data, settings) {
        $("[data-template-bind]", template).each(function () {
            var $this = $(this),
                param = $.parseJSON($this.attr("data-template-bind"));

            $this.removeAttr("data-template-bind");

            $(param).each(function () {
                var value;

                if (typeof (this.value) === 'object') {
                    value = getValue(data, this.value.data);
                } else {
                    value = getValue(data, this.value);
                }
                if (this.attribute) {

                    if (!valueIsAllowedByBindingOptions(this, value, settings)) {
                        $this.remove();
                        return;
                    }

                    switch (this.attribute) {
                        case "content":
                            $this.html(applyDataBindFormatters($this, value, this));
                            break;
                        case "contentAppend":
                            $this.append(applyDataBindFormatters($this, value, this));
                            break;
                        case "contentPrepend":
                            $this.prepend(applyDataBindFormatters($this, value, this));
                            break;
                        case "contentText":
                            $this.text(applyDataBindFormatters($this, value, this));
                            break;
                        case "options":
                            var optionsData = this;
                            $(value).each(function () {
                                var $option = $("<option/>");
                                $option
                                    .attr('value', this[optionsData.value.value])
                                    .text(applyDataBindFormatters($this, this[optionsData.value.content], optionsData))
                                    .attr('selected', typeof this[optionsData.value.selected] == undefined ? false : this[optionsData.value.selected])
                                    .appendTo($this);
                            });
                            break;
                        default:
                            $this.attr(this.attribute, applyDataBindFormatters($this, value, this));
                    }
                }
            });
        });
    }

    function applyDataBindFormatters($elem, value, data, settings) {
        if (data.formatter && formatters[data.formatter]) {
            return (function (formatterSettings) {
                return formatters[data.formatter].call($elem, value, data.formatOptions, formatterSettings);
            })(settings);
        }
        return value;
    }

    function getValue(data, param) {
        if (param === "this") {
            return data;
        }
        var paramParts = param.split('.'),
            part,
            value = data;

        while ((part = paramParts.shift()) && typeof value !== "undefined") {
            value = value[part];
        }

        return value;
    }

    function applyFormatters($elem, value, attr, settings) {
        var formatterTarget = $elem.attr("data-format-target"),
            formatter;

        if (formatterTarget === attr || (!formatterTarget && attr === "content")) {
            formatter = $elem.attr("data-format");
            if (formatter && typeof formatters[formatter] === "function") {
                var formatOptions = $elem.attr("data-format-options");
                return (function (formatterSettings) {
                    return formatters[formatter].call($elem[0], value, formatOptions, $.extend({}, formatterSettings));
                })(settings);
            }
        }

        return value;
    }
    addTemplateFormatter("nestedTemplateFormatter", function (value, options, internalSettings) {
        if (!options) {
            return;
        }

        if (typeof options === "string" && options[0] === "{") {
            options = $.parseJSON(options);
        }

        var parentElement = options.parentElement || "div";
        var template = options.template || options;
        return $("<" + parentElement + "/>").loadTemplate(template, value, internalSettings);
    });
    $.fn.loadTemplate = loadTemplate;
    $.addTemplateFormatter = addTemplateFormatter;

})(jQuery);
<commit_msg>Updates to jquery.loadTemplate-1.4.3.js<commit_after>(function ($) {
    "use strict";
    var templates = {},
        queue = {},
        formatters = {};

    function loadTemplate(template, data, options) {
        var $that = this,
            $template,
            isFile,
            settings;

        data = data || {};

        settings = $.extend(true, {
            // These are the defaults.
            async: true,
            overwriteCache: false,
            complete: null,
            success: null,
            error: function () {
                $(this).each(function () {
                    $(this).html(settings.errorMessage);
                });
            },
            errorMessage: "There was an error loading the template.",
            paged: false,
            pageNo: 1,
            elemPerPage: 10,
            append: false,
            prepend: false,
            beforeInsert: null,
            afterInsert: null,
            bindingOptions: {
                ignoreUndefined: false,
                ignoreNull: false,
                ignoreEmptyString: false
            }
        }, options);

        if ($.type(data) === "array") {
            return processArray.call(this, template, data, settings);
        }

        if (!containsSlashes(template)) {
            $template = $(template);
            if (typeof template === 'string' && template.indexOf('#') === 0) {
                settings.isFile = false;
            }
        }

        isFile = settings.isFile || (typeof settings.isFile === "undefined" && (typeof $template === "undefined" || $template.length === 0));

        if (isFile && !settings.overwriteCache && templates[template]) {
            prepareTemplateFromCache(template, $that, data, settings);
        } else if (isFile && !settings.overwriteCache && templates.hasOwnProperty(template)) {
            addToQueue(template, $that, data, settings);
        } else if (isFile) {
            loadAndPrepareTemplate(template, $that, data, settings);
        } else {
            loadTemplateFromDocument($template, $that, data, settings);
        }
        return this;
    }

    function addTemplateFormatter(key, formatter) {
        if (formatter) {
            formatters[key] = formatter;
        } else {
            formatters = $.extend(formatters, key);
        }
    }

    function containsSlashes(str) {
        return typeof str === "string" && str.indexOf("/") > -1;
    }

    function processArray(template, data, settings) {
        settings = settings || {};
        var $that = this,
            todo = data.length,
            doPrepend = settings.prepend && !settings.append,
            done = 0,
            success = 0,
            errored = false,
            newOptions;

        if (settings.paged) {
            var startNo = (settings.pageNo - 1) * settings.elemPerPage;
            data = data.slice(startNo, startNo + settings.elemPerPage);
            todo = data.length;
        }

        newOptions = $.extend(
            {},
            settings,
            {
                complete: function () {
                    if (this.html) {
                        if (doPrepend) {
                            $that.prepend(this.html());
                        } else {
                            $that.append(this.html());
                        }
                    }
                    done++;
                    if (done === todo || errored) {
                        if (errored && settings && typeof settings.error === "function") {
                            settings.error.call($that);
                        }
                        if (settings && typeof settings.complete === "function") {
                            settings.complete();
                        }
                    }
                },
                success: function () {
                    success++;
                    if (success === todo) {
                        if (settings && typeof settings.success === "function") {
                            settings.success();
                        }
                    }
                },
                error: function () {
                    errored = true;
                }
            }
        );

        if (!settings.append && !settings.prepend) {
            $that.html("");
        }

        if (doPrepend) data.reverse();
        $(data).each(function () {
            var $div = $("<div/>");
            loadTemplate.call($div, template, this, newOptions);
            if (errored) {
                return false;
            }
        });

        return this;
    }

    function addToQueue(template, selection, data, settings) {
        if (queue[template]) {
            queue[template].push({ data: data, selection: selection, settings: settings });
        } else {
            queue[template] = [{ data: data, selection: selection, settings: settings}];
        }
    }

    function prepareTemplateFromCache(template, selection, data, settings) {
        var $templateContainer = templates[template].clone();

        prepareTemplate.call(selection, $templateContainer, data, settings);
        if (typeof settings.success === "function") {
            settings.success();
        }
    }

    function uniqueId() {
        return new Date().getTime();
    }

    function urlAvoidCache(url) {
        if (url.indexOf('?') !== -1) {
            return url + "&_=" + uniqueId();
        }
        else {
            return url + "?_=" + uniqueId();
        }
    }

    function loadAndPrepareTemplate(template, selection, data, settings) {
        var $templateContainer = $("<div/>");

        templates[template] = null;
        var templateUrl = template;
        if (settings.overwriteCache) {
            templateUrl = urlAvoidCache(templateUrl);
        }
        $.ajax({
            url: templateUrl,
            async: settings.async,
            success: function (templateContent) {
                $templateContainer.html(templateContent);
                handleTemplateLoadingSuccess($templateContainer, template, selection, data, settings);
            },
            error: function () {
                handleTemplateLoadingError(template, selection, data, settings);
            }
        });
    }

    function loadTemplateFromDocument($template, selection, data, settings) {
        var $templateContainer = $("<div/>");

        if ($template.is("script") || $template.is("template")) {
            $template = $.parseHTML($.trim($template.html()));
        }

        $templateContainer.html($template);
        prepareTemplate.call(selection, $templateContainer, data, settings);

        if (typeof settings.success === "function") {
            settings.success();
        }
    }

    function prepareTemplate(template, data, settings) {
        bindData(template, data, settings);

        $(this).each(function () {
            var $templateHtml = $(template.html());
            if (settings.beforeInsert) {
                settings.beforeInsert($templateHtml);
            }
            if (settings.append) {

                $(this).append($templateHtml);
            } else if (settings.prepend) {
                $(this).prepend($templateHtml);
            } else {
                $(this).html($templateHtml);
            }
            if (settings.afterInsert) {
                settings.afterInsert($templateHtml);
            }
        });

        if (typeof settings.complete === "function") {
            settings.complete.call($(this));
        }
    }

    function handleTemplateLoadingError(template, selection, data, settings) {
        var value;

        if (typeof settings.error === "function") {
            settings.error.call(selection);
        }

        $(queue[template]).each(function (key, value) {
            if (typeof value.settings.error === "function") {
                value.settings.error.call(value.selection);
            }
        });

        if (typeof settings.complete === "function") {
            settings.complete.call(selection);
        }

        while (queue[template] && (value = queue[template].shift())) {
            if (typeof value.settings.complete === "function") {
                value.settings.complete.call(value.selection);
            }
        }

        if (typeof queue[template] !== 'undefined' && queue[template].length > 0) {
            queue[template] = [];
        }
    }

    function handleTemplateLoadingSuccess($templateContainer, template, selection, data, settings) {
        var value;

        templates[template] = $templateContainer.clone();
        prepareTemplate.call(selection, $templateContainer, data, settings);

        if (typeof settings.success === "function") {
            settings.success.call(selection);
        }

        while (queue[template] && (value = queue[template].shift())) {
            prepareTemplate.call(value.selection, templates[template].clone(), value.data, value.settings);
            if (typeof value.settings.success === "function") {
                value.settings.success.call(value.selection);
            }
        }
    }

    function bindData(template, data, settings) {
        data = data || {};

        processElements("data-content", template, data, settings, function ($elem, value) {
            $elem.html(applyFormatters($elem, value, "content", settings));
        });

        processElements("data-content-append", template, data, settings, function ($elem, value) {
            $elem.append(applyFormatters($elem, value, "content", settings));
        });

        processElements("data-content-prepend", template, data, settings, function ($elem, value) {
            $elem.prepend(applyFormatters($elem, value, "content", settings));
        });

        processElements("data-content-text", template, data, settings, function ($elem, value) {
            $elem.text(applyFormatters($elem, value, "content", settings));
        });

        processElements("data-src", template, data, settings, function ($elem, value) {
            $elem.attr("src", applyFormatters($elem, value, "src", settings));
        }, function ($elem) {
            $elem.remove();
        });

        processElements("data-alt", template, data, settings, function ($elem, value) {
            $elem.attr("alt", applyFormatters($elem, value, "alt", settings));
        });

        processElements("data-id", template, data, settings, function ($elem, value) {
            $elem.attr("id", applyFormatters($elem, value, "id", settings));
        });

        processElements("data-value", template, data, settings, function ($elem, value) {
            $elem.attr("value", applyFormatters($elem, value, "value", settings));
        });

        processElements("data-link", template, data, settings, function ($elem, value) {
            var $linkElem = $("<a/>");
            $linkElem.attr("href", applyFormatters($elem, value, "link", settings));
            $linkElem.html($elem.html());
            $elem.html($linkElem);
        });

        processElements("data-link-wrap", template, data, settings, function ($elem, value) {
            var $linkElem = $("<a/>");
            $linkElem.attr("href", applyFormatters($elem, value, "link-wrap", settings));
            $elem.wrap($linkElem);
        });

        processElements("data-options", template, data, settings, function ($elem, value) {
            $(value).each(function () {
                var $option = $("<option/>");
                $option.attr('value', this).text(this).appendTo($elem);
            });
        });

        processAllElements(template, data, settings);
    }

    function processElements(attribute, template, data, settings, dataBindFunction, noDataFunction) {
        $("[" + attribute + "]", template).each(function () {
            var $this = $(this),
                param = $this.attr(attribute),
                value = getValue(data, param);

            if (!valueIsAllowedByBindingOptions($this, value, settings)) {
                $this.remove();
                return;
            }

            $this.removeAttr(attribute);

            if (typeof value !== 'undefined' && dataBindFunction) {
                dataBindFunction($this, value);
            } else if (noDataFunction) {
                noDataFunction($this);
            }
        });
        return;
    }

    function valueIsAllowedByBindingOptions(bindingOptionsContainer, value, settings) {

        var bindingOptions = getBindingOptions(bindingOptionsContainer, settings);

        if (bindingOptions.ignoreUndefined && typeof value === "undefined") {
            return false;

        } else if (bindingOptions.ignoreNull && value === null) {
            return false;

        } else if (bindingOptions.ignoreEmptyString && value === "") {
            return false;

        } else {
            return true;
        }
    }

    function getBindingOptions(bindingOptionsContainer, settings) {

        var bindingOptions = {};

        // binding options passed as template attribute, i.e. 'data-binding-options'
        if (bindingOptionsContainer instanceof jQuery && bindingOptionsContainer.attr("data-binding-options")) {

            bindingOptions = $.parseJSON(bindingOptionsContainer.attr("data-binding-options"));
            bindingOptionsContainer.removeAttr("data-binding-options");

            // binding options defined in a "data-template-bind" attribute
        } else if (typeof bindingOptionsContainer === "object" && bindingOptionsContainer.hasOwnProperty('bindingOptions')) {
            bindingOptions = bindingOptionsContainer.bindingOptions;
        }

        // extend general bindingOptions with specific settings
        return $.extend({}, settings.bindingOptions, bindingOptions);
    }

    function processAllElements(template, data, settings) {
        $("[data-template-bind]", template).each(function () {
            var $this = $(this),
                param = $.parseJSON($this.attr("data-template-bind"));

            $this.removeAttr("data-template-bind");

            $(param).each(function () {
                var value;

                if (typeof (this.value) === 'object') {
                    value = getValue(data, this.value.data);
                } else {
                    value = getValue(data, this.value);
                }
                if (this.attribute) {

                    if (!valueIsAllowedByBindingOptions(this, value, settings)) {
                        $this.remove();
                        return;
                    }

                    switch (this.attribute) {
                        case "content":
                            $this.html(applyDataBindFormatters($this, value, this));
                            break;
                        case "contentAppend":
                            $this.append(applyDataBindFormatters($this, value, this));
                            break;
                        case "contentPrepend":
                            $this.prepend(applyDataBindFormatters($this, value, this));
                            break;
                        case "contentText":
                            $this.text(applyDataBindFormatters($this, value, this));
                            break;
                        case "options":
                            var optionsData = this;
                            $(value).each(function () {
                                var $option = $("<option/>");
                                $option
                                    .attr('value', this[optionsData.value.value])
                                    .text(applyDataBindFormatters($this, this[optionsData.value.content], optionsData))
                                    .attr('selected', typeof this[optionsData.value.selected] == undefined ? false : this[optionsData.value.selected])
                                    .appendTo($this);
                            });
                            break;
                        default:
                            $this.attr(this.attribute, applyDataBindFormatters($this, value, this));
                    }
                }
            });
        });
    }

    function applyDataBindFormatters($elem, value, data, settings) {
        if (data.formatter && formatters[data.formatter]) {
            return (function (formatterSettings) {
                return formatters[data.formatter].call($elem, value, data.formatOptions, formatterSettings);
            })(settings);
        }
        return value;
    }

    function getValue(data, param) {
        if (param === "this") {
            return data;
        }
        var paramParts = param.split('.'),
            part,
            value = data;

        while ((part = paramParts.shift()) && typeof value !== "undefined" && value != null) {
            value = value[part];
        }

        return value;
    }

    function applyFormatters($elem, value, attr, settings) {
        var formatterTarget = $elem.attr("data-format-target"),
            formatter;

        if (formatterTarget === attr || (!formatterTarget && attr === "content")) {
            formatter = $elem.attr("data-format");
            if (formatter && typeof formatters[formatter] === "function") {
                var formatOptions = $elem.attr("data-format-options");
                return (function (formatterSettings) {
                    return formatters[formatter].call($elem[0], value, formatOptions, $.extend({}, formatterSettings));
                })(settings);
            }
        }

        return value;
    }
    addTemplateFormatter("nestedTemplateFormatter", function (value, options, internalSettings) {
        if (!options) {
            return;
        }

        if (typeof options === "string" && options[0] === "{") {
            options = $.parseJSON(options);
        }

        var parentElement = options.parentElement || "div";
        var template = options.template || options;

        //If a parent is specified, return it; otherwise only return the generated children.
        if(options.parentElement)
            return $("<" + parentElement + "/>").loadTemplate(template, value, internalSettings);
        else
            return $("<" + parentElement + "/>").loadTemplate(template, value, internalSettings).children();
    });
    $.fn.loadTemplate = loadTemplate;
    $.addTemplateFormatter = addTemplateFormatter;

})(jQuery);
<|endoftext|>