<commit_before>angular.module('omniwallet')
  .factory('enumerated_addresses', function($http, $q, $timeout, $injector) {
    var count = 1;
    return {
      "getData": function() {
        var deferred = $q.defer();

        _.defer(function() {
          var wallet = $injector.get('userService').getWallet();
          if (wallet && wallet.addresses.length > 0) {

            deferred.resolve({
              addresses: wallet.addresses
            });
          } else {
            deferred.resolve({
              addresses: []
            });
          }
        });
        return deferred.promise;
      }
    };
  })
  .controller('AddAddressController', function($modal, $injector, $scope, $timeout, userService, enumerated_addresses) {

  function decodeAddressFromPrivateKey(key) {

    //  Return the address decoded from the private key.
    var eckey = new Bitcoin.ECKey(key);
    var addr = eckey.getBitcoinAddress().toString();

    return addr;
  };

  function encodePrivateKey(key, passphrase) {

    //  Return encoded key.  Forget the passphrase forever.
    var eckey = new Bitcoin.ECKey(key);
    var enc = eckey.getEncryptedFormat(passphrase);

    return enc;
  };

  $scope.backupWallet = function() {
    $scope.login = {
      uuid: userService.data.wallet.uuid,
      action: 'verify',
      title: 'Verify Account',
      button: 'Validate',
      disable: true //disable UUID field in template
    };
    var modalInstance = $modal.open({
      templateUrl: '/partials/login_modal.html',
      controller: LoginController,
      scope: $scope
    });

    modalInstance.result.then(function(wallet) {
      $scope.exportData = {
        backupName : wallet.uuid,
        exportPrivate : true,
        exportWatch : true
      };
      $scope.exportInProgress=false;
      var exportModalInstance = $modal.open({
        templateUrl: '/partials/export_wallet.html',
        controller: function($scope, $modalInstance, wallet){
          $scope.summary = [];
          $scope.exportFinished = false;
          $scope.exportWallet = function(exportData){
            $scope.exportInProgress=true;
            $scope.exported = 0;
            var walletAddresses = wallet.addresses;
            $scope.total = walletAddresses.length;
            var blob = {
              addresses: []
            };

            var next = function(){
              $timeout(function(){
                return exportAddress(walletAddresses[$scope.exported]);
              },0,false);
            };

            var exportAddress = function(obj){
              $scope.$apply(function(){
                if($scope.exported == $scope.total) {
                  var exportBlob = new Blob([JSON.stringify(blob)], {
                    type: 'application/json;charset=utf-8'
                  });
                  fileName=exportData.backupName+".json";
                  saveAs(exportBlob, fileName);
                  $scope.exportInProgress = false;
                  return $scope.exportFinished = true;
                }

                try{
                  if(exportData.exportPrivate && obj.privkey) {
                    var ecKey = Bitcoin.ECKey.decodeEncryptedFormat(obj.privkey, obj.address);
                    var addr = ecKey.getBitcoinAddress().toString();
                    var key = ecKey.getWalletImportFormat();
                    blob.addresses.push({ address: addr, privkey: key });
                    $scope.progressMessage = "Exported trading address " + addr;
                    $scope.progressColor = "green";
                  }
                  if(exportData.exportWatch && !obj.privkey) {
                    blob.addresses.push({ address: obj.address, privkey: "" });
                    $scope.progressMessage = "Exported watch address " + addr;
                    $scope.progressColor = "green";
                  }
                } catch (e) {
                  $scope.progressMessage = "Error exporting "+addr+": " + e;
                  $scope.progressColor = "red";
                }
                $scope.summary.push({color:$scope.progressColor,message: $scope.progressMessage});
                $scope.exported++;

                return next();
              });
            };

            // Start the loop
            next();
          };

          $scope.cancel = function() {
            $modalInstance.dismiss('cancel');
          };

          $scope.close = function() {
            $modalInstance.dismiss('close');
          };
        },
        scope: $scope,
        resolve:{
          wallet: function(){
            return wallet;
          }
        }
      });
    });
  };

  // Begin Import watch only Form Code
  $scope.openImportWatchOnlyForm = function() {
    var modalInstance = $modal.open({
      templateUrl: '/partials/import_watch_only.html',
      controller: AddBtcAddressModal
    });

    modalInstance.result.then(function(result) {

      if (result.address) {
        $injector.get('userService').addAddress(result.address);
      }
      $scope.refresh();

    }, function() {});
  };

  var AddBtcAddressModal = function($scope, $modalInstance) {
    $scope.validate = function(address) {
      return Bitcoin.Address.validate(address);
    };

    $scope.addressNotListed = function(address) {
      var addresses = $injector.get('userService').getAllAddresses();
      for (var i in addresses) {
        if (addresses[i].address == address) {
          return false;
        }
      }

      return true;
    };

    $scope.ok = function(result) {
      if (Bitcoin.Address.validate(result.address))
        $modalInstance.close(result);
      else
        console.log('*** Invalid address: ' + result.address);
    };

    $scope.cancel = function() {
      $modalInstance.dismiss('cancel');
    };
  };
  // Done Import Watch Only Form Code.

  // Begin Import Private Key Form Code
  $scope.openImportPrivateKeyForm = function() {
    var modalInstance = $modal.open({
      templateUrl: '/partials/import_private.html',
      controller: AddPrivateKeyModal
    });

    modalInstance.result.then(function(result) {

      if (result.privKey) {
        // Use address as passphrase for now
        var addr = decodeAddressFromPrivateKey(result.privKey);
        $injector.get('userService').addAddress(
        addr,
        encodePrivateKey(result.privKey, addr));
      }
      $scope.refresh();

    }, function() {});
  };

  var AddPrivateKeyModal = function($scope, $modalInstance) {
    $scope.validate = function(address) {
      if (!address) return false;

      try {
        var eckey = new Bitcoin.ECKey(address);
        var addr = eckey.getBitcoinAddress().toString();
        return true;
      } catch (e) {
        return false;
      }
    };

    $scope.ok = function(result) {
      $modalInstance.close(result);
    };

    $scope.cancel = function() {
      $modalInstance.dismiss('cancel');
    };
  };
  // Done Import Private Key Form Code.
  // Begin Import Encrypted Key Form Code
  $scope.openImportEncryptedKeyForm = function() {
    var modalInstance = $modal.open({
      templateUrl: '/partials/import_encrypted_private.html',
      controller: AddEncryptedPrivateModal
    });

    modalInstance.result.then(function(result) {

      if (result.encryptedPrivKey && result.password) {
        // Decrypt key then store with default password of addr
        var key = Bitcoin.ECKey.decodeEncryptedFormat(result.encryptedPrivKey, result.password);
        var privkey = Bitcoin.Util.bytesToHex(key.getPrivateKeyByteArray());
        // Use address as passphrase for now
        var addr = decodeAddressFromPrivateKey(privkey);
        $injector.get('userService').addAddress(
        addr,
        encodePrivateKey(privkey, addr));
      }
      $scope.refresh();

    }, function() {});
  };

  var AddEncryptedPrivateModal = function($scope, $modalInstance) {
    $scope.ok = function(result) {
      $modalInstance.close(result);
    };

    $scope.cancel = function() {
      $modalInstance.dismiss('cancel');
    };
  };
  // Done Import Encrypted Private Key Code.

  // Begine Create Form Code.
  $scope.createBTCAddress = createBTCAddress;
  function createBTCAddress() {
    var ecKey = new Bitcoin.ECKey();
    var address = ecKey.getBitcoinAddress().toString();
    var encryptedPrivateKey = ecKey.getEncryptedFormat(address);
    $injector.get('userService').addAddress(address, encryptedPrivateKey);
    $scope.refresh();
  }
  ;
  // Done Create Form Code.
  // Begin Import Backup Form Code
  $scope.openImportWalletForm = function() {
    var modalInstance = $modal.open({
      templateUrl: '/partials/import_wallet.html',
      controller: ImportWalletModal
    });

    modalInstance.result.then(function(wallet){
      $scope.refresh();
    });
  };

  var ImportWalletModal = function($scope, $modalInstance, $q, $timeout) {
    $scope.summary = [];
    $scope.importFinished = false;
    $scope.startImport = function(walletData){
      $scope.validate(walletData).then(function(result){$scope.ok(result);},function(reason){$scope.progressMessage= reason;$scope.progressColor = "red";});
    };
    $scope.validate = function(backup) {
      var deferred = $q.defer();

      if (!backup) deferred.reject("No File");
      $scope.processing = true;
      try {
        var wallet = JSON.parse(backup);
        $scope.completed = 0;
        $scope.total = wallet.addresses.length;

        var next = function(){
          $timeout(function(){
            return validateAddress(wallet.addresses[$scope.completed]);
          },0,false);
        };
        var validated = {
          addresses : []
        };

        var validateAddress = function(address){
          $scope.$apply(function(){
            if($scope.completed == $scope.total){
              $scope.progressMessage = "Validated!";
              $scope.progressColor = "green";
              return deferred.resolve(validated);
            }

            try{
              var addr = address.address;
              if(address.privkey){
                var eckey = new Bitcoin.ECKey(address.privkey);
                addr = eckey.getBitcoinAddress().toString();
              }

              if(Bitcoin.Address.validate(addr)){
                validated.addresses.push(address);
                $scope.progressMessage = "Validated address " + addr;
                $scope.progressColor = "green";
              } else {
                $scope.progressMessage = "Invalid address " + addr;
                $scope.progressColor = "red";
              }
            } catch (e) {
              $scope.progressMessage = "Error validating "+addr+": " + e;
              $scope.progressColor = "red";
            }
            $scope.summary.push({message:$scope.progressMessage,color:$scope.progressColor});
            $scope.completed++;

            return next();
          });

        };

        // Start the loop
        next();

        deferred.notify("Validating...");
      } catch (e) {
        deferred.reject("Error during validation:" +e);
      }

      return deferred.promise;
    };

    $scope.ok = function(wallet) {
      if (wallet) {
        $scope.total = wallet.addresses.length;
        $scope.completed = 0;
        var next = function(){
          if($scope.completed < $scope.total) $scope.progressMessage="Importing address " + wallet.addresses[$scope.completed].address;
          $timeout(function(){
            return importAddress(wallet.addresses[$scope.completed]);
          },0,false);
        };

        var importAddress = function(addr){
          $scope.$apply(function(){
            if($scope.completed == $scope.total){
              $scope.importFinished = true;
              $scope.processing = false;
              return;
            }

            // Use address as passphrase for now
            if(addr.privkey)
              $injector.get('userService').addAddress(
                addr.address,
                encodePrivateKey(addr.privkey, addr.address))
                .then(function(){
                  $scope.progressMessage="Imported address " + addr.address;
                  $scope.progressColor = "green";

                  $scope.summary.push({message:$scope.progressMessage,color:$scope.progressColor});
                  $scope.completed++;
                  return next();
                });
            else
              $injector.get('userService').addAddress(
                addr.address)
                .then(function(){
                  $scope.progressMessage="Imported address " + addr.address;
                  $scope.progressColor = "green";

                  $scope.summary.push({message:$scope.progressMessage,color:$scope.progressColor});
                  $scope.completed++;
                  return next();
                });

          });
        };

        next();
      }
    };

    $scope.cancel = function() {
      $modalInstance.dismiss('cancel');
    };

    $scope.close = function() {
      $modalInstance.dismiss('close');
    };
  };
  // Done Import Import Backup Form Code.

  $scope.enumerateAddresses = function() {

    $scope.items = enumerated_addresses.getData().then(function(result) {
      if (result.addresses.length == 0) {
        createBTCAddress();
	      $scope.newAddress=true;
      }
      $scope.addresses = result.addresses;
    });
  };

});

<commit_msg>Fix export messages<commit_after>angular.module('omniwallet')
  .factory('enumerated_addresses', function($http, $q, $timeout, $injector) {
    var count = 1;
    return {
      "getData": function() {
        var deferred = $q.defer();

        _.defer(function() {
          var wallet = $injector.get('userService').getWallet();
          if (wallet && wallet.addresses.length > 0) {

            deferred.resolve({
              addresses: wallet.addresses
            });
          } else {
            deferred.resolve({
              addresses: []
            });
          }
        });
        return deferred.promise;
      }
    };
  })
  .controller('AddAddressController', function($modal, $injector, $scope, $timeout, userService, enumerated_addresses) {

  function decodeAddressFromPrivateKey(key) {

    //  Return the address decoded from the private key.
    var eckey = new Bitcoin.ECKey(key);
    var addr = eckey.getBitcoinAddress().toString();

    return addr;
  };

  function encodePrivateKey(key, passphrase) {

    //  Return encoded key.  Forget the passphrase forever.
    var eckey = new Bitcoin.ECKey(key);
    var enc = eckey.getEncryptedFormat(passphrase);

    return enc;
  };

  $scope.backupWallet = function() {
    $scope.login = {
      uuid: userService.data.wallet.uuid,
      action: 'verify',
      title: 'Verify Account',
      button: 'Validate',
      disable: true //disable UUID field in template
    };
    var modalInstance = $modal.open({
      templateUrl: '/partials/login_modal.html',
      controller: LoginController,
      scope: $scope
    });

    modalInstance.result.then(function(wallet) {
      $scope.exportData = {
        backupName : wallet.uuid,
        exportPrivate : true,
        exportWatch : true
      };
      $scope.exportInProgress=false;
      var exportModalInstance = $modal.open({
        templateUrl: '/partials/export_wallet.html',
        controller: function($scope, $modalInstance, wallet){
          $scope.summary = [];
          $scope.exportFinished = false;
          $scope.exportWallet = function(exportData){
            $scope.exportInProgress=true;
            $scope.exported = 0;
            var walletAddresses = wallet.addresses;
            $scope.total = walletAddresses.length;
            var blob = {
              addresses: []
            };

            var next = function(){
              $timeout(function(){
                return exportAddress(walletAddresses[$scope.exported]);
              },0,false);
            };

            var exportAddress = function(obj){
              $scope.$apply(function(){
                if($scope.exported == $scope.total) {
                  var exportBlob = new Blob([JSON.stringify(blob)], {
                    type: 'application/json;charset=utf-8'
                  });
                  fileName=exportData.backupName+".json";
                  saveAs(exportBlob, fileName);
                  $scope.exportInProgress = false;
                  return $scope.exportFinished = true;
                }

                try{
                  if(exportData.exportPrivate && obj.privkey) {
                    var ecKey = Bitcoin.ECKey.decodeEncryptedFormat(obj.privkey, obj.address);
                    var addr = ecKey.getBitcoinAddress().toString();
                    var key = ecKey.getWalletImportFormat();
                    blob.addresses.push({ address: addr, privkey: key });
                    $scope.progressMessage = "Exported trading address " + addr;
                    $scope.progressColor = "green";
                  }
                  if(exportData.exportWatch && !obj.privkey) {
                    blob.addresses.push({ address: obj.address, privkey: "" });
                    $scope.progressMessage = "Exported watch address " + obj.address;
                    $scope.progressColor = "green";
                  }
                } catch (e) {
                  $scope.progressMessage = "Error exporting "+obj.address+": " + e;
                  $scope.progressColor = "red";
                }
                $scope.summary.push({color:$scope.progressColor,message: $scope.progressMessage});
                $scope.exported++;

                return next();
              });
            };

            // Start the loop
            next();
          };

          $scope.cancel = function() {
            $modalInstance.dismiss('cancel');
          };

          $scope.close = function() {
            $modalInstance.dismiss('close');
          };
        },
        scope: $scope,
        resolve:{
          wallet: function(){
            return wallet;
          }
        }
      });
    });
  };

  // Begin Import watch only Form Code
  $scope.openImportWatchOnlyForm = function() {
    var modalInstance = $modal.open({
      templateUrl: '/partials/import_watch_only.html',
      controller: AddBtcAddressModal
    });

    modalInstance.result.then(function(result) {

      if (result.address) {
        $injector.get('userService').addAddress(result.address);
      }
      $scope.refresh();

    }, function() {});
  };

  var AddBtcAddressModal = function($scope, $modalInstance) {
    $scope.validate = function(address) {
      return Bitcoin.Address.validate(address);
    };

    $scope.addressNotListed = function(address) {
      var addresses = $injector.get('userService').getAllAddresses();
      for (var i in addresses) {
        if (addresses[i].address == address) {
          return false;
        }
      }

      return true;
    };

    $scope.ok = function(result) {
      if (Bitcoin.Address.validate(result.address))
        $modalInstance.close(result);
      else
        console.log('*** Invalid address: ' + result.address);
    };

    $scope.cancel = function() {
      $modalInstance.dismiss('cancel');
    };
  };
  // Done Import Watch Only Form Code.

  // Begin Import Private Key Form Code
  $scope.openImportPrivateKeyForm = function() {
    var modalInstance = $modal.open({
      templateUrl: '/partials/import_private.html',
      controller: AddPrivateKeyModal
    });

    modalInstance.result.then(function(result) {

      if (result.privKey) {
        // Use address as passphrase for now
        var addr = decodeAddressFromPrivateKey(result.privKey);
        $injector.get('userService').addAddress(
        addr,
        encodePrivateKey(result.privKey, addr));
      }
      $scope.refresh();

    }, function() {});
  };

  var AddPrivateKeyModal = function($scope, $modalInstance) {
    $scope.validate = function(address) {
      if (!address) return false;

      try {
        var eckey = new Bitcoin.ECKey(address);
        var addr = eckey.getBitcoinAddress().toString();
        return true;
      } catch (e) {
        return false;
      }
    };

    $scope.ok = function(result) {
      $modalInstance.close(result);
    };

    $scope.cancel = function() {
      $modalInstance.dismiss('cancel');
    };
  };
  // Done Import Private Key Form Code.
  // Begin Import Encrypted Key Form Code
  $scope.openImportEncryptedKeyForm = function() {
    var modalInstance = $modal.open({
      templateUrl: '/partials/import_encrypted_private.html',
      controller: AddEncryptedPrivateModal
    });

    modalInstance.result.then(function(result) {

      if (result.encryptedPrivKey && result.password) {
        // Decrypt key then store with default password of addr
        var key = Bitcoin.ECKey.decodeEncryptedFormat(result.encryptedPrivKey, result.password);
        var privkey = Bitcoin.Util.bytesToHex(key.getPrivateKeyByteArray());
        // Use address as passphrase for now
        var addr = decodeAddressFromPrivateKey(privkey);
        $injector.get('userService').addAddress(
        addr,
        encodePrivateKey(privkey, addr));
      }
      $scope.refresh();

    }, function() {});
  };

  var AddEncryptedPrivateModal = function($scope, $modalInstance) {
    $scope.ok = function(result) {
      $modalInstance.close(result);
    };

    $scope.cancel = function() {
      $modalInstance.dismiss('cancel');
    };
  };
  // Done Import Encrypted Private Key Code.

  // Begine Create Form Code.
  $scope.createBTCAddress = createBTCAddress;
  function createBTCAddress() {
    var ecKey = new Bitcoin.ECKey();
    var address = ecKey.getBitcoinAddress().toString();
    var encryptedPrivateKey = ecKey.getEncryptedFormat(address);
    $injector.get('userService').addAddress(address, encryptedPrivateKey);
    $scope.refresh();
  }
  ;
  // Done Create Form Code.
  // Begin Import Backup Form Code
  $scope.openImportWalletForm = function() {
    var modalInstance = $modal.open({
      templateUrl: '/partials/import_wallet.html',
      controller: ImportWalletModal
    });

    modalInstance.result.then(function(wallet){
      $scope.refresh();
    });
  };

  var ImportWalletModal = function($scope, $modalInstance, $q, $timeout) {
    $scope.summary = [];
    $scope.importFinished = false;
    $scope.startImport = function(walletData){
      $scope.validate(walletData).then(function(result){$scope.ok(result);},function(reason){$scope.progressMessage= reason;$scope.progressColor = "red";});
    };
    $scope.validate = function(backup) {
      var deferred = $q.defer();

      if (!backup) deferred.reject("No File");
      $scope.processing = true;
      try {
        var wallet = JSON.parse(backup);
        $scope.completed = 0;
        $scope.total = wallet.addresses.length;

        var next = function(){
          $timeout(function(){
            return validateAddress(wallet.addresses[$scope.completed]);
          },0,false);
        };
        var validated = {
          addresses : []
        };

        var validateAddress = function(address){
          $scope.$apply(function(){
            if($scope.completed == $scope.total){
              $scope.progressMessage = "Validated!";
              $scope.progressColor = "green";
              return deferred.resolve(validated);
            }

            try{
              var addr = address.address;
              if(address.privkey){
                var eckey = new Bitcoin.ECKey(address.privkey);
                addr = eckey.getBitcoinAddress().toString();
              }

              if(Bitcoin.Address.validate(addr)){
                validated.addresses.push(address);
                $scope.progressMessage = "Validated address " + addr;
                $scope.progressColor = "green";
              } else {
                $scope.progressMessage = "Invalid address " + addr;
                $scope.progressColor = "red";
              }
            } catch (e) {
              $scope.progressMessage = "Error validating "+addr+": " + e;
              $scope.progressColor = "red";
            }
            $scope.summary.push({message:$scope.progressMessage,color:$scope.progressColor});
            $scope.completed++;

            return next();
          });

        };

        // Start the loop
        next();

        deferred.notify("Validating...");
      } catch (e) {
        deferred.reject("Error during validation:" +e);
      }

      return deferred.promise;
    };

    $scope.ok = function(wallet) {
      if (wallet) {
        $scope.total = wallet.addresses.length;
        $scope.completed = 0;
        var next = function(){
          if($scope.completed < $scope.total) $scope.progressMessage="Importing address " + wallet.addresses[$scope.completed].address;
          $timeout(function(){
            return importAddress(wallet.addresses[$scope.completed]);
          },0,false);
        };

        var importAddress = function(addr){
          $scope.$apply(function(){
            if($scope.completed == $scope.total){
              $scope.importFinished = true;
              $scope.processing = false;
              return;
            }

            // Use address as passphrase for now
            if(addr.privkey)
              $injector.get('userService').addAddress(
                addr.address,
                encodePrivateKey(addr.privkey, addr.address))
                .then(function(){
                  $scope.progressMessage="Imported address " + addr.address;
                  $scope.progressColor = "green";

                  $scope.summary.push({message:$scope.progressMessage,color:$scope.progressColor});
                  $scope.completed++;
                  return next();
                });
            else
              $injector.get('userService').addAddress(
                addr.address)
                .then(function(){
                  $scope.progressMessage="Imported address " + addr.address;
                  $scope.progressColor = "green";

                  $scope.summary.push({message:$scope.progressMessage,color:$scope.progressColor});
                  $scope.completed++;
                  return next();
                });

          });
        };

        next();
      }
    };

    $scope.cancel = function() {
      $modalInstance.dismiss('cancel');
    };

    $scope.close = function() {
      $modalInstance.dismiss('close');
    };
  };
  // Done Import Import Backup Form Code.

  $scope.enumerateAddresses = function() {

    $scope.items = enumerated_addresses.getData().then(function(result) {
      if (result.addresses.length == 0) {
        createBTCAddress();
	      $scope.newAddress=true;
      }
      $scope.addresses = result.addresses;
    });
  };

});

<|endoftext|>


<commit_before>var pk = pk || {};
(function(pk) {
    pk.drag = function(opt) {
        var el = opt.element;
        var handle = opt.handle || opt.element;
        var container = {
            element: opt.container && opt.container.element ? opt.container.element : document.body,
            style: opt.container && opt.container.style ? opt.container.style : 'restrict'
        };

        pk.addClass(handle, 'pk-drag');
        var fn = opt.listeners;
        var m = opt.move;
        if (m && typeof m !== 'object') {
            m = {
                x: true,
                y: true
            };
        }
        var dragging = false;
        var dragStart = {};
        var startOffset;
        var containerD = {};
        var elD = {};

        function augmentEvent(e) {

            e.dragStart = dragStart;
            e.dragOffset = startOffset;

            e.dragEnd = {
                x: e.clientX,
                y: e.clientY
            };
            e.dragDist = {
                x: e.dragEnd.x - e.dragStart.x,
                y: e.dragEnd.y - e.dragStart.y
            };
            e.dragPerc = {
                x: (pk.layout(el).left + e.dragDist.x + e.dragOffset.x) / pk.layout(container.element).width,
                y: (pk.layout(el).top + e.dragDist.y + e.dragOffset.y) / pk.layout(container.element).height
            };
            return e;
        }

        pk.bindEvent("mousedown", handle, function(e) {
            dragging = true;
            dragStart = {
                x: e.clientX,
                y: e.clientY
            };
            startOffset = {
                x: e.clientX - el.getBoundingClientRect().left,
                y: e.clientY - el.getBoundingClientRect().top
            };
            e = augmentEvent(e);
            pk.addClass(handle, 'pk-drag-dragging');
            pk.addClass(document.body, 'pk-noselect');
            document.onselectstart = function() {
                return false;
            };
            containerD = pk.layout(container.element);
            elD = pk.layout(el);
            if (fn && fn.dragstart) {
                fn.dragstart(el, e);
            }
        });
        pk.bindEvent("mouseup", window, function(e) {
            if (!dragging) {
                return;
            }
            dragging = false;
            e = augmentEvent(e);
            pk.removeClass(handle, 'pk-drag-dragging');
            pk.removeClass(document.body, 'pk-noselect');
            document.onselectstart = function() {
                return true;
            };
            if (m && container.style === "snap") {
                contain();
            }
            if (fn && fn.dragend) {
                fn.dragend(el, e);
            }
        });

        function contain() {

            var h = container.element.tagName === "BODY" ? document.documentElement.clientHeight : container.element.offsetHeight,
                w = container.element.tagName === "BODY" ? document.documentElement.clientWidth : container.element.offsetWidth;

            if (m.x && el.offsetLeft < 0) {
                el.style.left = 0 + 'px';
            } else if (m.x && el.offsetLeft > w - el.offsetWidth) {
                el.style.left = w - el.offsetWidth + 'px';
            }
            if (m.y && el.offsetTop < 0) {
                el.style.top = 0 + 'px';
            } else if (m.y && el.offsetTop > h - el.offsetHeight) {
                el.style.top = h - el.offsetHeight + 'px';
            }
        }
        pk.bindEvent("mousemove", window, function(e) {
            if (!dragging) {
                return;
            }
            e = augmentEvent(e);
            if (m.x) {
                el.style.left = el.offsetLeft + (e.dragEnd.x - el.getBoundingClientRect().left) - e.dragOffset.x + 'px';
            }
            if (m.y) {
                el.style.top = el.offsetTop + (e.dragEnd.y - el.getBoundingClientRect().top) - e.dragOffset.y + 'px';
            }
            if (container.style === "restrict") {
                contain();
            }
            if (fn && fn.dragging) {
                fn.dragging(el, e);
            }
        });
    };
})(pk);
<commit_msg>Update drag.js<commit_after>var pk = pk || {};
(function(pk) {
    pk.drag = function(opt) {
        var el = opt.element;
        var handle = opt.handle || opt.element;
        var container = {
            element: opt.container && opt.container.element ? opt.container.element : document.body,
            style: opt.container && opt.container.style ? opt.container.style : 'restrict'
        };

        pk.addClass(handle, 'pk-drag');
        var fn = opt.listeners;
        var m = opt.move;
        if (m && typeof m !== 'object') {
            m = {
                x: true,
                y: true
            };
        }
        var dragging = false;
        var dragStart = {};
        var startOffset;
        var containerD = {};
        var elD = {};

        function augmentEvent(e) {

            e.dragStart = dragStart;
            e.dragOffset = startOffset;

            e.dragEnd = {
                x: e.clientX,
                y: e.clientY
            };
            e.dragDist = {
                x: e.dragEnd.x - e.dragStart.x,
                y: e.dragEnd.y - e.dragStart.y
            };
            e.dragPerc = {
                x: (pk.layout(el).left + e.dragDist.x + e.dragOffset.x) / pk.layout(container.element).width,
                y: (pk.layout(el).top + e.dragDist.y + e.dragOffset.y) / pk.layout(container.element).height
            };
            return e;
        }

        pk.bindEvent("mousedown", handle, function(e) {
            dragging = true;
            dragStart = {
                x: e.clientX,
                y: e.clientY
            };
            startOffset = {
                x: e.clientX - el.getBoundingClientRect().left,
                y: e.clientY - el.getBoundingClientRect().top
            };
            e = augmentEvent(e);
            pk.addClass(handle, 'pk-drag-dragging');
            pk.addClass(document.body, 'pk-noselect');
            document.onselectstart = function() {
                return false;
            };
            containerD = pk.layout(container.element);
            elD = pk.layout(el);
            if (fn && fn.dragstart) {
                fn.dragstart(el, e);
            }
        });
        pk.bindEvent("mouseup", window, function(e) {
            if (!dragging) {
                return;
            }
            dragging = false;
            e = augmentEvent(e);
            pk.removeClass(handle, 'pk-drag-dragging');
            pk.removeClass(document.body, 'pk-noselect');
            document.onselectstart = function() {
                return true;
            };
            if (m && container.style === "snap") {
                contain();
            }
            if (fn && fn.dragend) {
                fn.dragend(el, e);
            }
        });

        function contain() {

            var h = container.element.tagName === "BODY" ? document.documentElement.clientHeight : container.element.offsetHeight,
                w = container.element.tagName === "BODY" ? document.documentElement.clientWidth : container.element.offsetWidth,
				oX = container.style.x || 0, oY = container.style.y || 0;

            if (m.x && el.offsetLeft < (0 + oX)) {
                el.style.left = (0 + oX) + 'px';
            } else if (m.x && el.offsetLeft > w - el.offsetWidth - oX) {
                el.style.left = w - el.offsetWidth - oX + 'px';
            }
            if (m.y && el.offsetTop < (0 + oY)) {
                el.style.top = (0 + oY) + 'px';
            } else if (m.y && el.offsetTop > h - el.offsetHeight - oY) {
                el.style.top = h - el.offsetHeight - oY + 'px';
            }
        }
        pk.bindEvent("mousemove", window, function(e) {
            if (!dragging) {
                return;
            }
            e = augmentEvent(e);
            if (m.x) {
                el.style.left = el.offsetLeft + (e.dragEnd.x - el.getBoundingClientRect().left) - e.dragOffset.x + 'px';
            }
            if (m.y) {
                el.style.top = el.offsetTop + (e.dragEnd.y - el.getBoundingClientRect().top) - e.dragOffset.y + 'px';
            }
            if (container.style === "restrict" || (container.style.x && container.style.y)) {
                contain();
            }
            if (fn && fn.dragging) {
                fn.dragging(el, e);
            }
        });
    };
})(pk);
<|endoftext|>


<commit_before>/**
 * Created by dailer on 2019/6/19.
 */
!(function () {
    BI.AbstractLabel = BI.inherit(BI.Single, {

        _defaultConfig: function (props) {
            var conf = BI.AbstractLabel.superclass._defaultConfig.apply(this, arguments);
            return BI.extend(conf, {
                textAlign: "center",
                whiteSpace: "nowrap", // normal  or  nowrap
                textWidth: null,
                textHeight: null,
                hgap: 0,
                vgap: 0,
                lgap: 0,
                rgap: 0,
                tgap: 0,
                bgap: 0,
                highLight: false,
                handler: null
            });
        },

        _createJson: function () {
            var o = this.options;
            return {
                type: "bi.text",
                textAlign: o.textAlign,
                whiteSpace: o.whiteSpace,
                lineHeight: o.textHeight,
                text: o.text,
                value: o.value,
                py: o.py,
                keyword: o.keyword,
                highLight: o.highLight,
                handler: o.handler
            };
        },

        _init: function () {
            BI.AbstractLabel.superclass._init.apply(this, arguments);

            if (this.options.textAlign === "center") {
                this._createCenterEl();
            } else {
                this._createNotCenterEl();
            }
        },

        _createCenterEl: function () {
            var o = this.options;
            var json = this._createJson();
            json.textAlign = "left";
            if (BI.isNumber(o.width) && o.width > 0) {
                if (BI.isNumber(o.textWidth) && o.textWidth > 0) {
                    json.maxWidth = o.textWidth;
                    if (BI.isNumber(o.height) && o.height > 0) { // 1.1
                        BI.createWidget({
                            type: "bi.center_adapt",
                            height: o.height,
                            columnSize: [o.whiteSpace === "normal" ? "auto" : ""], // important！ 让文字在normal下shrink为1
                            scrollable: o.whiteSpace === "normal",
                            element: this,
                            items: [
                                {
                                    el: (this.text = BI.createWidget(json))
                                }
                            ]
                        });
                        return;
                    }
                    BI.createWidget({ // 1.2
                        type: "bi.center_adapt",
                        columnSize: [o.whiteSpace === "normal" ? "auto" : ""], // important！ 让文字在normal下shrink为1
                        scrollable: o.whiteSpace === "normal",
                        element: this,
                        items: [
                            {
                                el: (this.text = BI.createWidget(json))
                            }
                        ]
                    });
                    return;
                }
                if (o.whiteSpace == "normal") { // 1.3
                    BI.extend(json, {
                        hgap: o.hgap,
                        vgap: o.vgap,
                        lgap: o.lgap,
                        rgap: o.rgap,
                        tgap: o.tgap,
                        bgap: o.bgap
                    });
                    this.text = BI.createWidget(json);
                    BI.createWidget({
                        type: "bi.center_adapt",
                        columnSize: [o.whiteSpace === "normal" ? "auto" : ""], // important！ 让文字在normal下shrink为1
                        scrollable: o.whiteSpace === "normal",
                        element: this,
                        items: [this.text]
                    });
                    return;
                }
                if (BI.isNumber(o.height) && o.height > 0) { // 1.4
                    this.element.css({
                        "line-height": o.height / BI.pixRatio + BI.pixUnit
                    });
                    json.textAlign = o.textAlign;
                    this.text = BI.createWidget(BI.extend(json, {
                        element: this,
                        hgap: o.hgap,
                        vgap: o.vgap,
                        lgap: o.lgap,
                        rgap: o.rgap,
                        tgap: o.tgap,
                        bgap: o.bgap
                    }));
                    return;
                }
                BI.extend(json, { // 1.5
                    hgap: o.hgap,
                    vgap: o.vgap,
                    lgap: o.lgap,
                    rgap: o.rgap,
                    tgap: o.tgap,
                    bgap: o.bgap,
                    maxWidth: "100%"
                });
                this.text = BI.createWidget(json);
                BI.createWidget({
                    type: "bi.center_adapt",
                    columnSize: [o.whiteSpace === "normal" ? "auto" : ""], // important！ 让文字在normal下shrink为1
                    scrollable: o.whiteSpace === "normal",
                    element: this,
                    items: [this.text]
                });
                return;
            }
            if (BI.isNumber(o.textWidth) && o.textWidth > 0) {  // 1.6
                json.maxWidth = o.textWidth;
                BI.createWidget({
                    type: "bi.center_adapt",
                    columnSize: [o.whiteSpace === "normal" ? "auto" : ""], // important！ 让文字在normal下shrink为1
                    scrollable: o.whiteSpace === "normal",
                    element: this,
                    items: [
                        {
                            el: (this.text = BI.createWidget(json))
                        }
                    ]
                });
                return;
            }
            if (o.whiteSpace == "normal") { // 1.7
                BI.extend(json, {
                    hgap: o.hgap,
                    vgap: o.vgap,
                    lgap: o.lgap,
                    rgap: o.rgap,
                    tgap: o.tgap,
                    bgap: o.bgap
                });
                this.text = BI.createWidget(json);
                BI.createWidget({
                    type: "bi.center_adapt",
                    columnSize: [o.whiteSpace === "normal" ? "auto" : ""], // important！ 让文字在normal下shrink为1
                    scrollable: true,
                    element: this,
                    items: [this.text]
                });
                return;
            }
            if (BI.isNumber(o.height) && o.height > 0) { // 1.8
                this.element.css({
                    "line-height": o.height / BI.pixRatio + BI.pixUnit
                });
                json.textAlign = o.textAlign;
                this.text = BI.createWidget(BI.extend(json, {
                    element: this,
                    hgap: o.hgap,
                    vgap: o.vgap,
                    lgap: o.lgap,
                    rgap: o.rgap,
                    tgap: o.tgap,
                    bgap: o.bgap
                }));
                return;
            }
            BI.extend(json, {
                hgap: o.hgap,
                vgap: o.vgap,
                lgap: o.lgap,
                rgap: o.rgap,
                tgap: o.tgap,
                bgap: o.bgap
            });

            this.text = BI.createWidget(BI.extend(json, {
                maxWidth: "100%"
            }));
            BI.createWidget({
                type: "bi.center_adapt",
                columnSize: [o.whiteSpace === "normal" ? "auto" : ""], // important！ 让文字在normal下shrink为1
                element: this,
                items: [this.text]
            });
        },

        _createNotCenterEl: function () {
            var o = this.options;
            var adaptLayout = "bi.vertical_adapt";
            var json = this._createJson();
            if (BI.isNumber(o.width) && o.width > 0) {
                if (BI.isNumber(o.textWidth) && o.textWidth > 0) {
                    json.width = o.textWidth;
                    if (BI.isNumber(o.height) && o.height > 0) { // 2.1
                        BI.createWidget({
                            type: adaptLayout,
                            horizontalAlign: o.textAlign,
                            columnSize: [o.whiteSpace === "normal" ? "auto" : ""], // important！ 让文字在normal下shrink为1
                            height: o.height,
                            scrollable: o.whiteSpace === "normal",
                            element: this,
                            items: [
                                {
                                    el: (this.text = BI.createWidget(json))
                                }
                            ]
                        });
                        return;
                    }
                    BI.createWidget({ // 2.2
                        type: adaptLayout,
                        horizontalAlign: o.textAlign,
                        columnSize: [o.whiteSpace === "normal" ? "auto" : ""], // important！ 让文字在normal下shrink为1
                        scrollable: o.whiteSpace === "normal",
                        hgap: o.hgap,
                        vgap: o.vgap,
                        lgap: o.lgap,
                        rgap: o.rgap,
                        tgap: o.tgap,
                        bgap: o.bgap,
                        element: this,
                        items: [
                            {
                                el: (this.text = BI.createWidget(json))
                            }
                        ]
                    });
                    return;
                }
                if (BI.isNumber(o.height) && o.height > 0) { // 2.3
                    this.text = BI.createWidget(BI.extend(json, {
                        element: this,
                        hgap: o.hgap,
                        vgap: o.vgap,
                        lgap: o.lgap,
                        rgap: o.rgap,
                        tgap: o.tgap,
                        bgap: o.bgap
                    }));
                    if (o.whiteSpace !== "normal") {
                        this.element.css({
                            "line-height": (o.height - (o.vgap * 2)) / BI.pixRatio + BI.pixUnit
                        });
                    }
                    return;
                }
                json.width = o.width - 2 * o.hgap - o.lgap - o.rgap;
                BI.createWidget({ // 2.4
                    type: adaptLayout,
                    horizontalAlign: o.textAlign,
                    columnSize: [o.whiteSpace === "normal" ? "auto" : ""], // important！ 让文字在normal下shrink为1
                    scrollable: o.whiteSpace === "normal",
                    hgap: o.hgap,
                    vgap: o.vgap,
                    lgap: o.lgap,
                    rgap: o.rgap,
                    tgap: o.tgap,
                    bgap: o.bgap,
                    element: this,
                    items: [{
                        el: (this.text = BI.createWidget(json))
                    }]
                });
                return;
            }
            if (BI.isNumber(o.textWidth) && o.textWidth > 0) {
                json.width = o.textWidth;
                BI.createWidget({  // 2.5
                    type: adaptLayout,
                    horizontalAlign: o.textAlign,
                    columnSize: [o.whiteSpace === "normal" ? "auto" : ""], // important！ 让文字在normal下shrink为1
                    scrollable: o.whiteSpace === "normal",
                    hgap: o.hgap,
                    vgap: o.vgap,
                    lgap: o.lgap,
                    rgap: o.rgap,
                    tgap: o.tgap,
                    bgap: o.bgap,
                    element: this,
                    items: [
                        {
                            el: (this.text = BI.createWidget(json))
                        }
                    ]
                });
                return;
            }
            if (BI.isNumber(o.height) && o.height > 0) {
                if (o.whiteSpace !== "normal") {
                    this.element.css({
                        "line-height": (o.height - (o.vgap * 2)) / BI.pixRatio + BI.pixUnit
                    });
                }
                this.text = BI.createWidget(BI.extend(json, { // 2.6
                    element: this,
                    hgap: o.hgap,
                    vgap: o.vgap,
                    lgap: o.lgap,
                    rgap: o.rgap,
                    tgap: o.tgap,
                    bgap: o.bgap
                }));
                return;
            }
            BI.extend(json, {
                hgap: o.hgap,
                vgap: o.vgap,
                lgap: o.lgap,
                rgap: o.rgap,
                tgap: o.tgap,
                bgap: o.bgap
            });

            this.text = BI.createWidget(BI.extend(json, {
                maxWidth: "100%"
            }));
            BI.createWidget({
                type: adaptLayout,
                horizontalAlign: o.textAlign,
                columnSize: [o.whiteSpace === "normal" ? "auto" : ""], // important！ 让文字在normal下shrink为1
                element: this,
                scrollable: o.whiteSpace === "normal",
                items: [this.text]
            });
        },

        doRedMark: function () {
            this.text.doRedMark.apply(this.text, arguments);
        },

        unRedMark: function () {
            this.text.unRedMark.apply(this.text, arguments);
        },

        doHighLight: function () {
            this.text.doHighLight.apply(this.text, arguments);
        },

        unHighLight: function () {
            this.text.unHighLight.apply(this.text, arguments);
        },

        setText: function (v) {
            this.options.text = v;
            this.text.setText(v);
        },

        getText: function () {
            return this.options.text;
        },

        setStyle: function (css) {
            this.text.setStyle(css);
        },

        setValue: function (v) {
            BI.AbstractLabel.superclass.setValue.apply(this, arguments);
            if (!this.isReadOnly()) {
                this.text.setValue(v);
            }
        },

        populate: function () {
            BI.AbstractLabel.superclass.populate.apply(this, arguments);
        }
    });
}());
<commit_msg>Pull request #1766: 无JIRA任务 bugfix<commit_after>/**
 * Created by dailer on 2019/6/19.
 */
!(function () {
    BI.AbstractLabel = BI.inherit(BI.Single, {

        _defaultConfig: function (props) {
            var conf = BI.AbstractLabel.superclass._defaultConfig.apply(this, arguments);
            return BI.extend(conf, {
                textAlign: "center",
                whiteSpace: "nowrap", // normal  or  nowrap
                textWidth: null,
                textHeight: null,
                hgap: 0,
                vgap: 0,
                lgap: 0,
                rgap: 0,
                tgap: 0,
                bgap: 0,
                highLight: false,
                handler: null
            });
        },

        _createJson: function () {
            var o = this.options;
            return {
                type: "bi.text",
                textAlign: o.textAlign,
                whiteSpace: o.whiteSpace,
                lineHeight: o.textHeight,
                text: o.text,
                value: o.value,
                py: o.py,
                keyword: o.keyword,
                highLight: o.highLight,
                handler: o.handler
            };
        },

        _init: function () {
            BI.AbstractLabel.superclass._init.apply(this, arguments);

            if (this.options.textAlign === "center") {
                this._createCenterEl();
            } else {
                this._createNotCenterEl();
            }
        },

        _createCenterEl: function () {
            var o = this.options;
            var json = this._createJson();
            json.textAlign = "left";
            if (BI.isNumber(o.width) && o.width > 0) {
                if (BI.isNumber(o.textWidth) && o.textWidth > 0) {
                    json.maxWidth = o.textWidth;
                    if (BI.isNumber(o.height) && o.height > 0) { // 1.1
                        BI.createWidget({
                            type: "bi.center_adapt",
                            height: o.height,
                            columnSize: ["auto"], // important！ 让文字在flex布局下shrink为1
                            scrollable: o.whiteSpace === "normal",
                            element: this,
                            items: [
                                {
                                    el: (this.text = BI.createWidget(json))
                                }
                            ]
                        });
                        return;
                    }
                    BI.createWidget({ // 1.2
                        type: "bi.center_adapt",
                        columnSize: ["auto"], // important！ 让文字在flex布局下shrink为1
                        scrollable: o.whiteSpace === "normal",
                        element: this,
                        items: [
                            {
                                el: (this.text = BI.createWidget(json))
                            }
                        ]
                    });
                    return;
                }
                if (o.whiteSpace == "normal") { // 1.3
                    BI.extend(json, {
                        hgap: o.hgap,
                        vgap: o.vgap,
                        lgap: o.lgap,
                        rgap: o.rgap,
                        tgap: o.tgap,
                        bgap: o.bgap
                    });
                    this.text = BI.createWidget(json);
                    BI.createWidget({
                        type: "bi.center_adapt",
                        columnSize: ["auto"], // important！ 让文字在flex布局下shrink为1
                        scrollable: o.whiteSpace === "normal",
                        element: this,
                        items: [this.text]
                    });
                    return;
                }
                if (BI.isNumber(o.height) && o.height > 0) { // 1.4
                    this.element.css({
                        "line-height": o.height / BI.pixRatio + BI.pixUnit
                    });
                    json.textAlign = o.textAlign;
                    this.text = BI.createWidget(BI.extend(json, {
                        element: this,
                        hgap: o.hgap,
                        vgap: o.vgap,
                        lgap: o.lgap,
                        rgap: o.rgap,
                        tgap: o.tgap,
                        bgap: o.bgap
                    }));
                    return;
                }
                BI.extend(json, { // 1.5
                    hgap: o.hgap,
                    vgap: o.vgap,
                    lgap: o.lgap,
                    rgap: o.rgap,
                    tgap: o.tgap,
                    bgap: o.bgap,
                    maxWidth: "100%"
                });
                this.text = BI.createWidget(json);
                BI.createWidget({
                    type: "bi.center_adapt",
                    columnSize: ["auto"], // important！ 让文字在flex布局下shrink为1
                    scrollable: o.whiteSpace === "normal",
                    element: this,
                    items: [this.text]
                });
                return;
            }
            if (BI.isNumber(o.textWidth) && o.textWidth > 0) {  // 1.6
                json.maxWidth = o.textWidth;
                BI.createWidget({
                    type: "bi.center_adapt",
                    columnSize: ["auto"], // important！ 让文字在flex布局下shrink为1
                    scrollable: o.whiteSpace === "normal",
                    element: this,
                    items: [
                        {
                            el: (this.text = BI.createWidget(json))
                        }
                    ]
                });
                return;
            }
            if (o.whiteSpace == "normal") { // 1.7
                BI.extend(json, {
                    hgap: o.hgap,
                    vgap: o.vgap,
                    lgap: o.lgap,
                    rgap: o.rgap,
                    tgap: o.tgap,
                    bgap: o.bgap
                });
                this.text = BI.createWidget(json);
                BI.createWidget({
                    type: "bi.center_adapt",
                    columnSize: ["auto"], // important！ 让文字在flex布局下shrink为1
                    scrollable: true,
                    element: this,
                    items: [this.text]
                });
                return;
            }
            if (BI.isNumber(o.height) && o.height > 0) { // 1.8
                this.element.css({
                    "line-height": o.height / BI.pixRatio + BI.pixUnit
                });
                json.textAlign = o.textAlign;
                this.text = BI.createWidget(BI.extend(json, {
                    element: this,
                    hgap: o.hgap,
                    vgap: o.vgap,
                    lgap: o.lgap,
                    rgap: o.rgap,
                    tgap: o.tgap,
                    bgap: o.bgap
                }));
                return;
            }
            BI.extend(json, {
                hgap: o.hgap,
                vgap: o.vgap,
                lgap: o.lgap,
                rgap: o.rgap,
                tgap: o.tgap,
                bgap: o.bgap
            });

            this.text = BI.createWidget(BI.extend(json, {
                maxWidth: "100%"
            }));
            BI.createWidget({
                type: "bi.center_adapt",
                columnSize: ["auto"], // important！ 让文字在flex布局下shrink为1
                element: this,
                items: [this.text]
            });
        },

        _createNotCenterEl: function () {
            var o = this.options;
            var adaptLayout = "bi.vertical_adapt";
            var json = this._createJson();
            if (BI.isNumber(o.width) && o.width > 0) {
                if (BI.isNumber(o.textWidth) && o.textWidth > 0) {
                    json.width = o.textWidth;
                    if (BI.isNumber(o.height) && o.height > 0) { // 2.1
                        BI.createWidget({
                            type: adaptLayout,
                            horizontalAlign: o.textAlign,
                            columnSize: ["auto"], // important！ 让文字在flex布局下shrink为1
                            height: o.height,
                            scrollable: o.whiteSpace === "normal",
                            element: this,
                            items: [
                                {
                                    el: (this.text = BI.createWidget(json))
                                }
                            ]
                        });
                        return;
                    }
                    BI.createWidget({ // 2.2
                        type: adaptLayout,
                        horizontalAlign: o.textAlign,
                        columnSize: ["auto"], // important！ 让文字在flex布局下shrink为1
                        scrollable: o.whiteSpace === "normal",
                        hgap: o.hgap,
                        vgap: o.vgap,
                        lgap: o.lgap,
                        rgap: o.rgap,
                        tgap: o.tgap,
                        bgap: o.bgap,
                        element: this,
                        items: [
                            {
                                el: (this.text = BI.createWidget(json))
                            }
                        ]
                    });
                    return;
                }
                if (BI.isNumber(o.height) && o.height > 0) { // 2.3
                    this.text = BI.createWidget(BI.extend(json, {
                        element: this,
                        hgap: o.hgap,
                        vgap: o.vgap,
                        lgap: o.lgap,
                        rgap: o.rgap,
                        tgap: o.tgap,
                        bgap: o.bgap
                    }));
                    if (o.whiteSpace !== "normal") {
                        this.element.css({
                            "line-height": (o.height - (o.vgap * 2)) / BI.pixRatio + BI.pixUnit
                        });
                    }
                    return;
                }
                json.width = o.width - 2 * o.hgap - o.lgap - o.rgap;
                BI.createWidget({ // 2.4
                    type: adaptLayout,
                    horizontalAlign: o.textAlign,
                    columnSize: ["auto"], // important！ 让文字在flex布局下shrink为1
                    scrollable: o.whiteSpace === "normal",
                    hgap: o.hgap,
                    vgap: o.vgap,
                    lgap: o.lgap,
                    rgap: o.rgap,
                    tgap: o.tgap,
                    bgap: o.bgap,
                    element: this,
                    items: [{
                        el: (this.text = BI.createWidget(json))
                    }]
                });
                return;
            }
            if (BI.isNumber(o.textWidth) && o.textWidth > 0) {
                json.width = o.textWidth;
                BI.createWidget({  // 2.5
                    type: adaptLayout,
                    horizontalAlign: o.textAlign,
                    columnSize: ["auto"], // important！ 让文字在flex布局下shrink为1
                    scrollable: o.whiteSpace === "normal",
                    hgap: o.hgap,
                    vgap: o.vgap,
                    lgap: o.lgap,
                    rgap: o.rgap,
                    tgap: o.tgap,
                    bgap: o.bgap,
                    element: this,
                    items: [
                        {
                            el: (this.text = BI.createWidget(json))
                        }
                    ]
                });
                return;
            }
            if (BI.isNumber(o.height) && o.height > 0) {
                if (o.whiteSpace !== "normal") {
                    this.element.css({
                        "line-height": (o.height - (o.vgap * 2)) / BI.pixRatio + BI.pixUnit
                    });
                }
                this.text = BI.createWidget(BI.extend(json, { // 2.6
                    element: this,
                    hgap: o.hgap,
                    vgap: o.vgap,
                    lgap: o.lgap,
                    rgap: o.rgap,
                    tgap: o.tgap,
                    bgap: o.bgap
                }));
                return;
            }
            BI.extend(json, {
                hgap: o.hgap,
                vgap: o.vgap,
                lgap: o.lgap,
                rgap: o.rgap,
                tgap: o.tgap,
                bgap: o.bgap
            });

            this.text = BI.createWidget(BI.extend(json, {
                maxWidth: "100%"
            }));
            BI.createWidget({
                type: adaptLayout,
                horizontalAlign: o.textAlign,
                columnSize: ["auto"], // important！ 让文字在flex布局下shrink为1
                element: this,
                scrollable: o.whiteSpace === "normal",
                items: [this.text]
            });
        },

        doRedMark: function () {
            this.text.doRedMark.apply(this.text, arguments);
        },

        unRedMark: function () {
            this.text.unRedMark.apply(this.text, arguments);
        },

        doHighLight: function () {
            this.text.doHighLight.apply(this.text, arguments);
        },

        unHighLight: function () {
            this.text.unHighLight.apply(this.text, arguments);
        },

        setText: function (v) {
            this.options.text = v;
            this.text.setText(v);
        },

        getText: function () {
            return this.options.text;
        },

        setStyle: function (css) {
            this.text.setStyle(css);
        },

        setValue: function (v) {
            BI.AbstractLabel.superclass.setValue.apply(this, arguments);
            if (!this.isReadOnly()) {
                this.text.setValue(v);
            }
        },

        populate: function () {
            BI.AbstractLabel.superclass.populate.apply(this, arguments);
        }
    });
}());
<|endoftext|>


<commit_before>
var util = require('util');

var tokenize = function(/*String*/ str, /*RegExp*/ re, /*Function?*/ parseDelim, /*Object?*/ instance){
  // summary:
  //    Split a string by a regular expression with the ability to capture the delimeters
  // parseDelim:
  //    Each group (excluding the 0 group) is passed as a parameter. If the function returns
  //    a value, it's added to the list of tokens.
  // instance:
  //    Used as the "this' instance when calling parseDelim
  var tokens = [];
  var match, content, lastIndex = 0;
  while((match = re.exec(str))){
    content = str.slice(lastIndex, re.lastIndex - match[0].length);
    if(content.length){
      tokens.push(content);
    }
    if(parseDelim){
      var parsed = parseDelim.apply(instance, match.slice(1).concat(tokens.length));
      if(typeof parsed != 'undefined'){
        if(parsed.specifier === '%'){
          tokens.push('%');
        }else{
          tokens.push(parsed);
        }
      }
    }
    lastIndex = re.lastIndex;
  }
  content = str.slice(lastIndex);
  if(content.length){
    tokens.push(content);
  }
  return tokens;
};

var Formatter = function(/*String*/ format){
  this._mapped = false;
  this._format = format;
  this._tokens = tokenize(format, this._re, this._parseDelim, this);
};

Formatter.prototype._re = /\%(?:\(([\w_.]+)\)|([1-9]\d*)\$)?([0 +\-\#]*)(\*|\d+)?(\.)?(\*|\d+)?[hlL]?([\%bscdeEfFgGioOuxX])/g;
Formatter.prototype._parseDelim = function(mapping, intmapping, flags, minWidth, period, precision, specifier){
  if(mapping){
    this._mapped = true;
  }
  return {
    mapping: mapping,
    intmapping: intmapping,
    flags: flags,
    _minWidth: minWidth, // May be dependent on parameters
    period: period,
    _precision: precision, // May be dependent on parameters
    specifier: specifier
  };
};
Formatter.prototype._specifiers = {
  b: {
    base: 2,
    isInt: true
  },
  o: {
    base: 8,
    isInt: true
  },
  x: {
    base: 16,
    isInt: true
  },
  X: {
    extend: ['x'],
    toUpper: true
  },
  d: {
    base: 10,
    isInt: true
  },
  i: {
    extend: ['d']
  },
  u: {
    extend: ['d'],
    isUnsigned: true
  },
  c: {
    setArg: function(token){
      if(!isNaN(token.arg)){
        var num = parseInt(token.arg);
        if(num < 0 || num > 127){
          throw new Error('invalid character code passed to %c in printf');
        }
        token.arg = isNaN(num) ? '' + num : String.fromCharCode(num);
      }
    }
  },
  s: {
    setMaxWidth: function(token){
      token.maxWidth = (token.period == '.') ? token.precision : -1;
    }
  },
  e: {
    isDouble: true,
    doubleNotation: 'e'
  },
  E: {
    extend: ['e'],
    toUpper: true
  },
  f: {
    isDouble: true,
    doubleNotation: 'f'
  },
  F: {
    extend: ['f']
  },
  g: {
    isDouble: true,
    doubleNotation: 'g'
  },
  G: {
    extend: ['g'],
    toUpper: true
  },
  O: {
    isObject: true
  }
};
Formatter.prototype.format = function(/*mixed...*/ filler){
  if(this._mapped && typeof filler != 'object'){
    throw new Error('format requires a mapping');
  }

  var str = '';
  var position = 0;
  for(var i = 0, token; i < this._tokens.length; i++){
    token = this._tokens[i];

    if(typeof token == 'string'){
      str += token;
    }else{
      if(this._mapped){
        // Identify value of property defined in `token.mapping`
        var tokens = token.mapping.split('.');
        var value = filler;
        for (var j = 0, c = tokens.length; j < c; j++) {
          value = value[tokens[j]];
          if (typeof value === 'undefined') {
            break
          }
        }
        if(typeof value == 'undefined'){
          throw new Error('missing key ' + token.mapping);
        }
        token.arg = value;
      }else{
        if(token.intmapping){
          position = parseInt(token.intmapping) - 1;
        }
        if(position >= arguments.length){
          throw new Error('got ' + arguments.length + ' printf arguments, insufficient for \'' + this._format + '\'');
        }
        token.arg = arguments[position++];
      }

      if(!token.compiled){
        token.compiled = true;
        token.sign = '';
        token.zeroPad = false;
        token.rightJustify = false;
        token.alternative = false;

        var flags = {};
        for(var fi = token.flags.length; fi--;){
          var flag = token.flags.charAt(fi);
          flags[flag] = true;
          switch(flag){
            case ' ':
              token.sign = ' ';
              break;
            case '+':
              token.sign = '+';
              break;
            case '0':
              token.zeroPad = (flags['-']) ? false : true;
              break;
            case '-':
              token.rightJustify = true;
              token.zeroPad = false;
              break;
            case '#':
              token.alternative = true;
              break;
            default:
              throw Error('bad formatting flag \'' + token.flags.charAt(fi) + '\'');
          }
        }

        token.minWidth = (token._minWidth) ? parseInt(token._minWidth) : 0;
        token.maxWidth = -1;
        token.toUpper = false;
        token.isUnsigned = false;
        token.isInt = false;
        token.isDouble = false;
        token.isObject = false;
        token.precision = 1;
        if(token.period == '.'){
          if(token._precision){
            token.precision = parseInt(token._precision);
          }else{
            token.precision = 0;
          }
        }

        var mixins = this._specifiers[token.specifier];
        if(typeof mixins == 'undefined'){
          throw new Error('unexpected specifier \'' + token.specifier + '\'');
        }
        if(mixins.extend){
          var s = this._specifiers[mixins.extend];
          for(var k in s){
            mixins[k] = s[k];
          }
          delete mixins.extend;
        }
        for(var l in mixins){
          token[l] = mixins[l];
        }
      }

      if(typeof token.setArg == 'function'){
        token.setArg(token);
      }

      if(typeof token.setMaxWidth == 'function'){
        token.setMaxWidth(token);
      }

      if(token._minWidth == '*'){
        if(this._mapped){
          throw new Error('* width not supported in mapped formats');
        }
        token.minWidth = parseInt(arguments[position++]);
        if(isNaN(token.minWidth)){
          throw new Error('the argument for * width at position ' + position + ' is not a number in ' + this._format);
        }
        // negative width means rightJustify
        if (token.minWidth < 0) {
          token.rightJustify = true;
          token.minWidth = -token.minWidth;
        }
      }

      if(token._precision == '*' && token.period == '.'){
        if(this._mapped){
          throw new Error('* precision not supported in mapped formats');
        }
        token.precision = parseInt(arguments[position++]);
        if(isNaN(token.precision)){
          throw Error('the argument for * precision at position ' + position + ' is not a number in ' + this._format);
        }
        // negative precision means unspecified
        if (token.precision < 0) {
          token.precision = 1;
          token.period = '';
        }
      }
      if(token.isInt){
        // a specified precision means no zero padding
        if(token.period == '.'){
          token.zeroPad = false;
        }
        this.formatInt(token);
      }else if(token.isDouble){
        if(token.period != '.'){
          token.precision = 6;
        }
        this.formatDouble(token);
      }else if(token.isObject){
        this.formatObject(token);
      }
      this.fitField(token);

      str += '' + token.arg;
    }
  }

  return str;
};
Formatter.prototype._zeros10 = '0000000000';
Formatter.prototype._spaces10 = '          ';
Formatter.prototype.formatInt = function(token) {
  var i = parseInt(token.arg);
  if(!isFinite(i)){ // isNaN(f) || f == Number.POSITIVE_INFINITY || f == Number.NEGATIVE_INFINITY)
    // allow this only if arg is number
    if(typeof token.arg != 'number'){
      throw new Error('format argument \'' + token.arg + '\' not an integer; parseInt returned ' + i);
    }
    //return '' + i;
    i = 0;
  }

  // if not base 10, make negatives be positive
  // otherwise, (-10).toString(16) is '-a' instead of 'fffffff6'
  if(i < 0 && (token.isUnsigned || token.base != 10)){
    i = 0xffffffff + i + 1;
  }

  if(i < 0){
    token.arg = (- i).toString(token.base);
    this.zeroPad(token);
    token.arg = '-' + token.arg;
  }else{
    token.arg = i.toString(token.base);
    // need to make sure that argument 0 with precision==0 is formatted as ''
    if(!i && !token.precision){
      token.arg = '';
    }else{
      this.zeroPad(token);
    }
    if(token.sign){
      token.arg = token.sign + token.arg;
    }
  }
  if(token.base == 16){
    if(token.alternative){
      token.arg = '0x' + token.arg;
    }
    token.arg = token.toUpper ? token.arg.toUpperCase() : token.arg.toLowerCase();
  }
  if(token.base == 8){
    if(token.alternative && token.arg.charAt(0) != '0'){
      token.arg = '0' + token.arg;
    }
  }
};
Formatter.prototype.formatDouble = function(token) {
  var f = parseFloat(token.arg);
  if(!isFinite(f)){ // isNaN(f) || f == Number.POSITIVE_INFINITY || f == Number.NEGATIVE_INFINITY)
    // allow this only if arg is number
    if(typeof token.arg != 'number'){
      throw new Error('format argument \'' + token.arg + '\' not a float; parseFloat returned ' + f);
    }
    // C99 says that for 'f':
    //   infinity -> '[-]inf' or '[-]infinity' ('[-]INF' or '[-]INFINITY' for 'F')
    //   NaN -> a string  starting with 'nan' ('NAN' for 'F')
    // this is not commonly implemented though.
    //return '' + f;
    f = 0;
  }

  switch(token.doubleNotation) {
    case 'e': {
      token.arg = f.toExponential(token.precision);
      break;
    }
    case 'f': {
      token.arg = f.toFixed(token.precision);
      break;
    }
    case 'g': {
      // C says use 'e' notation if exponent is < -4 or is >= prec
      // ECMAScript for toPrecision says use exponential notation if exponent is >= prec,
      // though step 17 of toPrecision indicates a test for < -6 to force exponential.
      if(Math.abs(f) < 0.0001){
        //print('forcing exponential notation for f=' + f);
        token.arg = f.toExponential(token.precision > 0 ? token.precision - 1 : token.precision);
      }else{
        token.arg = f.toPrecision(token.precision);
      }

      // In C, unlike 'f', 'gG' removes trailing 0s from fractional part, unless alternative format flag ('#').
      // But ECMAScript formats toPrecision as 0.00100000. So remove trailing 0s.
      if(!token.alternative){
        //print('replacing trailing 0 in \'' + s + '\'');
        token.arg = token.arg.replace(/(\..*[^0])0*e/, '$1e');
        // if fractional part is entirely 0, remove it and decimal point
        token.arg = token.arg.replace(/\.0*e/, 'e').replace(/\.0$/,'');
      }
      break;
    }
    default: throw new Error('unexpected double notation \'' + token.doubleNotation + '\'');
  }

  // C says that exponent must have at least two digits.
  // But ECMAScript does not; toExponential results in things like '1.000000e-8' and '1.000000e+8'.
  // Note that s.replace(/e([\+\-])(\d)/, 'e$10$2') won't work because of the '$10' instead of '$1'.
  // And replace(re, func) isn't supported on IE50 or Safari1.
  token.arg = token.arg.replace(/e\+(\d)$/, 'e+0$1').replace(/e\-(\d)$/, 'e-0$1');

  // if alt, ensure a decimal point
  if(token.alternative){
    token.arg = token.arg.replace(/^(\d+)$/,'$1.');
    token.arg = token.arg.replace(/^(\d+)e/,'$1.e');
  }

  if(f >= 0 && token.sign){
    token.arg = token.sign + token.arg;
  }

  token.arg = token.toUpper ? token.arg.toUpperCase() : token.arg.toLowerCase();
};
Formatter.prototype.formatObject = function(token) {
  // If no precision is specified, then reset it to null (infinite depth).
  var precision = (token.period === '.') ? token.precision : null;
  token.arg = util.inspect(token.arg, !token.alternative, precision);
};
Formatter.prototype.zeroPad = function(token, /*Int*/ length) {
  length = (arguments.length == 2) ? length : token.precision;
  var negative = false;
  if(typeof token.arg != "string"){
    token.arg = "" + token.arg;
  }
  if (token.arg.substr(0,1) === '-') {
    negative = true;
    token.arg = token.arg.substr(1);
  }

  var tenless = length - 10;
  while(token.arg.length < tenless){
    token.arg = (token.rightJustify) ? token.arg + this._zeros10 : this._zeros10 + token.arg;
  }
  var pad = length - token.arg.length;
  token.arg = (token.rightJustify) ? token.arg + this._zeros10.substring(0, pad) : this._zeros10.substring(0, pad) + token.arg;
  if (negative) token.arg = '-' + token.arg;
};
Formatter.prototype.fitField = function(token) {
  if(token.maxWidth >= 0 && token.arg.length > token.maxWidth){
    return token.arg.substring(0, token.maxWidth);
  }
  if(token.zeroPad){
    this.zeroPad(token, token.minWidth);
    return;
  }
  this.spacePad(token);
};
Formatter.prototype.spacePad = function(token, /*Int*/ length) {
  length = (arguments.length == 2) ? length : token.minWidth;
  if(typeof token.arg != 'string'){
    token.arg = '' + token.arg;
  }
  var tenless = length - 10;
  while(token.arg.length < tenless){
    token.arg = (token.rightJustify) ? token.arg + this._spaces10 : this._spaces10 + token.arg;
  }
  var pad = length - token.arg.length;
  token.arg = (token.rightJustify) ? token.arg + this._spaces10.substring(0, pad) : this._spaces10.substring(0, pad) + token.arg;
};

module.exports = function(){
  var args = Array.prototype.slice.call(arguments),
    stream, format;
  if(args[0] instanceof require('stream').Stream){
    stream = args.shift();
  }
  format = args.shift();
  var formatter = new Formatter(format);
  var string = formatter.format.apply(formatter, args);
  if(stream){
    stream.write(string);
  }else{
    return string;
  }
};

module.exports.Formatter = Formatter;
<commit_msg>%+O inspects with colors<commit_after>
var util = require('util');

var tokenize = function(/*String*/ str, /*RegExp*/ re, /*Function?*/ parseDelim, /*Object?*/ instance){
  // summary:
  //    Split a string by a regular expression with the ability to capture the delimeters
  // parseDelim:
  //    Each group (excluding the 0 group) is passed as a parameter. If the function returns
  //    a value, it's added to the list of tokens.
  // instance:
  //    Used as the "this' instance when calling parseDelim
  var tokens = [];
  var match, content, lastIndex = 0;
  while((match = re.exec(str))){
    content = str.slice(lastIndex, re.lastIndex - match[0].length);
    if(content.length){
      tokens.push(content);
    }
    if(parseDelim){
      var parsed = parseDelim.apply(instance, match.slice(1).concat(tokens.length));
      if(typeof parsed != 'undefined'){
        if(parsed.specifier === '%'){
          tokens.push('%');
        }else{
          tokens.push(parsed);
        }
      }
    }
    lastIndex = re.lastIndex;
  }
  content = str.slice(lastIndex);
  if(content.length){
    tokens.push(content);
  }
  return tokens;
};

var Formatter = function(/*String*/ format){
  this._mapped = false;
  this._format = format;
  this._tokens = tokenize(format, this._re, this._parseDelim, this);
};

Formatter.prototype._re = /\%(?:\(([\w_.]+)\)|([1-9]\d*)\$)?([0 +\-\#]*)(\*|\d+)?(\.)?(\*|\d+)?[hlL]?([\%bscdeEfFgGioOuxX])/g;
Formatter.prototype._parseDelim = function(mapping, intmapping, flags, minWidth, period, precision, specifier){
  if(mapping){
    this._mapped = true;
  }
  return {
    mapping: mapping,
    intmapping: intmapping,
    flags: flags,
    _minWidth: minWidth, // May be dependent on parameters
    period: period,
    _precision: precision, // May be dependent on parameters
    specifier: specifier
  };
};
Formatter.prototype._specifiers = {
  b: {
    base: 2,
    isInt: true
  },
  o: {
    base: 8,
    isInt: true
  },
  x: {
    base: 16,
    isInt: true
  },
  X: {
    extend: ['x'],
    toUpper: true
  },
  d: {
    base: 10,
    isInt: true
  },
  i: {
    extend: ['d']
  },
  u: {
    extend: ['d'],
    isUnsigned: true
  },
  c: {
    setArg: function(token){
      if(!isNaN(token.arg)){
        var num = parseInt(token.arg);
        if(num < 0 || num > 127){
          throw new Error('invalid character code passed to %c in printf');
        }
        token.arg = isNaN(num) ? '' + num : String.fromCharCode(num);
      }
    }
  },
  s: {
    setMaxWidth: function(token){
      token.maxWidth = (token.period == '.') ? token.precision : -1;
    }
  },
  e: {
    isDouble: true,
    doubleNotation: 'e'
  },
  E: {
    extend: ['e'],
    toUpper: true
  },
  f: {
    isDouble: true,
    doubleNotation: 'f'
  },
  F: {
    extend: ['f']
  },
  g: {
    isDouble: true,
    doubleNotation: 'g'
  },
  G: {
    extend: ['g'],
    toUpper: true
  },
  O: {
    isObject: true
  }
};
Formatter.prototype.format = function(/*mixed...*/ filler){
  if(this._mapped && typeof filler != 'object'){
    throw new Error('format requires a mapping');
  }

  var str = '';
  var position = 0;
  for(var i = 0, token; i < this._tokens.length; i++){
    token = this._tokens[i];

    if(typeof token == 'string'){
      str += token;
    }else{
      if(this._mapped){
        // Identify value of property defined in `token.mapping`
        var tokens = token.mapping.split('.');
        var value = filler;
        for (var j = 0, c = tokens.length; j < c; j++) {
          value = value[tokens[j]];
          if (typeof value === 'undefined') {
            break
          }
        }
        if(typeof value == 'undefined'){
          throw new Error('missing key ' + token.mapping);
        }
        token.arg = value;
      }else{
        if(token.intmapping){
          position = parseInt(token.intmapping) - 1;
        }
        if(position >= arguments.length){
          throw new Error('got ' + arguments.length + ' printf arguments, insufficient for \'' + this._format + '\'');
        }
        token.arg = arguments[position++];
      }

      if(!token.compiled){
        token.compiled = true;
        token.sign = '';
        token.zeroPad = false;
        token.rightJustify = false;
        token.alternative = false;

        var flags = {};
        for(var fi = token.flags.length; fi--;){
          var flag = token.flags.charAt(fi);
          flags[flag] = true;
          switch(flag){
            case ' ':
              token.sign = ' ';
              break;
            case '+':
              token.sign = '+';
              break;
            case '0':
              token.zeroPad = (flags['-']) ? false : true;
              break;
            case '-':
              token.rightJustify = true;
              token.zeroPad = false;
              break;
            case '#':
              token.alternative = true;
              break;
            default:
              throw Error('bad formatting flag \'' + token.flags.charAt(fi) + '\'');
          }
        }

        token.minWidth = (token._minWidth) ? parseInt(token._minWidth) : 0;
        token.maxWidth = -1;
        token.toUpper = false;
        token.isUnsigned = false;
        token.isInt = false;
        token.isDouble = false;
        token.isObject = false;
        token.precision = 1;
        if(token.period == '.'){
          if(token._precision){
            token.precision = parseInt(token._precision);
          }else{
            token.precision = 0;
          }
        }

        var mixins = this._specifiers[token.specifier];
        if(typeof mixins == 'undefined'){
          throw new Error('unexpected specifier \'' + token.specifier + '\'');
        }
        if(mixins.extend){
          var s = this._specifiers[mixins.extend];
          for(var k in s){
            mixins[k] = s[k];
          }
          delete mixins.extend;
        }
        for(var l in mixins){
          token[l] = mixins[l];
        }
      }

      if(typeof token.setArg == 'function'){
        token.setArg(token);
      }

      if(typeof token.setMaxWidth == 'function'){
        token.setMaxWidth(token);
      }

      if(token._minWidth == '*'){
        if(this._mapped){
          throw new Error('* width not supported in mapped formats');
        }
        token.minWidth = parseInt(arguments[position++]);
        if(isNaN(token.minWidth)){
          throw new Error('the argument for * width at position ' + position + ' is not a number in ' + this._format);
        }
        // negative width means rightJustify
        if (token.minWidth < 0) {
          token.rightJustify = true;
          token.minWidth = -token.minWidth;
        }
      }

      if(token._precision == '*' && token.period == '.'){
        if(this._mapped){
          throw new Error('* precision not supported in mapped formats');
        }
        token.precision = parseInt(arguments[position++]);
        if(isNaN(token.precision)){
          throw Error('the argument for * precision at position ' + position + ' is not a number in ' + this._format);
        }
        // negative precision means unspecified
        if (token.precision < 0) {
          token.precision = 1;
          token.period = '';
        }
      }
      if(token.isInt){
        // a specified precision means no zero padding
        if(token.period == '.'){
          token.zeroPad = false;
        }
        this.formatInt(token);
      }else if(token.isDouble){
        if(token.period != '.'){
          token.precision = 6;
        }
        this.formatDouble(token);
      }else if(token.isObject){
        this.formatObject(token);
      }
      this.fitField(token);

      str += '' + token.arg;
    }
  }

  return str;
};
Formatter.prototype._zeros10 = '0000000000';
Formatter.prototype._spaces10 = '          ';
Formatter.prototype.formatInt = function(token) {
  var i = parseInt(token.arg);
  if(!isFinite(i)){ // isNaN(f) || f == Number.POSITIVE_INFINITY || f == Number.NEGATIVE_INFINITY)
    // allow this only if arg is number
    if(typeof token.arg != 'number'){
      throw new Error('format argument \'' + token.arg + '\' not an integer; parseInt returned ' + i);
    }
    //return '' + i;
    i = 0;
  }

  // if not base 10, make negatives be positive
  // otherwise, (-10).toString(16) is '-a' instead of 'fffffff6'
  if(i < 0 && (token.isUnsigned || token.base != 10)){
    i = 0xffffffff + i + 1;
  }

  if(i < 0){
    token.arg = (- i).toString(token.base);
    this.zeroPad(token);
    token.arg = '-' + token.arg;
  }else{
    token.arg = i.toString(token.base);
    // need to make sure that argument 0 with precision==0 is formatted as ''
    if(!i && !token.precision){
      token.arg = '';
    }else{
      this.zeroPad(token);
    }
    if(token.sign){
      token.arg = token.sign + token.arg;
    }
  }
  if(token.base == 16){
    if(token.alternative){
      token.arg = '0x' + token.arg;
    }
    token.arg = token.toUpper ? token.arg.toUpperCase() : token.arg.toLowerCase();
  }
  if(token.base == 8){
    if(token.alternative && token.arg.charAt(0) != '0'){
      token.arg = '0' + token.arg;
    }
  }
};
Formatter.prototype.formatDouble = function(token) {
  var f = parseFloat(token.arg);
  if(!isFinite(f)){ // isNaN(f) || f == Number.POSITIVE_INFINITY || f == Number.NEGATIVE_INFINITY)
    // allow this only if arg is number
    if(typeof token.arg != 'number'){
      throw new Error('format argument \'' + token.arg + '\' not a float; parseFloat returned ' + f);
    }
    // C99 says that for 'f':
    //   infinity -> '[-]inf' or '[-]infinity' ('[-]INF' or '[-]INFINITY' for 'F')
    //   NaN -> a string  starting with 'nan' ('NAN' for 'F')
    // this is not commonly implemented though.
    //return '' + f;
    f = 0;
  }

  switch(token.doubleNotation) {
    case 'e': {
      token.arg = f.toExponential(token.precision);
      break;
    }
    case 'f': {
      token.arg = f.toFixed(token.precision);
      break;
    }
    case 'g': {
      // C says use 'e' notation if exponent is < -4 or is >= prec
      // ECMAScript for toPrecision says use exponential notation if exponent is >= prec,
      // though step 17 of toPrecision indicates a test for < -6 to force exponential.
      if(Math.abs(f) < 0.0001){
        //print('forcing exponential notation for f=' + f);
        token.arg = f.toExponential(token.precision > 0 ? token.precision - 1 : token.precision);
      }else{
        token.arg = f.toPrecision(token.precision);
      }

      // In C, unlike 'f', 'gG' removes trailing 0s from fractional part, unless alternative format flag ('#').
      // But ECMAScript formats toPrecision as 0.00100000. So remove trailing 0s.
      if(!token.alternative){
        //print('replacing trailing 0 in \'' + s + '\'');
        token.arg = token.arg.replace(/(\..*[^0])0*e/, '$1e');
        // if fractional part is entirely 0, remove it and decimal point
        token.arg = token.arg.replace(/\.0*e/, 'e').replace(/\.0$/,'');
      }
      break;
    }
    default: throw new Error('unexpected double notation \'' + token.doubleNotation + '\'');
  }

  // C says that exponent must have at least two digits.
  // But ECMAScript does not; toExponential results in things like '1.000000e-8' and '1.000000e+8'.
  // Note that s.replace(/e([\+\-])(\d)/, 'e$10$2') won't work because of the '$10' instead of '$1'.
  // And replace(re, func) isn't supported on IE50 or Safari1.
  token.arg = token.arg.replace(/e\+(\d)$/, 'e+0$1').replace(/e\-(\d)$/, 'e-0$1');

  // if alt, ensure a decimal point
  if(token.alternative){
    token.arg = token.arg.replace(/^(\d+)$/,'$1.');
    token.arg = token.arg.replace(/^(\d+)e/,'$1.e');
  }

  if(f >= 0 && token.sign){
    token.arg = token.sign + token.arg;
  }

  token.arg = token.toUpper ? token.arg.toUpperCase() : token.arg.toLowerCase();
};
Formatter.prototype.formatObject = function(token) {
  // If no precision is specified, then reset it to null (infinite depth).
  var precision = (token.period === '.') ? token.precision : null;
  token.arg = util.inspect(token.arg, !token.alternative, precision, token.sign);
};
Formatter.prototype.zeroPad = function(token, /*Int*/ length) {
  length = (arguments.length == 2) ? length : token.precision;
  var negative = false;
  if(typeof token.arg != "string"){
    token.arg = "" + token.arg;
  }
  if (token.arg.substr(0,1) === '-') {
    negative = true;
    token.arg = token.arg.substr(1);
  }

  var tenless = length - 10;
  while(token.arg.length < tenless){
    token.arg = (token.rightJustify) ? token.arg + this._zeros10 : this._zeros10 + token.arg;
  }
  var pad = length - token.arg.length;
  token.arg = (token.rightJustify) ? token.arg + this._zeros10.substring(0, pad) : this._zeros10.substring(0, pad) + token.arg;
  if (negative) token.arg = '-' + token.arg;
};
Formatter.prototype.fitField = function(token) {
  if(token.maxWidth >= 0 && token.arg.length > token.maxWidth){
    return token.arg.substring(0, token.maxWidth);
  }
  if(token.zeroPad){
    this.zeroPad(token, token.minWidth);
    return;
  }
  this.spacePad(token);
};
Formatter.prototype.spacePad = function(token, /*Int*/ length) {
  length = (arguments.length == 2) ? length : token.minWidth;
  if(typeof token.arg != 'string'){
    token.arg = '' + token.arg;
  }
  var tenless = length - 10;
  while(token.arg.length < tenless){
    token.arg = (token.rightJustify) ? token.arg + this._spaces10 : this._spaces10 + token.arg;
  }
  var pad = length - token.arg.length;
  token.arg = (token.rightJustify) ? token.arg + this._spaces10.substring(0, pad) : this._spaces10.substring(0, pad) + token.arg;
};

module.exports = function(){
  var args = Array.prototype.slice.call(arguments),
    stream, format;
  if(args[0] instanceof require('stream').Stream){
    stream = args.shift();
  }
  format = args.shift();
  var formatter = new Formatter(format);
  var string = formatter.format.apply(formatter, args);
  if(stream){
    stream.write(string);
  }else{
    return string;
  }
};

module.exports.Formatter = Formatter;
<|endoftext|>


<commit_before>/**
 * We'll use ES6 in our server-side code for consistency.
 * This pulls in Babel as a preprocessor for future code
 * required by Node.
 */
require('babel/register')

var Server = require('./lib/server')

Server.start(process.env.PORT || 4000, function (error, server) {
  if (error) {
    throw Error(error)
  }

  console.log('[info] Examples listening on %s', server.info.uri)
})
<commit_msg>Use assert.ifError instead of conditional in server index<commit_after>/**
 * We'll use ES6 in our server-side code for consistency.
 * This pulls in Babel as a preprocessor for future code
 * required by Node.
 */
require('babel/register')

var Server = require('./lib/server')
var assert = require('assert')

Server.start(process.env.PORT || 4000, function (error, server) {
  assert.ifError(error)

  console.log('[info] Examples listening on %s', server.info.uri)
})
<|endoftext|>