<commit_before>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var App = require('app');
var uiEffects = require('utils/ui_effects');

App.MainHostSummaryView = Em.View.extend({
  templateName: require('templates/main/host/summary'),

  content: function () {
    return App.router.get('mainHostDetailsController.content');
  }.property('App.router.mainHostDetailsController.content'),

  showGangliaCharts: function () {
    var name = this.get('content.hostName');
    var gangliaMobileUrl = App.router.get('clusterController.gangliaUrl') + "/mobile_helper.php?show_host_metrics=1&h=" + name + "&c=HDPNameNode&r=hour&cs=&ce=";
    window.open(gangliaMobileUrl);
  },

  /**
   * @type: [{String}]
   */
  decommissionDataNodeHostNames: null,

  loadDecommissionNodesList: function () {
    var self = this;
    var clusterName = App.router.get('clusterController.clusterName');
    var persistUrl = App.apiPrefix + '/persist';
    var clusterUrl = App.apiPrefix + '/clusters/' + clusterName;
    var getConfigAjax = {
      type: 'GET',
      url: persistUrl,
      dataType: 'json',
      timeout: App.timeout,
      success: function (data) {
        if (data && data.decommissionDataNodesTag) {
          // We know the tag which contains the decommisioned nodes.
          var configsUrl = clusterUrl + '/configurations?type=hdfs-exclude-file&tag=' + data.decommissionDataNodesTag;
          var decomNodesAjax = {
            type: 'GET',
            url: configsUrl,
            dataType: 'json',
            timeout: App.timeout,
            success: function (data) {
              if (data && data.items) {
                var csv = data.items[0].properties.datanodes;
                self.set('decommissionDataNodeHostNames', csv.split(','));
              }
            },
            error: function (xhr, textStatus, errorThrown) {
              console.log(textStatus);
              console.log(errorThrown);
            }
          };
          jQuery.ajax(decomNodesAjax);
        }
      },
      error: function (xhr, textStatus, errorThrown) {
        // No tag pointer in persist. Rely on service's decomNodes.
        var hdfsSvcs = App.HDFSService.find();
        if (hdfsSvcs && hdfsSvcs.get('length') > 0) {
          var hdfsSvc = hdfsSvcs.objectAt(0);
          if (hdfsSvc) {
            var hostNames = [];
            var decomNodes = hdfsSvc.get('decommissionDataNodes');
            decomNodes.forEach(function (decomNode) {
              hostNames.push(decomNode.get('hostName'));
            });
            self.set('decommissionDataNodeHostNames', hostNames);
          }
        }
      }
    }
    jQuery.ajax(getConfigAjax);
  },
  didInsertElement: function () {
    this.loadDecommissionNodesList();
  },
  sortedComponents: function () {
    var slaveComponents = [];
    var masterComponents = [];
    this.get('content.hostComponents').forEach(function (component) {
      if (component.get('isMaster')) {
        masterComponents.push(component);
      } else if (component.get('isSlave')) {
        slaveComponents.push(component);
      }
    }, this);
    return masterComponents.concat(slaveComponents);
  }.property('content', 'content.hostComponents.length'),
  clients: function () {
    var clients = [];
    this.get('content.hostComponents').forEach(function (component) {
      if (!component.get('componentName')) {
        //temporary fix because of different data in hostComponents and serviceComponents
        return;
      }
      if (!component.get('isSlave') && !component.get('isMaster')) {
        if (clients.length) {
          clients[clients.length - 1].set('isLast', false);
        }
        component.set('isLast', true);
        clients.push(component);
      }
    }, this);
    return clients;
  }.property('content'),

  addableComponentObject: Em.Object.extend({
    componentName: '',
    subComponentNames: null,
    displayName: function () {
      if (this.get('componentName') === 'CLIENTS') {
        return this.t('common.clients');
      }
      return App.format.role(this.get('componentName'));
    }.property('componentName')
  }),
  isAddComponent: function () {
    return this.get('content.healthClass') !== 'health-status-DEAD-YELLOW';
  }.property('content.healthClass'),

  installableClientComponents: function() {
    var installableClients = [];
    if (!App.supports.deleteHost) {
      return installableClients;
    }
    App.Service.find().forEach(function(svc){
      switch(svc.get('serviceName')){
        case 'PIG':
          installableClients.push('PIG');
          break;
        case 'SQOOP':
          installableClients.push('SQOOP');
          break;
        case 'HCAT':
          installableClients.push('HCAT');
          break;
        case 'HDFS':
          installableClients.push('HDFS_CLIENT');
          break;
        case 'OOZIE':
          installableClients.push('OOZIE_CLIENT');
          break;
        case 'ZOOKEEPER':
          installableClients.push('ZOOKEEPER_CLIENT');
          break;
        case 'HIVE':
          installableClients.push('HIVE_CLIENT');
          break;
        case 'HBASE':
          installableClients.push('HBASE_CLIENT');
          break;
        case 'YARN':
          installableClients.push('YARN_CLIENT');
          break;
        case 'MAPREDUCE':
          installableClients.push('MAPREDUCE_CLIENT');
          break;
        case 'MAPREDUCE2':
          installableClients.push('MAPREDUCE2_CLIENT');
          break;
      }
    });
    this.get('content.hostComponents').forEach(function (component) {
      var index = installableClients.indexOf(component.get('componentName'));
      if (index > -1) {
        installableClients.splice(index, 1);
      }
    }, this);
    return installableClients;
  }.property('content', 'content.hostComponents.length', 'App.Service', 'App.supports.deleteHost'),

  addableComponents: function () {
    var components = [];
    var services = App.Service.find();
    var dataNodeExists = false;
    var taskTrackerExists = false;
    var regionServerExists = false;
    var zookeeperServerExists = false;
    var nodeManagerExists = false;

    var installableClients = this.get('installableClientComponents');

    this.get('content.hostComponents').forEach(function (component) {
      switch (component.get('componentName')) {
        case 'DATANODE':
          dataNodeExists = true;
          break;
        case 'TASKTRACKER':
          taskTrackerExists = true;
          break;
        case 'HBASE_REGIONSERVER':
          regionServerExists = true;
          break;
        case 'ZOOKEEPER_SERVER':
          zookeeperServerExists = true;
          break;
        case 'NODEMANAGER':
          nodeManagerExists = true;
          break;
      }
    }, this);

    if (!dataNodeExists) {
      components.pushObject(this.addableComponentObject.create({ 'componentName': 'DATANODE' }));
    }
    if (!taskTrackerExists && services.findProperty('serviceName', 'MAPREDUCE')) {
      components.pushObject(this.addableComponentObject.create({ 'componentName': 'TASKTRACKER' }));
    }
    if (!regionServerExists && services.findProperty('serviceName', 'HBASE')) {
      components.pushObject(this.addableComponentObject.create({ 'componentName': 'HBASE_REGIONSERVER' }));
    }
    if (!zookeeperServerExists && services.findProperty('serviceName', 'ZOOKEEPER')) {
      components.pushObject(this.addableComponentObject.create({ 'componentName': 'ZOOKEEPER_SERVER' }));
    }
    if (!nodeManagerExists && services.findProperty('serviceName', 'YARN')) {
      components.pushObject(this.addableComponentObject.create({ 'componentName': 'NODEMANAGER' }));
    }
    if (installableClients.length > 0) {
      components.pushObject(this.addableComponentObject.create({ 'componentName': 'CLIENTS', subComponentNames: installableClients }));
    }
    return components;
  }.property('content', 'content.hostComponents.length', 'installableClientComponents'),

  ComponentView: Em.View.extend({
    content: null,
    didInsertElement: function () {
      if (this.get('isInProgress')) {
        this.doBlinking();
      }
    },
    hostComponent: function () {
      var hostComponent = null;
      var serviceComponent = this.get('content');
      var host = App.router.get('mainHostDetailsController.content');
      if (host) {
        hostComponent = host.get('hostComponents').findProperty('componentName', serviceComponent.get('componentName'));
      }
      return hostComponent;
    }.property('content', 'App.router.mainHostDetailsController.content'),
    workStatus: function () {
      var workStatus = this.get('content.workStatus');
      var hostComponent = this.get('hostComponent');
      if (hostComponent) {
        workStatus = hostComponent.get('workStatus');
      }
      return workStatus;
    }.property('content.workStatus', 'hostComponent.workStatus'),

    /**
     * Return host component text status
     */
    componentTextStatus: function () {
      var workStatus = this.get("workStatus");
      var componentTextStatus = this.get('content.componentTextStatus');
      var hostComponent = this.get('hostComponent');
      if (hostComponent) {
        componentTextStatus = hostComponent.get('componentTextStatus');
        if(this.get("isDataNode"))
          if(this.get('isDataNodeRecommissionAvailable')){
            if(hostComponent.get('isDecommissioning')){
              componentTextStatus = "Decommissioning...";
            } else {
              componentTextStatus = "Decommissioned";
            }
          }
      }
      return componentTextStatus;
    }.property('workStatus','isDataNodeRecommissionAvailable'),

    statusClass: function () {
      //If the component is DataNode
      if (this.get('isDataNode')) {
        if (this.get('isDataNodeRecommissionAvailable') && (this.get('isStart') || this.get('workStatus') == 'INSTALLED')) {
          return 'health-status-DEAD-ORANGE';
        }
      }

      //Class when install failed
      if (this.get('workStatus') === App.HostComponentStatus.install_failed) {
        return 'health-status-color-red icon-cog';
      }

      //Class when installing
      if (this.get('workStatus') === App.HostComponentStatus.installing) {
        return 'health-status-color-blue icon-cog';
      }

      //For all other cases
      return 'health-status-' + App.HostComponentStatus.getKeyName(this.get('workStatus'));
    }.property('workStatus', 'isDataNodeRecommissionAvailable', 'this.content.isDecommissioning'),

    disabled: function() {
      return this.get('parentView.content.isNotHeartBeating')?'disabled':'';
    }.property('parentView.content.isNotHeartBeating'),
    /**
     * For Upgrade failed state
     */
    isUpgradeFailed: function () {
      return App.HostComponentStatus.getKeyName(this.get('workStatus')) === "upgrade_failed";
    }.property("workStatus"),
    /**
     * For Install failed state
     */
    isInstallFailed: function () {
      return App.HostComponentStatus.getKeyName(this.get('workStatus')) === "install_failed";
    }.property("workStatus"),
    /**
     * Do blinking for 1 minute
     */
    doBlinking: function () {
      var workStatus = this.get('workStatus');
      var self = this;
      var pulsate = [ App.HostComponentStatus.starting, App.HostComponentStatus.stopping, App.HostComponentStatus.installing].contains(workStatus);
      if (!pulsate && this.get('isDataNode')) {
        var dataNodeComponent = this.get('content');
        if (dataNodeComponent && workStatus != "INSTALLED") {
          pulsate = this.get('isDecommissioning');
        }
      }
      if (pulsate && !self.get('isBlinking')) {
        self.set('isBlinking', true);
        uiEffects.pulsate(self.$('.components-health'), 1000, function () {
          !self.get('isDestroyed') && self.set('isBlinking', false);
          self.doBlinking();
        });
      }
    },
    /**
     * Start blinking when host component is starting/stopping
     */
    startBlinking: function () {
      this.$('.components-health').stop(true, true);
      this.$('.components-health').css({opacity: 1.0});
      this.doBlinking();
    }.observes('workStatus','isDataNodeRecommissionAvailable'),

    isStart: function () {
      return (this.get('workStatus') == App.HostComponentStatus.started || this.get('workStatus') == App.HostComponentStatus.starting);
    }.property('workStatus'),

    isInstalling: function () {
      return (this.get('workStatus') == App.HostComponentStatus.installing);
    }.property('workStatus'),
    /**
     * No action available while component is starting/stopping/unknown
     */
    noActionAvailable: function () {
      var workStatus = this.get('workStatus');
      if ([App.HostComponentStatus.starting, App.HostComponentStatus.stopping, App.HostComponentStatus.unknown].contains(workStatus)) {
        return "hidden";
      }else{
        return "";
      }
    }.property('workStatus'),

    isInProgress: function () {
      return (this.get('workStatus') === App.HostComponentStatus.stopping ||
          this.get('workStatus') === App.HostComponentStatus.starting) ||
          this.get('isDecommissioning');
    }.property('workStatus', 'isDataNodeRecommissionAvailable'),
    /**
     * Shows whether we need to show Decommision/Recomission buttons
     */
    isDataNode: function () {
      return this.get('content.componentName') === 'DATANODE';
    }.property('content'),

    isDecommissioning: function () {
      var hostComponentDecommissioning = this.get('hostComponent.isDecommissioning');
      return this.get('isDataNode') &&  this.get("isDataNodeRecommissionAvailable") && hostComponentDecommissioning;
    }.property("workStatus", "isDataNodeRecommissionAvailable", "hostComponent.isDecommissioning"),

    /**
     * Set in template via binding from parent view
     */
    decommissionDataNodeHostNames: null,
    /**
     * Decommission is available whenever the service is started.
     */
    isDataNodeDecommissionAvailable: function () {
      return this.get('isStart') && !this.get('isDataNodeRecommissionAvailable');
    }.property('isStart', 'isDataNodeRecommissionAvailable'),

    /**
     * Recommission is available only when this hostname shows up in the
     * 'decommissionDataNodeHostNames'
     */
    isDataNodeRecommissionAvailable: function () {
      var decommissionHostNames = this.get('decommissionDataNodeHostNames');
      var hostName = App.router.get('mainHostDetailsController.content.hostName');
      return decommissionHostNames != null && decommissionHostNames.contains(hostName);
    }.property('App.router.mainHostDetailsController.content', 'decommissionDataNodeHostNames')

  }),
  timeSinceHeartBeat: function () {
    var d = this.get('content.lastHeartBeatTime');
    if (d) {
      return $.timeago(d);
    }
    return "";
  }.property('content.lastHeartBeatTime')
});<commit_msg>AMBARI-3282. Unnecessary comma (,) when a data node is decommissioned the second time. (srimanth)<commit_after>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var App = require('app');
var uiEffects = require('utils/ui_effects');

App.MainHostSummaryView = Em.View.extend({
  templateName: require('templates/main/host/summary'),

  content: function () {
    return App.router.get('mainHostDetailsController.content');
  }.property('App.router.mainHostDetailsController.content'),

  showGangliaCharts: function () {
    var name = this.get('content.hostName');
    var gangliaMobileUrl = App.router.get('clusterController.gangliaUrl') + "/mobile_helper.php?show_host_metrics=1&h=" + name + "&c=HDPNameNode&r=hour&cs=&ce=";
    window.open(gangliaMobileUrl);
  },

  /**
   * @type: [{String}]
   */
  decommissionDataNodeHostNames: null,

  loadDecommissionNodesList: function () {
    var self = this;
    var clusterName = App.router.get('clusterController.clusterName');
    var persistUrl = App.apiPrefix + '/persist';
    var clusterUrl = App.apiPrefix + '/clusters/' + clusterName;
    var getConfigAjax = {
      type: 'GET',
      url: persistUrl,
      dataType: 'json',
      timeout: App.timeout,
      success: function (data) {
        if (data && data.decommissionDataNodesTag) {
          // We know the tag which contains the decommisioned nodes.
          var configsUrl = clusterUrl + '/configurations?type=hdfs-exclude-file&tag=' + data.decommissionDataNodesTag;
          var decomNodesAjax = {
            type: 'GET',
            url: configsUrl,
            dataType: 'json',
            timeout: App.timeout,
            success: function (data) {
              if (data && data.items) {
                var csv = data.items[0].properties.datanodes;
                if (csv!==null && csv.length>0) {
                  self.set('decommissionDataNodeHostNames', csv.split(','));
                } else {
                  self.set('decommissionDataNodeHostNames', null);
                }
              }
            },
            error: function (xhr, textStatus, errorThrown) {
              console.log(textStatus);
              console.log(errorThrown);
            }
          };
          jQuery.ajax(decomNodesAjax);
        }
      },
      error: function (xhr, textStatus, errorThrown) {
        // No tag pointer in persist. Rely on service's decomNodes.
        var hdfsSvcs = App.HDFSService.find();
        if (hdfsSvcs && hdfsSvcs.get('length') > 0) {
          var hdfsSvc = hdfsSvcs.objectAt(0);
          if (hdfsSvc) {
            var hostNames = [];
            var decomNodes = hdfsSvc.get('decommissionDataNodes');
            decomNodes.forEach(function (decomNode) {
              hostNames.push(decomNode.get('hostName'));
            });
            self.set('decommissionDataNodeHostNames', hostNames);
          }
        }
      }
    }
    jQuery.ajax(getConfigAjax);
  },
  didInsertElement: function () {
    this.loadDecommissionNodesList();
  },
  sortedComponents: function () {
    var slaveComponents = [];
    var masterComponents = [];
    this.get('content.hostComponents').forEach(function (component) {
      if (component.get('isMaster')) {
        masterComponents.push(component);
      } else if (component.get('isSlave')) {
        slaveComponents.push(component);
      }
    }, this);
    return masterComponents.concat(slaveComponents);
  }.property('content', 'content.hostComponents.length'),
  clients: function () {
    var clients = [];
    this.get('content.hostComponents').forEach(function (component) {
      if (!component.get('componentName')) {
        //temporary fix because of different data in hostComponents and serviceComponents
        return;
      }
      if (!component.get('isSlave') && !component.get('isMaster')) {
        if (clients.length) {
          clients[clients.length - 1].set('isLast', false);
        }
        component.set('isLast', true);
        clients.push(component);
      }
    }, this);
    return clients;
  }.property('content'),

  addableComponentObject: Em.Object.extend({
    componentName: '',
    subComponentNames: null,
    displayName: function () {
      if (this.get('componentName') === 'CLIENTS') {
        return this.t('common.clients');
      }
      return App.format.role(this.get('componentName'));
    }.property('componentName')
  }),
  isAddComponent: function () {
    return this.get('content.healthClass') !== 'health-status-DEAD-YELLOW';
  }.property('content.healthClass'),

  installableClientComponents: function() {
    var installableClients = [];
    if (!App.supports.deleteHost) {
      return installableClients;
    }
    App.Service.find().forEach(function(svc){
      switch(svc.get('serviceName')){
        case 'PIG':
          installableClients.push('PIG');
          break;
        case 'SQOOP':
          installableClients.push('SQOOP');
          break;
        case 'HCAT':
          installableClients.push('HCAT');
          break;
        case 'HDFS':
          installableClients.push('HDFS_CLIENT');
          break;
        case 'OOZIE':
          installableClients.push('OOZIE_CLIENT');
          break;
        case 'ZOOKEEPER':
          installableClients.push('ZOOKEEPER_CLIENT');
          break;
        case 'HIVE':
          installableClients.push('HIVE_CLIENT');
          break;
        case 'HBASE':
          installableClients.push('HBASE_CLIENT');
          break;
        case 'YARN':
          installableClients.push('YARN_CLIENT');
          break;
        case 'MAPREDUCE':
          installableClients.push('MAPREDUCE_CLIENT');
          break;
        case 'MAPREDUCE2':
          installableClients.push('MAPREDUCE2_CLIENT');
          break;
      }
    });
    this.get('content.hostComponents').forEach(function (component) {
      var index = installableClients.indexOf(component.get('componentName'));
      if (index > -1) {
        installableClients.splice(index, 1);
      }
    }, this);
    return installableClients;
  }.property('content', 'content.hostComponents.length', 'App.Service', 'App.supports.deleteHost'),

  addableComponents: function () {
    var components = [];
    var services = App.Service.find();
    var dataNodeExists = false;
    var taskTrackerExists = false;
    var regionServerExists = false;
    var zookeeperServerExists = false;
    var nodeManagerExists = false;

    var installableClients = this.get('installableClientComponents');

    this.get('content.hostComponents').forEach(function (component) {
      switch (component.get('componentName')) {
        case 'DATANODE':
          dataNodeExists = true;
          break;
        case 'TASKTRACKER':
          taskTrackerExists = true;
          break;
        case 'HBASE_REGIONSERVER':
          regionServerExists = true;
          break;
        case 'ZOOKEEPER_SERVER':
          zookeeperServerExists = true;
          break;
        case 'NODEMANAGER':
          nodeManagerExists = true;
          break;
      }
    }, this);

    if (!dataNodeExists) {
      components.pushObject(this.addableComponentObject.create({ 'componentName': 'DATANODE' }));
    }
    if (!taskTrackerExists && services.findProperty('serviceName', 'MAPREDUCE')) {
      components.pushObject(this.addableComponentObject.create({ 'componentName': 'TASKTRACKER' }));
    }
    if (!regionServerExists && services.findProperty('serviceName', 'HBASE')) {
      components.pushObject(this.addableComponentObject.create({ 'componentName': 'HBASE_REGIONSERVER' }));
    }
    if (!zookeeperServerExists && services.findProperty('serviceName', 'ZOOKEEPER')) {
      components.pushObject(this.addableComponentObject.create({ 'componentName': 'ZOOKEEPER_SERVER' }));
    }
    if (!nodeManagerExists && services.findProperty('serviceName', 'YARN')) {
      components.pushObject(this.addableComponentObject.create({ 'componentName': 'NODEMANAGER' }));
    }
    if (installableClients.length > 0) {
      components.pushObject(this.addableComponentObject.create({ 'componentName': 'CLIENTS', subComponentNames: installableClients }));
    }
    return components;
  }.property('content', 'content.hostComponents.length', 'installableClientComponents'),

  ComponentView: Em.View.extend({
    content: null,
    didInsertElement: function () {
      if (this.get('isInProgress')) {
        this.doBlinking();
      }
    },
    hostComponent: function () {
      var hostComponent = null;
      var serviceComponent = this.get('content');
      var host = App.router.get('mainHostDetailsController.content');
      if (host) {
        hostComponent = host.get('hostComponents').findProperty('componentName', serviceComponent.get('componentName'));
      }
      return hostComponent;
    }.property('content', 'App.router.mainHostDetailsController.content'),
    workStatus: function () {
      var workStatus = this.get('content.workStatus');
      var hostComponent = this.get('hostComponent');
      if (hostComponent) {
        workStatus = hostComponent.get('workStatus');
      }
      return workStatus;
    }.property('content.workStatus', 'hostComponent.workStatus'),

    /**
     * Return host component text status
     */
    componentTextStatus: function () {
      var workStatus = this.get("workStatus");
      var componentTextStatus = this.get('content.componentTextStatus');
      var hostComponent = this.get('hostComponent');
      if (hostComponent) {
        componentTextStatus = hostComponent.get('componentTextStatus');
        if(this.get("isDataNode"))
          if(this.get('isDataNodeRecommissionAvailable')){
            if(hostComponent.get('isDecommissioning')){
              componentTextStatus = "Decommissioning...";
            } else {
              componentTextStatus = "Decommissioned";
            }
          }
      }
      return componentTextStatus;
    }.property('workStatus','isDataNodeRecommissionAvailable'),

    statusClass: function () {
      //If the component is DataNode
      if (this.get('isDataNode')) {
        if (this.get('isDataNodeRecommissionAvailable') && (this.get('isStart') || this.get('workStatus') == 'INSTALLED')) {
          return 'health-status-DEAD-ORANGE';
        }
      }

      //Class when install failed
      if (this.get('workStatus') === App.HostComponentStatus.install_failed) {
        return 'health-status-color-red icon-cog';
      }

      //Class when installing
      if (this.get('workStatus') === App.HostComponentStatus.installing) {
        return 'health-status-color-blue icon-cog';
      }

      //For all other cases
      return 'health-status-' + App.HostComponentStatus.getKeyName(this.get('workStatus'));
    }.property('workStatus', 'isDataNodeRecommissionAvailable', 'this.content.isDecommissioning'),

    disabled: function() {
      return this.get('parentView.content.isNotHeartBeating')?'disabled':'';
    }.property('parentView.content.isNotHeartBeating'),
    /**
     * For Upgrade failed state
     */
    isUpgradeFailed: function () {
      return App.HostComponentStatus.getKeyName(this.get('workStatus')) === "upgrade_failed";
    }.property("workStatus"),
    /**
     * For Install failed state
     */
    isInstallFailed: function () {
      return App.HostComponentStatus.getKeyName(this.get('workStatus')) === "install_failed";
    }.property("workStatus"),
    /**
     * Do blinking for 1 minute
     */
    doBlinking: function () {
      var workStatus = this.get('workStatus');
      var self = this;
      var pulsate = [ App.HostComponentStatus.starting, App.HostComponentStatus.stopping, App.HostComponentStatus.installing].contains(workStatus);
      if (!pulsate && this.get('isDataNode')) {
        var dataNodeComponent = this.get('content');
        if (dataNodeComponent && workStatus != "INSTALLED") {
          pulsate = this.get('isDecommissioning');
        }
      }
      if (pulsate && !self.get('isBlinking')) {
        self.set('isBlinking', true);
        uiEffects.pulsate(self.$('.components-health'), 1000, function () {
          !self.get('isDestroyed') && self.set('isBlinking', false);
          self.doBlinking();
        });
      }
    },
    /**
     * Start blinking when host component is starting/stopping
     */
    startBlinking: function () {
      this.$('.components-health').stop(true, true);
      this.$('.components-health').css({opacity: 1.0});
      this.doBlinking();
    }.observes('workStatus','isDataNodeRecommissionAvailable'),

    isStart: function () {
      return (this.get('workStatus') == App.HostComponentStatus.started || this.get('workStatus') == App.HostComponentStatus.starting);
    }.property('workStatus'),

    isInstalling: function () {
      return (this.get('workStatus') == App.HostComponentStatus.installing);
    }.property('workStatus'),
    /**
     * No action available while component is starting/stopping/unknown
     */
    noActionAvailable: function () {
      var workStatus = this.get('workStatus');
      if ([App.HostComponentStatus.starting, App.HostComponentStatus.stopping, App.HostComponentStatus.unknown].contains(workStatus)) {
        return "hidden";
      }else{
        return "";
      }
    }.property('workStatus'),

    isInProgress: function () {
      return (this.get('workStatus') === App.HostComponentStatus.stopping ||
          this.get('workStatus') === App.HostComponentStatus.starting) ||
          this.get('isDecommissioning');
    }.property('workStatus', 'isDataNodeRecommissionAvailable'),
    /**
     * Shows whether we need to show Decommision/Recomission buttons
     */
    isDataNode: function () {
      return this.get('content.componentName') === 'DATANODE';
    }.property('content'),

    isDecommissioning: function () {
      var hostComponentDecommissioning = this.get('hostComponent.isDecommissioning');
      return this.get('isDataNode') &&  this.get("isDataNodeRecommissionAvailable") && hostComponentDecommissioning;
    }.property("workStatus", "isDataNodeRecommissionAvailable", "hostComponent.isDecommissioning"),

    /**
     * Set in template via binding from parent view
     */
    decommissionDataNodeHostNames: null,
    /**
     * Decommission is available whenever the service is started.
     */
    isDataNodeDecommissionAvailable: function () {
      return this.get('isStart') && !this.get('isDataNodeRecommissionAvailable');
    }.property('isStart', 'isDataNodeRecommissionAvailable'),

    /**
     * Recommission is available only when this hostname shows up in the
     * 'decommissionDataNodeHostNames'
     */
    isDataNodeRecommissionAvailable: function () {
      var decommissionHostNames = this.get('decommissionDataNodeHostNames');
      var hostName = App.router.get('mainHostDetailsController.content.hostName');
      return decommissionHostNames != null && decommissionHostNames.contains(hostName);
    }.property('App.router.mainHostDetailsController.content', 'decommissionDataNodeHostNames')

  }),
  timeSinceHeartBeat: function () {
    var d = this.get('content.lastHeartBeatTime');
    if (d) {
      return $.timeago(d);
    }
    return "";
  }.property('content.lastHeartBeatTime')
});<|endoftext|>


<commit_before>openerp.suvit_web_tree = function(instance, local) {

  /********* Custom domain for List & Tree Views in same Action ********/
  instance.web.FormView.include({
      on_button_save: function(e) {
          var self = this;
          return self._super(e).then(function(){
              if (self.ViewManager.views.tree)
                self.ViewManager.views.tree.controller.switch_mode()
          });
      },
      on_button_create: function() {
          var self = this;
          self._super();
          if (self.ViewManager.views.tree)
            self.ViewManager.views.tree.controller.switch_mode()
      }
  });

  instance.web.TreeView.include({
    init: function (parent, dataset, view_id, options) {
        if (parent.action && parent.action.context.tree_domain){
          var domain = new instance.web.CompoundDomain(dataset.domain, parent.action.context.tree_domain);
          dataset = new instance.web.DataSetSearch(this, parent.action.res_model, dataset.context, domain);
        }
        this._super(parent, dataset, view_id, options);
    },
    switch_mode: function () {
      this.$el.find(".oe-treeview-table > tbody").empty();
      _(this.fields_view.arch.children).each(function (field) {
          if (field.attrs.modifiers && typeof(field.attrs.modifiers) == 'object') {
              field.attrs.modifiers = JSON.stringify(field.attrs.modifiers);
          }
      });
      this.view_loading(this.fields_view);
    },
    hook_row_click: function () {
      this.$el.undelegate('.treeview-tr', 'click');
      this._super();
    }
  });

  /********* Many2Many Tree Field ********/
  local.Many2ManyTreeField = instance.web.form.FieldMany2Many.extend({
    initialize_content: function() {
        if (!(this.field.type == 'many2many' || this.field.type == 'one2many'))
            return this._super();
        this.list_view = new instance.web.TreeView(this, this.dataset, false, {
                    'addable': false,
                    'deletable': false,
                    'selectable': false,
                    'sortable': false,
                    'reorderable': false,
                    'import_enabled': false,
            });
        this.$el.empty();
        this.list_view.appendTo(this.$el);
    },
    render_value: function() {
      this.initialize_content();
      return this._super();
    }
  });

  instance.web.form.widgets.add('many2many_tree', 'instance.suvit_web_tree.Many2ManyTreeField');
};
<commit_msg>обновление дерева<commit_after>openerp.suvit_web_tree = function(instance, local) {

  /********* Custom domain for List & Tree Views in same Action ********/
  instance.web.FormView.include({
      on_button_save: function(e) {
          var self = this;
          return self._super(e).then(function(){
              if (self.ViewManager.views.tree)
                self.ViewManager.views.tree.controller.switch_mode()
          });
      },
      on_button_create: function() {
          var self = this;
          self._super();
          if (self.ViewManager.views.tree)
            self.ViewManager.views.tree.controller.switch_mode()
      }
  });

  instance.web.TreeView.include({
    init: function (parent, dataset, view_id, options) {
        if (parent.action && parent.action.context.tree_domain){
          var domain = new instance.web.CompoundDomain(dataset.domain, parent.action.context.tree_domain);
          dataset = new instance.web.DataSetSearch(this, parent.action.res_model, dataset.context, domain);
        }
        this._super(parent, dataset, view_id, options);
    },
    switch_mode: function () {
      this.$el.find(".oe-treeview-table > tbody").empty();
      _(this.fields_view.arch.children).each(function (field) {
          if (field.attrs.modifiers && typeof(field.attrs.modifiers) == 'object') {
              field.attrs.modifiers = JSON.stringify(field.attrs.modifiers);
          }
      });
      this.view_loading(this.fields_view);
    },
    hook_row_click: function () {
      this.$el.undelegate('.treeview-tr', 'click');
      this._super();
    }
  });
  instance.web.ActionManager.include({
    select_breadcrumb: function(index, subindex) {
      var self = this;
      var item = this.breadcrumbs[index];
      if (item.widget.views.tree) {
        item.widget.views.tree.controller.switch_mode();
      }
      return this._super(index, subindex);
    },
  });

  /********* Many2Many Tree Field ********/
  local.Many2ManyTreeField = instance.web.form.FieldMany2Many.extend({
    initialize_content: function() {
        if (!(this.field.type == 'many2many' || this.field.type == 'one2many'))
            return this._super();
        this.list_view = new instance.web.TreeView(this, this.dataset, false, {
                    'addable': false,
                    'deletable': false,
                    'selectable': false,
                    'sortable': false,
                    'reorderable': false,
                    'import_enabled': false,
            });
        this.$el.empty();
        this.list_view.appendTo(this.$el);
    },
    render_value: function() {
      this.initialize_content();
      return this._super();
    }
  });

  instance.web.form.widgets.add('many2many_tree', 'instance.suvit_web_tree.Many2ManyTreeField');
};
<|endoftext|>


<commit_before>/* globals key */

// requires keymaster.js

;(function () {

    // Wait for xt.options to be set
  ;(function check() {
    // If hotkey is switched on, add the buttons
    if( xt.options && xt.options['buffer.op.key-enable'] === 'key-enable') {
      key(xt.options['buffer.op.key-combo'], function () {
        xt.port.emit("buffer_click", {placement: 'hotkey'});
        return false;
      });
    } else {
      setTimeout(check, 50);
    }
  }());

}());
<commit_msg>Prevent double-execution of alt+b shortcut on buffer.com/app<commit_after>/* globals key */

// requires keymaster.js

;(function () {
    // Wait for xt.options to be set
  ;(function check() {
    // If hotkey is switched on, add the buttons
    if( xt.options && xt.options['buffer.op.key-enable'] === 'key-enable') {
      key(xt.options['buffer.op.key-combo'], function () {
        var usesDefaultShortcut = xt.options['buffer.op.key-combo'] === 'alt+b';
        var isShortcutPressedInBufferApp = /https?:\/\/buffer.com\/app\//.test(location.href);
        if (usesDefaultShortcut && isShortcutPressedInBufferApp) {
          return false; // Buffer.com already offers the alt+b shortcut to open the in-app composer
        }

        xt.port.emit("buffer_click", {placement: 'hotkey'});
        return false;
      });
    } else {
      setTimeout(check, 50);
    }
  }());
}());
<|endoftext|>


<commit_before>exports.couch = (function() {

  function keyToAddress(key) {
    var i = 0;
    while(i < key.length && key[i] =='u') {
     i++;
    }
    if((i < key.length) && (key[i] == '_')) {
      key = 'u'+key;
    }
    return localStorage.getItem('_shadowBackendAddress') + key;
  }
  function doCall(method, key, obj, err, cb, timeout) {
    var ajaxObj = {
      url: keyToAddress(key),
      method: method,
      error: err,
      success: cb,
      timeout: timeout
    }
    ajaxObj.headers= {Authorization: 'Bearer '+localStorage.getItem('_shadowBackendToken')};
    ajaxObj.fields={withCredentials: 'true'};
    if(method!='GET') {
      ajaxObj.data=JSON.stringify(obj);
    }
    exports.ajax(ajaxObj);
  }
  function init(address, bearerToken) {
    localStorage.setItem('_shadowBackendAddress', address);
    localStorage.setItem('_shadowBackendToken', bearerToken);
  }
  function get(key, err, cb, timeout) {
    console.log('couch.get("'+key+'", err, cb, '+timeout+');');
    doCall('GET', key, null, err, cb, timeout);
  }
  function set(key, value, err, cb, timeout) {
    console.log('couch.set("'+key+'", "'+value+'", err, cb, '+timeout+');');
    doCall('PUT', key, value, err, cb, timeout);
  }
  function remove(key, err, cb, timeout) {
    console.log('couch.remove("'+key+'", err, cb, '+timeout+');');
    doCall('DELETE', key, null, err, cb, timeout);
  }
  return {
    init: init,
    set: set,
    get: get,
    remove: remove
  };
})();

<commit_msg>trying to add JSON-objectification and revision handling<commit_after>exports.couch = (function() {

  function keyToAddress(key) {
    var i = 0;
    while(i < key.length && key[i] =='u') {
     i++;
    }
    if((i < key.length) && (key[i] == '_')) {
      key = 'u'+key;
    }
    return localStorage.getItem('_shadowBackendAddress') + key;
  }
  function doCall(method, key, obj, err, cb, timeout) {
    var ajaxObj = {
      url: keyToAddress(key),
      method: method,
      error: err,
      success: cb,
      timeout: timeout
    }
    ajaxObj.headers= {Authorization: 'Bearer '+localStorage.getItem('_shadowBackendToken')};
    ajaxObj.fields={withCredentials: 'true'};
    if(method!='GET') {
      ajaxObj.data=JSON.stringify(obj);
    }
    exports.ajax(ajaxObj);
  }
  function init(address, bearerToken) {
    localStorage.setItem('_shadowBackendAddress', address);
    localStorage.setItem('_shadowBackendToken', bearerToken);
  }
  function get(key, err, cb, timeout) {
    console.log('couch.get("'+key+'", err, cb, '+timeout+');');
    doCall('GET', key, null, err, function(str) {
      var obj = JSON.parse(str);
      localStorage.setItem('_shadowCouchRev_'+key, obj.revision);
      cb(obj.value);
    }, timeout);
  }
  function set(key, value, err, cb, timeout) {
    console.log('couch.set("'+key+'", "'+value+'", err, cb, '+timeout+');');
    var revision = localStorage.getItem('_shadowCouchRev_'+key);
    var obj = {
      value: value
    };
    if(revision) {
      obj.revision = revision;
    }
    doCall('PUT', key, JSON.stringify(obj), err, cb, timeout);
  }
  function remove(key, err, cb, timeout) {
    console.log('couch.remove("'+key+'", err, cb, '+timeout+');');
    doCall('DELETE', key, null, err, cb, timeout);
  }
  return {
    init: init,
    set: set,
    get: get,
    remove: remove
  };
})();

<|endoftext|>


<commit_before>/************************
 * Provides IEnumerable for the js Array
 *
 *
 * Authors: KodingSykosis & OhRyanOh
 * https://github.com/KodingSykosis
 * https://github.com/OhRyanOh
 ***/
(function(array, string, exports) {
    //From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/Trim
    if (!string.prototype.trim) {
        string.prototype.trim = function () {
            return this.replace(/^\s+|\s+$/g, '');
        };
    }

    //From http://stackoverflow.com/questions/7616461/generate-a-hash-from-string-in-javascript-jquery
    string.prototype.hashCode = function () {
        var hash = 0, i, char;
        if (this.length === 0) return hash;
        for (var i = 0, l = this.length; i < l; i++) {
            char = this.charCodeAt(i);
            hash = ((hash << 5) - hash) + char;
            hash |= 0; // Convert to 32bit integer
        }
        return hash;
    };

    //Polyfill from
    //https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
    if (!array.prototype.forEach) {
      array.prototype.forEach = function(fun /*, thisArg */) {
        "use strict";

        if (this === void 0 || this === null)
          throw new TypeError();

        var t = Object(this);
        var len = t.length >>> 0;
        if (typeof fun !== "function")
          throw new TypeError();

        var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
        for (var i = 0; i < len; i++) {
          if (i in t)
            fun.call(thisArg, t[i], i, t);
        }
      };
    }

    // Array Linq like extensions where they make sense:
    // http://msdn.microsoft.com/en-us/library/system.linq.enumerable_methods(v=vs.110).aspx

    array.prototype.aggregate = function (func) {
        if (this.length === 0)
            return null;

        func = compileExp(func);
        var aggregateValue = this[0];
        for (var i = 1, len = this.length; i < len; i++)
            aggregateValue = func(aggregateValue, this[i]);
        return aggregateValue;
    };

    array.prototype.all = function (qry) {
        var results = typeof qry === 'undefined'
            ? this
            : this.where(qry);

        return results.length === this.count();
    };

    array.prototype.any = function (qry) {
        var results = typeof qry === 'undefined'
            ? this
            : this.where(qry);

        return results.length > 0;
    };

    array.prototype.average = function () {
        return this.sum() / this.count();
    };

    //concat is already in ecma...

    array.prototype.contains = function (value) {
        return this.count(
            function (item) {
                return compare(item, value) === 0;
            }) > 0;
    };

    array.prototype.count = function (qry) {
        var results = typeof qry === 'undefined'
            ? this
            : this.where(qry);

        return results.length;
    };

    // Excluding DefaultIfEmpty

    array.prototype.distinct = function () {
        if (this.length < 1)
            return this;

        var sortedResults = this.sort();
        var results = [];
        results.push(sortedResults[0]);
        for (var i = 0, j = 1, len = sortedResults.length; j < len; i++, j++) {
            var prev = sortedResults[i];
            var curr = sortedResults[j];

            if (compare(curr, prev) !== 0)
                results.push(curr);
        }

        return results;
    };

    array.prototype.elementAt = function (index) {
        if (this.length === 0 || index < 0 || (index - 1) > this.length)
            throw "No Results Found";

        return this[index];
    };

    array.prototype.elementAtOrDefault = function (index) {
        if (this.length === 0 || index < 0 || (index - 1) > this.length)
            return null;

        return this[index];
    };

    // Excluding Empty

    array.prototype.except = function (array) {
        if (this.length === 0 || array.length === 0)
            return this;

        var results = [];
        for (var i = 0, len = this.length; i < len; i++) {
            if (array.contains(this[i]))
                continue;

            results.push(this[i]);
        }

        return results.distinct();
    };

    array.prototype.first = function (qry) {
        var result = this.firstOrDefault(qry);

        if (result === null)
            throw "No Results Found";

        return result;
    };

    array.prototype.firstOrDefault = function (qry) {
        var results = typeof qry === 'undefined'
            ? this
            : this.where(qry);

        return results.length > 0
            ? results[0]
            : null;
    };

    array.prototype.groupBy = function (exp) {
        var compiled = compileExp(exp);
        var keys = this.select(compiled).distinct();
        var results = [];

        for (var i = 0, len = keys.length; i < len; i++)
            results.push({
                key: keys[i],
                value: this.where(function (item) {
                    return compiled(item) === keys[i];
                })
            });

        return results;
    };

    array.prototype.groupJoin = function (inner, outerKey, innerKey, zipFn) {
        var iKey = compileExp(innerKey);
        var oKey = compileExp(outerKey);
        var results = [];

        for (var i = 0, len = this.length; i < len; i++) {
            var matches = inner.where(function (item) {
                return compare(oKey(this[i]), iKey(item)) === 0;
            });

            results.push(matches);
        }

        return this.zip(results, zipFn);
    };

    // Same as join from microsoft documentation, however join already exists in ecma and is more of a concat...
    array.prototype.innerJoin = function (inner, outerKey, innerKey, zipFn) {
        var iKey = compileExp(innerKey);
        var oKey = compileExp(outerKey);
        var results = [];

        for (var i = 0; i < this.length; i++) {
            var outerItem = this[i];
            var matches = inner.where(function (item) {
                return compare(oKey(outerItem), iKey(item)) === 0;
            });

            for (var x = 0; x < matches.length; x++)
                results.push(matches[x]);
        }

        return this.zip(results, zipFn);
    };

    array.prototype.intersect = function (array) {
        if (this.length === 0 || array.length === 0)
            return [];

        var results = [];
        for (var i = 0; i < array.length; i++)
            for (var j = 0; j < this.length; j++)
                if (compare(this[j], array[i]) === 0)
                    results.push(this[j]);

        return results.distinct();
    };

    array.prototype.last = function (qry) {
        var result = this.lastOrDefault(qry);

        if (result === null)
            throw "No Results Found";

        return result;
    };

    array.prototype.lastOrDefault = function (qry) {
        var results = typeof qry === 'undefined'
            ? this
            : this.where(qry);

        return results.length > 0
            ? results[results.length - 1]
            : null;
    };

    // Excluding LongCount

    array.prototype.max = function (qry) {
        var results = this.select(qry);
        return Math.max.apply(null, results);
    };

    array.prototype.min = function (qry) {
        var results = this.select(qry);
        return Math.min.apply(null, results);
    };

    // Excluding OfType

    array.prototype.orderBy = function (qry) {
        if (typeof qry === 'undefined')
            return this.sort();

        var compiled = compileExp(qry);

        return this.sort(function (a, b) {
            return compare(compiled(a), compiled(b));
        });
    };

    array.prototype.orderByDescending = function (qry) {
        if (typeof qry === 'undefined')
            return this.sort().reverse();

        return this.orderBy(qry).reverse();
    };

    // Excluding Range

    // Excluding Repeat

    // Reverse already a part of ecma.

    array.prototype.select = function (qry) {
        if (typeof qry === 'undefined')
            return this;

        var compiled = compileExp(qry);
        var results = [];

        for (var i = 0, len = this.length; i < len; i++)
            results.push(compiled(this[i]));

        return results;
    };

    array.prototype.selectMany = function (qry) {
        if (typeof qry === 'undefined')
            return this;

        var results = this.select(qry);
        var array = [];
        for (var i = 0, len = results.length; i < len; i++)
            array = array.union(results[i]);

        return array;
    };

    array.prototype.sequenceEqual = function (array) {
        if (typeof array === 'undefined' || array === null)
            return false;

        if (this.length !== array.length)
            return false;

        for (var i = 0, len = this.length; i < len; i++)
            if (compare(this[i], array[i]) !== 0)
                return false;

        return true;
    };

    array.prototype.single = function () {
        if (this.length !== 1)
            throw "Sequence does not contain a single element.";

        return this[0];
    };

    array.prototype.singleOrDefault = function () {
        if (this.length > 1)
            throw "Sequence does not contain a single element.";

        return this.length === 1
            ? this[0]
            : null;
    };

    array.prototype.skip = function (index) {
        return this.slice(index, this.length);
    };

    array.prototype.skipWhile = function (qry) {
        var compiled = compileExp(qry);
        var results = [];

        for (var i = 0, len = this.length; i < len; i++)
            if (compiled(this[i]) !== true)
                results.push(this[i]);

        return results;
    };

    array.prototype.sum = function () {
        if (this.length === 0)
            return 0;

        var sum = 0;
        for (var i = 0, len = this.length; i < len; i++)
            sum += this[i];
        return sum;
    };

    array.prototype.take = function (count) {
        return this.slice(0, count);
    };

    array.prototype.takeWhile = function (qry) {
        var compiled = compileExp(qry);
        var results = [];

        for (var i = 0, len = this.length; i < len; i++) {
            var item = this[i];
            if (compiled(item) !== true)
                return results;

            results.push(item);
        }

        return results;
    };

    // Excluding ThenBy
    // Excluding ThenByDescending
    // Excluding ToArray ... lol
    // Excluding ToDictionary
    // Excluding ToList
    // Excluding ToLookup

    array.prototype.union = function (array) {
        if (typeof array === 'undefined' || array === null)
            return this;

        return this.concat(array).distinct();
    };

    array.prototype.where = function (qry) {
        var compiled = compileExp(qry);
        var results = [];

        for (var i = 0, len = this.length; i < len; i++)
            if (compiled(this[i]) === true)
                results.push(this[i]);

        return results;
    };

    array.prototype.zip = function (second, zipFn) {
        var results = [];

        if (typeof zipFn !== 'function')
            zipFn = compileExp(zipFn);

        for (var i = 0, len = this.length; i < len; i++)
            if (second.length > i)
                results.push(zipFn(this[i], second[i]));

        return results;
    };

    // Comparison and compilation expressions

    var compileExp = exports.compileExp = function (exp) {
        if (typeof exp === 'undefined')
            throw "Expression is invalid.";

        if (typeof exp === 'function')
            return exp;

        var parts = exp.split('=>');
        var arg = parts.length > 0 ? parts[0].trim().replace(/\(|\)/g, '') : null;
        var func = parts.length > 1 ? parts[1].trim() : null;

        if (arg === null || func === null)
            throw "Expression is invalid.";

        return new Function(arg, 'return (' + func + ');');
    };

    var compare = exports.compare = function (obj1, obj2) {
        if (typeof obj1 === 'undefined' || typeof obj2 === 'undefined')
            return typeof obj1 === 'undefined' ? -1 : (typeof obj2 === 'undefined' ? 1 : 0);

        if (typeof obj1 !== typeof obj2)
            throw "Both objects must be of the same type";

        if (obj1.compare)
            return obj1.compare(obj2);

        if (typeof obj1 === 'string') {
            var hash1 = obj1.hashCode();
            var hash2 = obj2.hashCode();

            return hash1 < hash2 ? -1 : (hash1 > hash2 ? 1 : 0);
        }

        if (typeof obj1 === 'number')
            return obj1 < obj2 ? -1 : (obj1 > obj2 ? 1 : 0);

        if (typeof obj1 === 'boolean')
            return obj1 === obj2 ? 0 : (obj1 ? 1 : -1);

        if (typeof obj1 === 'function') {
            var val1 = obj1();
            var val2 = obj2();

            return compare(val1, val2);
        }

        if (typeof obj1 === 'object') {
            var result = 0;
            for (var key in obj1) {
                var temp = compare(obj1[key], obj2[key]);
                if (temp === -1) return temp;
                result = Math.max(result, temp);
            }
            return result;
        }

        throw "Unable to compare objects";
    };
})(Array, String, (typeof module !== 'undefined' && module.exports) || window);<commit_msg>Updated Array.js to remove distinct from union<commit_after>/************************
 * Provides IEnumerable for the js Array
 *
 *
 * Authors: KodingSykosis & OhRyanOh
 * https://github.com/KodingSykosis
 * https://github.com/OhRyanOh
 ***/
(function(array, string, exports) {
    //From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/Trim
    if (!string.prototype.trim) {
        string.prototype.trim = function () {
            return this.replace(/^\s+|\s+$/g, '');
        };
    }

    //From http://stackoverflow.com/questions/7616461/generate-a-hash-from-string-in-javascript-jquery
    string.prototype.hashCode = function () {
        var hash = 0, i, char;
        if (this.length === 0) return hash;
        for (var i = 0, l = this.length; i < l; i++) {
            char = this.charCodeAt(i);
            hash = ((hash << 5) - hash) + char;
            hash |= 0; // Convert to 32bit integer
        }
        return hash;
    };

    //Polyfill from
    //https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
    if (!array.prototype.forEach) {
      array.prototype.forEach = function(fun /*, thisArg */) {
        "use strict";

        if (this === void 0 || this === null)
          throw new TypeError();

        var t = Object(this);
        var len = t.length >>> 0;
        if (typeof fun !== "function")
          throw new TypeError();

        var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
        for (var i = 0; i < len; i++) {
          if (i in t)
            fun.call(thisArg, t[i], i, t);
        }
      };
    }

    // Array Linq like extensions where they make sense:
    // http://msdn.microsoft.com/en-us/library/system.linq.enumerable_methods(v=vs.110).aspx

    array.prototype.aggregate = function (func) {
        if (this.length === 0)
            return null;

        func = compileExp(func);
        var aggregateValue = this[0];
        for (var i = 1, len = this.length; i < len; i++)
            aggregateValue = func(aggregateValue, this[i]);
        return aggregateValue;
    };

    array.prototype.all = function (qry) {
        var results = typeof qry === 'undefined'
            ? this
            : this.where(qry);

        return results.length === this.count();
    };

    array.prototype.any = function (qry) {
        var results = typeof qry === 'undefined'
            ? this
            : this.where(qry);

        return results.length > 0;
    };

    array.prototype.average = function () {
        return this.sum() / this.count();
    };

    //concat is already in ecma...

    array.prototype.contains = function (value) {
        return this.count(
            function (item) {
                return compare(item, value) === 0;
            }) > 0;
    };

    array.prototype.count = function (qry) {
        var results = typeof qry === 'undefined'
            ? this
            : this.where(qry);

        return results.length;
    };

    // Excluding DefaultIfEmpty

    array.prototype.distinct = function () {
        if (this.length < 1)
            return this;

        var sortedResults = this.sort();
        var results = [];
        results.push(sortedResults[0]);
        for (var i = 0, j = 1, len = sortedResults.length; j < len; i++, j++) {
            var prev = sortedResults[i];
            var curr = sortedResults[j];

            if (compare(curr, prev) !== 0)
                results.push(curr);
        }

        return results;
    };

    array.prototype.elementAt = function (index) {
        if (this.length === 0 || index < 0 || (index - 1) > this.length)
            throw "No Results Found";

        return this[index];
    };

    array.prototype.elementAtOrDefault = function (index) {
        if (this.length === 0 || index < 0 || (index - 1) > this.length)
            return null;

        return this[index];
    };

    // Excluding Empty

    array.prototype.except = function (array) {
        if (this.length === 0 || array.length === 0)
            return this;

        var results = [];
        for (var i = 0, len = this.length; i < len; i++) {
            if (array.contains(this[i]))
                continue;

            results.push(this[i]);
        }

        return results.distinct();
    };

    array.prototype.first = function (qry) {
        var result = this.firstOrDefault(qry);

        if (result === null)
            throw "No Results Found";

        return result;
    };

    array.prototype.firstOrDefault = function (qry) {
        var results = typeof qry === 'undefined'
            ? this
            : this.where(qry);

        return results.length > 0
            ? results[0]
            : null;
    };

    array.prototype.groupBy = function (exp) {
        var compiled = compileExp(exp);
        var keys = this.select(compiled).distinct();
        var results = [];

        for (var i = 0, len = keys.length; i < len; i++)
            results.push({
                key: keys[i],
                value: this.where(function (item) {
                    return compiled(item) === keys[i];
                })
            });

        return results;
    };

    array.prototype.groupJoin = function (inner, outerKey, innerKey, zipFn) {
        var iKey = compileExp(innerKey);
        var oKey = compileExp(outerKey);
        var results = [];

        for (var i = 0, len = this.length; i < len; i++) {
            var matches = inner.where(function (item) {
                return compare(oKey(this[i]), iKey(item)) === 0;
            });

            results.push(matches);
        }

        return this.zip(results, zipFn);
    };

    // Same as join from microsoft documentation, however join already exists in ecma and is more of a concat...
    array.prototype.innerJoin = function (inner, outerKey, innerKey, zipFn) {
        var iKey = compileExp(innerKey);
        var oKey = compileExp(outerKey);
        var results = [];

        for (var i = 0; i < this.length; i++) {
            var outerItem = this[i];
            var matches = inner.where(function (item) {
                return compare(oKey(outerItem), iKey(item)) === 0;
            });

            for (var x = 0; x < matches.length; x++)
                results.push(matches[x]);
        }

        return this.zip(results, zipFn);
    };

    array.prototype.intersect = function (array) {
        if (this.length === 0 || array.length === 0)
            return [];

        var results = [];
        for (var i = 0; i < array.length; i++)
            for (var j = 0; j < this.length; j++)
                if (compare(this[j], array[i]) === 0)
                    results.push(this[j]);

        return results.distinct();
    };

    array.prototype.last = function (qry) {
        var result = this.lastOrDefault(qry);

        if (result === null)
            throw "No Results Found";

        return result;
    };

    array.prototype.lastOrDefault = function (qry) {
        var results = typeof qry === 'undefined'
            ? this
            : this.where(qry);

        return results.length > 0
            ? results[results.length - 1]
            : null;
    };

    // Excluding LongCount

    array.prototype.max = function (qry) {
        var results = this.select(qry);
        return Math.max.apply(null, results);
    };

    array.prototype.min = function (qry) {
        var results = this.select(qry);
        return Math.min.apply(null, results);
    };

    // Excluding OfType

    array.prototype.orderBy = function (qry) {
        if (typeof qry === 'undefined')
            return this.sort();

        var compiled = compileExp(qry);

        return this.sort(function (a, b) {
            return compare(compiled(a), compiled(b));
        });
    };

    array.prototype.orderByDescending = function (qry) {
        if (typeof qry === 'undefined')
            return this.sort().reverse();

        return this.orderBy(qry).reverse();
    };

    // Excluding Range

    // Excluding Repeat

    // Reverse already a part of ecma.

    array.prototype.select = function (qry) {
        if (typeof qry === 'undefined')
            return this;

        var compiled = compileExp(qry);
        var results = [];

        for (var i = 0, len = this.length; i < len; i++)
            results.push(compiled(this[i]));

        return results;
    };

    array.prototype.selectMany = function (qry) {
        if (typeof qry === 'undefined')
            return this;

        var results = this.select(qry);
        var array = [];
        for (var i = 0, len = results.length; i < len; i++)
            array = array.union(results[i]);

        return array;
    };

    array.prototype.sequenceEqual = function (array) {
        if (typeof array === 'undefined' || array === null)
            return false;

        if (this.length !== array.length)
            return false;

        for (var i = 0, len = this.length; i < len; i++)
            if (compare(this[i], array[i]) !== 0)
                return false;

        return true;
    };

    array.prototype.single = function () {
        if (this.length !== 1)
            throw "Sequence does not contain a single element.";

        return this[0];
    };

    array.prototype.singleOrDefault = function () {
        if (this.length > 1)
            throw "Sequence does not contain a single element.";

        return this.length === 1
            ? this[0]
            : null;
    };

    array.prototype.skip = function (index) {
        return this.slice(index, this.length);
    };

    array.prototype.skipWhile = function (qry) {
        var compiled = compileExp(qry);
        var results = [];

        for (var i = 0, len = this.length; i < len; i++)
            if (compiled(this[i]) !== true)
                results.push(this[i]);

        return results;
    };

    array.prototype.sum = function () {
        if (this.length === 0)
            return 0;

        var sum = 0;
        for (var i = 0, len = this.length; i < len; i++)
            sum += this[i];
        return sum;
    };

    array.prototype.take = function (count) {
        return this.slice(0, count);
    };

    array.prototype.takeWhile = function (qry) {
        var compiled = compileExp(qry);
        var results = [];

        for (var i = 0, len = this.length; i < len; i++) {
            var item = this[i];
            if (compiled(item) !== true)
                return results;

            results.push(item);
        }

        return results;
    };

    // Excluding ThenBy
    // Excluding ThenByDescending
    // Excluding ToArray ... lol
    // Excluding ToDictionary
    // Excluding ToList
    // Excluding ToLookup

    array.prototype.union = function (array) {
        if (typeof array === 'undefined' || array === null)
            return this;

        return this.concat(array);
    };

    array.prototype.where = function (qry) {
        var compiled = compileExp(qry);
        var results = [];

        for (var i = 0, len = this.length; i < len; i++)
            if (compiled(this[i]) === true)
                results.push(this[i]);

        return results;
    };

    array.prototype.zip = function (second, zipFn) {
        var results = [];

        if (typeof zipFn !== 'function')
            zipFn = compileExp(zipFn);

        for (var i = 0, len = this.length; i < len; i++)
            if (second.length > i)
                results.push(zipFn(this[i], second[i]));

        return results;
    };

    // Comparison and compilation expressions

    var compileExp = exports.compileExp = function (exp) {
        if (typeof exp === 'undefined')
            throw "Expression is invalid.";

        if (typeof exp === 'function')
            return exp;

        var parts = exp.split('=>');
        var arg = parts.length > 0 ? parts[0].trim().replace(/\(|\)/g, '') : null;
        var func = parts.length > 1 ? parts[1].trim() : null;

        if (arg === null || func === null)
            throw "Expression is invalid.";

        return new Function(arg, 'return (' + func + ');');
    };

    var compare = exports.compare = function (obj1, obj2) {
        if (typeof obj1 === 'undefined' || typeof obj2 === 'undefined')
            return typeof obj1 === 'undefined' ? -1 : (typeof obj2 === 'undefined' ? 1 : 0);

        if (typeof obj1 !== typeof obj2)
            throw "Both objects must be of the same type";

        if (obj1.compare)
            return obj1.compare(obj2);

        if (typeof obj1 === 'string') {
            var hash1 = obj1.hashCode();
            var hash2 = obj2.hashCode();

            return hash1 < hash2 ? -1 : (hash1 > hash2 ? 1 : 0);
        }

        if (typeof obj1 === 'number')
            return obj1 < obj2 ? -1 : (obj1 > obj2 ? 1 : 0);

        if (typeof obj1 === 'boolean')
            return obj1 === obj2 ? 0 : (obj1 ? 1 : -1);

        if (typeof obj1 === 'function') {
            var val1 = obj1();
            var val2 = obj2();

            return compare(val1, val2);
        }

        if (typeof obj1 === 'object') {
            var result = 0;
            for (var key in obj1) {
                var temp = compare(obj1[key], obj2[key]);
                if (temp === -1) return temp;
                result = Math.max(result, temp);
            }
            return result;
        }

        throw "Unable to compare objects";
    };
})(Array, String, (typeof module !== 'undefined' && module.exports) || window);
<|endoftext|>


<commit_before>import { Schema, arrayOf, normalize } from 'normalizr'
import { camelizeKeys } from 'humps'

// Extracts the next page URL from Github API response.
const getNextPageUrl = response => {
  const link = response.headers.get('link')
  if (!link) {
    return null
  }

  const nextLink = link.split(',').find(s => s.indexOf('rel="next"') > -1)
  if (!nextLink) {
    return null
  }

  return nextLink.split(';')[0].slice(1, -1)
}

const API_ROOT = 'https://api.github.com/'

// Fetches an API response and normalizes the result JSON according to schema.
// This makes every API response have the same shape, regardless of how nested it was.
const callApi = (endpoint, schema) => {
  const fullUrl = (endpoint.indexOf(API_ROOT) === -1) ? API_ROOT + endpoint : endpoint

  return fetch(fullUrl)
    .then(response =>
      response.json().then(json => ({ json, response }))
    ).then(({ json, response }) => {
      if (!response.ok) {
        return Promise.reject(json)
      }

      const camelizedJson = camelizeKeys(json)
      const nextPageUrl = getNextPageUrl(response)

      return Object.assign({},
        normalize(camelizedJson, schema),
        { nextPageUrl }
      )
    })
}

// We use this Normalizr schemas to transform API responses from a nested form
// to a flat form where repos and users are placed in `entities`, and nested
// JSON objects are replaced with their IDs. This is very convenient for
// consumption by reducers, because we can easily build a normalized tree
// and keep it updated as we fetch more data.

// Read more about Normalizr: https://github.com/paularmstrong/normalizr

// GitHub's API may return results with uppercase letters while the query
// doesn't contain any. For example, "someuser" could result in "SomeUser"
// leading to a frozen UI as it wouldn't find "someuser" in the entities.
// That's why we're forcing lower cases down there.

const userSchema = new Schema('users', {
  idAttribute: user => user.login.toLowerCase()
})

const repoSchema = new Schema('repos', {
  idAttribute: repo => repo.fullName.toLowerCase()
})

repoSchema.define({
  owner: userSchema
})

// Schemas for Github API responses.
export const Schemas = {
  USER: userSchema,
  USER_ARRAY: arrayOf(userSchema),
  REPO: repoSchema,
  REPO_ARRAY: arrayOf(repoSchema)
}

// Action key that carries API call info interpreted by this Redux middleware.
export const CALL_API = Symbol('Call API')

// A Redux middleware that interprets actions with CALL_API info specified.
// Performs the call and promises when such actions are dispatched.
export default store => next => action => {
  const callAPI = action[CALL_API]
  if (typeof callAPI === 'undefined') {
    return next(action)
  }

  let { endpoint } = callAPI
  const { schema, types } = callAPI

  if (typeof endpoint === 'function') {
    endpoint = endpoint(store.getState())
  }

  if (typeof endpoint !== 'string') {
    throw new Error('Specify a string endpoint URL.')
  }
  if (!schema) {
    throw new Error('Specify one of the exported Schemas.')
  }
  if (!Array.isArray(types) || types.length !== 3) {
    throw new Error('Expected an array of three action types.')
  }
  if (!types.every(type => typeof type === 'string')) {
    throw new Error('Expected action types to be strings.')
  }

  const actionWith = data => {
    const finalAction = Object.assign({}, action, data)
    delete finalAction[CALL_API]
    return finalAction
  }

  const [ requestType, successType, failureType ] = types
  next(actionWith({ type: requestType }))

  return callApi(endpoint, schema).then(
    response => next(actionWith({
      response,
      type: successType
    })),
    error => next(actionWith({
      type: failureType,
      error: error.message || 'Something bad happened'
    }))
  )
}
<commit_msg>Simplify Promise nesting (#2007)<commit_after>import { Schema, arrayOf, normalize } from 'normalizr'
import { camelizeKeys } from 'humps'

// Extracts the next page URL from Github API response.
const getNextPageUrl = response => {
  const link = response.headers.get('link')
  if (!link) {
    return null
  }

  const nextLink = link.split(',').find(s => s.indexOf('rel="next"') > -1)
  if (!nextLink) {
    return null
  }

  return nextLink.split(';')[0].slice(1, -1)
}

const API_ROOT = 'https://api.github.com/'

// Fetches an API response and normalizes the result JSON according to schema.
// This makes every API response have the same shape, regardless of how nested it was.
const callApi = (endpoint, schema) => {
  const fullUrl = (endpoint.indexOf(API_ROOT) === -1) ? API_ROOT + endpoint : endpoint

  return fetch(fullUrl)
    .then(response =>
      response.json().then(json => {
        if (!response.ok) {
          return Promise.reject(json)
        }

        const camelizedJson = camelizeKeys(json)
        const nextPageUrl = getNextPageUrl(response)

        return Object.assign({},
          normalize(camelizedJson, schema),
          { nextPageUrl }
        )
      })
    )
}

// We use this Normalizr schemas to transform API responses from a nested form
// to a flat form where repos and users are placed in `entities`, and nested
// JSON objects are replaced with their IDs. This is very convenient for
// consumption by reducers, because we can easily build a normalized tree
// and keep it updated as we fetch more data.

// Read more about Normalizr: https://github.com/paularmstrong/normalizr

// GitHub's API may return results with uppercase letters while the query
// doesn't contain any. For example, "someuser" could result in "SomeUser"
// leading to a frozen UI as it wouldn't find "someuser" in the entities.
// That's why we're forcing lower cases down there.

const userSchema = new Schema('users', {
  idAttribute: user => user.login.toLowerCase()
})

const repoSchema = new Schema('repos', {
  idAttribute: repo => repo.fullName.toLowerCase()
})

repoSchema.define({
  owner: userSchema
})

// Schemas for Github API responses.
export const Schemas = {
  USER: userSchema,
  USER_ARRAY: arrayOf(userSchema),
  REPO: repoSchema,
  REPO_ARRAY: arrayOf(repoSchema)
}

// Action key that carries API call info interpreted by this Redux middleware.
export const CALL_API = Symbol('Call API')

// A Redux middleware that interprets actions with CALL_API info specified.
// Performs the call and promises when such actions are dispatched.
export default store => next => action => {
  const callAPI = action[CALL_API]
  if (typeof callAPI === 'undefined') {
    return next(action)
  }

  let { endpoint } = callAPI
  const { schema, types } = callAPI

  if (typeof endpoint === 'function') {
    endpoint = endpoint(store.getState())
  }

  if (typeof endpoint !== 'string') {
    throw new Error('Specify a string endpoint URL.')
  }
  if (!schema) {
    throw new Error('Specify one of the exported Schemas.')
  }
  if (!Array.isArray(types) || types.length !== 3) {
    throw new Error('Expected an array of three action types.')
  }
  if (!types.every(type => typeof type === 'string')) {
    throw new Error('Expected action types to be strings.')
  }

  const actionWith = data => {
    const finalAction = Object.assign({}, action, data)
    delete finalAction[CALL_API]
    return finalAction
  }

  const [ requestType, successType, failureType ] = types
  next(actionWith({ type: requestType }))

  return callApi(endpoint, schema).then(
    response => next(actionWith({
      response,
      type: successType
    })),
    error => next(actionWith({
      type: failureType,
      error: error.message || 'Something bad happened'
    }))
  )
}
<|endoftext|>


<commit_before>import { subscribe } from 'alfa'
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import classnames from 'classnames'
import { SHOW_ALL, SHOW_COMPLETED, SHOW_ACTIVE } from '../constants/TodoFilters'

const FILTER_TITLES = {
  [SHOW_ALL]: 'All',
  [SHOW_ACTIVE]: 'Active',
  [SHOW_COMPLETED]: 'Completed'
}

class Footer extends Component {
  static propTypes = {
    filter: PropTypes.string.isRequired,
    activeCount: PropTypes.number.isRequired,
    completedCount: PropTypes.number.isRequired,
    clearCompleted: PropTypes.func.isRequired
  }

  renderTodoCount() {
    const { activeCount } = this.props
    const itemWord = 1 === activeCount ? 'item' : 'items'

    return (

        {activeCount || 'No'} {itemWord} left

    )
  }

  renderFilterLink(filter) {
    const title = FILTER_TITLES[filter]
    const { filter: selectedFilter } = this.props
    const css = classnames({
      selected: filter === selectedFilter
    })
    return (
       this.props.set('filter', filter)}
      >
        {title}

    )
  }

  renderClearButton() {
    const { completedCount, clearCompleted } = this.props
    if (completedCount > 0) {
      return (
        <button className="clear-completed" onClick={() => clearCompleted()}>
          Clear completed
        </button>
      )
    }
  }

  render() {
    return (

        {this.renderTodoCount()}

          {[SHOW_ALL, SHOW_ACTIVE, SHOW_COMPLETED].map(filter => (

{this.renderFilterLink(filter)}

          ))}

        {this.renderClearButton()}

    )
  }
}

export default subscribe(
  Footer,
  ['set', 'filter', 'clearCompleted'],
  ['todos', 'filter']
)
<commit_msg>Add anchor for filter button.<commit_after>import { subscribe } from 'alfa'
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import classnames from 'classnames'
import { SHOW_ALL, SHOW_COMPLETED, SHOW_ACTIVE } from '../constants/TodoFilters'

const FILTER_TITLES = {
  [SHOW_ALL]: 'All',
  [SHOW_ACTIVE]: 'Active',
  [SHOW_COMPLETED]: 'Completed'
}

class Footer extends Component {
  static propTypes = {
    filter: PropTypes.string.isRequired,
    activeCount: PropTypes.number.isRequired,
    completedCount: PropTypes.number.isRequired,
    clearCompleted: PropTypes.func.isRequired
  }

  renderTodoCount() {
    const { activeCount } = this.props
    const itemWord = 1 === activeCount ? 'item' : 'items'

    return (

        {activeCount || 'No'} {itemWord} left

    )
  }

  renderFilterLink(filter) {
    const title = FILTER_TITLES[filter]
    const { filter: selectedFilter } = this.props
    const css = classnames({
      selected: filter === selectedFilter
    })
    return (
      <a
        href={`#filter-${filter}`}
        style={{ cursor: 'pointer' }}
        onClick={() => this.props.set('filter', filter)}
        className={css}
      >
        {title}

    )
  }

  renderClearButton() {
    const { completedCount, clearCompleted } = this.props
    if (completedCount > 0) {
      return (
        <button className="clear-completed" onClick={() => clearCompleted()}>
          Clear completed
        </button>
      )
    }
  }

  render() {
    return (

        {this.renderTodoCount()}

          {[SHOW_ALL, SHOW_ACTIVE, SHOW_COMPLETED].map(filter => (

{this.renderFilterLink(filter)}

          ))}

        {this.renderClearButton()}

    )
  }
}

export default subscribe(
  Footer,
  ['set', 'filter', 'clearCompleted'],
  ['todos', 'filter']
)
<|endoftext|>


<commit_before>/**
 * Created by Lei on 2015/6/9.
 */

yii.actionColumn = (function ($) {

    var pub = {
        clickableSelector: 'a.action-delete, a.action-refresh',
        isActive: true,
        params : {},
        getCsrfParam: function () {
            return $('meta[name=csrf-param]').prop('content');
        },
        getCsrfToken: function () {
            return $('meta[name=csrf-token]').prop('content');
        },
        setCsrfToken: function (name, value) {
            $('meta[name=csrf-param]').prop('content', name);
            $('meta[name=csrf-token]').prop('content', value)
        },
        refreshCsrfToken: function () {
            var token = pub.getCsrfToken();
            if (token) {
                pub.params[pub.getCsrfParam()] = token;
            }
        },
        confirm: function (message, ok, cancel) {
            if (confirm(message)) {
                !ok || ok();
            } else {
                !cancel || cancel();
            }
        },
        handleAction: function ($e) {
            var method = $e.data('method'),
                url = $e.attr('href'),
                action = $e.data('action'),
                params = $e.data('params');

            //通过Ajax处理删除和刷新
            if (!url || !url.match(/(^\/|:\/\/)/)) {
                url = window.location.href;
            }
            $.extend(pub.params,params);
            $.post(
                url,
                pub.params,
                function(res){
                    if(action == 'delete') $e.parents('tr').hide();
                    if(typeof (res.data) == 'string') {
                        pub.notify({type:res.status == 1?'success':'error',title:res.data});
                    } else {
                        pub.notify(res.data);
                    }
                },
                'json'
            );
            return;
        },
        init: function () {
            initDataMethods();
        },
        notify : function(data){
            if(!data) return;
            if(data.type == undefined || data.title == undefined) return;
            toastr.options = {"closeButton":true,"debug":false,"positionClass":"toast-top-right","onclick":null,"showDuration":"1000","hideDuration":"1000","timeOut":"5000","extendedTimeOut":"1000","showEasing":"swing","hideEasing":"linear","showMethod":"fadeIn","hideMethod":"fadeOut"};
            toastr[data.type](data.content == undefined ? null:data.content,data.title);
        }

    };

    function initDataMethods() {
        var handler = function (event) {
            var $this = $(this),
                method = $this.data('method'),
                message = $this.data('confirm');
            if (method === undefined && message === undefined) {
                return true;
            }
            if (message !== undefined) {
                pub.confirm(message, function () {
                    pub.handleAction($this);
                });
            } else {
                pub.handleAction($this);
            }
            event.stopImmediatePropagation();
            return false;
        };
        pub.refreshCsrfToken();
        $(pub.clickableSelector).off('click.yii')
            .on('click.yiiAction',  handler);
    }

    return pub;

})(jQuery);<commit_msg>完善action-column删除操作<commit_after>/**
 * Created by Lei on 2015/6/9.
 */

yii.actionColumn = (function ($) {

    var pub = {
        clickableSelector: 'a.action-delete, a.action-refresh',
        isActive: true,
        params : {},
        getCsrfParam: function () {
            return $('meta[name=csrf-param]').prop('content');
        },
        getCsrfToken: function () {
            return $('meta[name=csrf-token]').prop('content');
        },
        setCsrfToken: function (name, value) {
            $('meta[name=csrf-param]').prop('content', name);
            $('meta[name=csrf-token]').prop('content', value)
        },
        refreshCsrfToken: function () {
            var token = pub.getCsrfToken();
            if (token) {
                pub.params[pub.getCsrfParam()] = token;
            }
        },
        confirm: function (message, ok, cancel) {
            if (confirm(message)) {
                !ok || ok();
            } else {
                !cancel || cancel();
            }
        },
        handleAction: function ($e) {
            var method = $e.data('method'),
                url = $e.attr('href'),
                action = $e.data('action'),
                params = $e.data('params');

            //通过Ajax处理删除和刷新
            if (!url || !url.match(/(^\/|:\/\/)/)) {
                url = window.location.href;
            }
            $.extend(pub.params,params);
            $.post(
                url,
                pub.params,
                function(res){
                    if(action == 'delete'&&res.status == 1) $e.parents('tr').hide();
                    if(typeof (res.data) == 'string') {
                        pub.notify({type:res.status == 1?'success':'error',title:res.data});
                    } else {
                        pub.notify(res.data);
                    }
                },
                'json'
            );
            return;
        },
        init: function () {
            initDataMethods();
        },
        notify : function(data){
            if(!data) return;
            if(data.type == undefined || data.title == undefined) return;
            toastr.options = {"closeButton":true,"debug":false,"positionClass":"toast-top-right","onclick":null,"showDuration":"1000","hideDuration":"1000","timeOut":"5000","extendedTimeOut":"1000","showEasing":"swing","hideEasing":"linear","showMethod":"fadeIn","hideMethod":"fadeOut"};
            toastr[data.type](data.content == undefined ? null:data.content,data.title);
        }

    };

    function initDataMethods() {
        var handler = function (event) {
            var $this = $(this),
                method = $this.data('method'),
                message = $this.data('confirm');
            if (method === undefined && message === undefined) {
                return true;
            }
            if (message !== undefined) {
                pub.confirm(message, function () {
                    pub.handleAction($this);
                });
            } else {
                pub.handleAction($this);
            }
            event.stopImmediatePropagation();
            return false;
        };
        pub.refreshCsrfToken();
        $(pub.clickableSelector).off('click.yii')
            .on('click.yiiAction',  handler);
    }

    return pub;

})(jQuery);<|endoftext|>