<commit_before>/*!
 * @preserve
 *
 * Readmore.js jQuery plugin
 * Author: @jed_foster
 * Project home: http://jedfoster.github.io/Readmore.js
 * Licensed under the MIT license
 *
 * Debounce function from http://davidwalsh.name/javascript-debounce-function
 */

/* global jQuery */

(function(factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD
    define(['jquery'], factory);
  } else if (typeof exports === 'object') {
    // CommonJS
    module.exports = factory(require('jquery'));
  } else {
    // Browser globals
    factory(jQuery);
  }
}(function($) {
  'use strict';

  var readmore = 'readmore',
      defaults = {
        speed: 100,
        collapsedHeight: 200,
        heightMargin: 16,
        moreLink: 'Read More',
        lessLink: 'Close',
        embedCSS: true,
        blockCSS: 'display: block; width: 100%;',
        startOpen: false,

        // callbacks
        beforeToggle: function(){},
        afterToggle: function(){}
      },
      cssEmbedded = {},
      uniqueIdCounter = 0;

  function debounce(func, wait, immediate) {
    var timeout;

    return function() {
      var context = this, args = arguments;
      var later = function() {
        timeout = null;
        if (! immediate) {
          func.apply(context, args);
        }
      };
      var callNow = immediate && !timeout;

      clearTimeout(timeout);
      timeout = setTimeout(later, wait);

      if (callNow) {
        func.apply(context, args);
      }
    };
  }

  function uniqueId(prefix) {
    var id = ++uniqueIdCounter;

    return String(prefix == null ? 'rmjs-' : prefix) + id;
  }

  function setBoxHeights(element) {
    var el = element.clone().css({
          height: 'auto',
          width: element.width(),
          maxHeight: 'none',
          overflow: 'hidden'
        }).insertAfter(element),
        expandedHeight = el.outerHeight(),
        cssMaxHeight = parseInt(el.css({maxHeight: ''}).css('max-height').replace(/[^-\d\.]/g, ''), 10),
        defaultHeight = element.data('defaultHeight');

    el.remove();

    var collapsedHeight = cssMaxHeight || element.data('collapsedHeight') || defaultHeight;

    // Store our measurements.
    element.data({
      expandedHeight: expandedHeight,
      maxHeight: cssMaxHeight,
      collapsedHeight: collapsedHeight
    })
    // and disable any `max-height` property set in CSS
    .css({
      maxHeight: 'none'
    });
  }

  var resizeBoxes = debounce(function() {
    $('[data-readmore]').each(function() {
      var current = $(this),
          isExpanded = (current.attr('aria-expanded') === 'true');

      setBoxHeights(current);

      current.css({
        height: current.data( (isExpanded ? 'expandedHeight' : 'collapsedHeight') )
      });
    });
  }, 100);

  function embedCSS(options) {
    if (! cssEmbedded[options.selector]) {
      var styles = ' ';

      if (options.embedCSS && options.blockCSS !== '') {
        styles += options.selector + ' + [data-readmore-toggle], ' +
          options.selector + '[data-readmore]{' +
            options.blockCSS +
          '}';
      }

      // Include the transition CSS even if embedCSS is false
      styles += options.selector + '[data-readmore]{' +
        'transition: height ' + options.speed + 'ms;' +
        'overflow: hidden;' +
      '}';

      (function(d, u) {
        var css = d.createElement('style');
        css.type = 'text/css';

        if (css.styleSheet) {
          css.styleSheet.cssText = u;
        }
        else {
          css.appendChild(d.createTextNode(u));
        }

        d.getElementsByTagName('head')[0].appendChild(css);
      }(document, styles));

      cssEmbedded[options.selector] = true;
    }
  }

  function Readmore(element, options) {
    this.element = element;

    this.options = $.extend({}, defaults, options);

    embedCSS(this.options);

    this._defaults = defaults;
    this._name = readmore;

    this.init();

    // IE8 chokes on `window.addEventListener`, so need to test for support.
    if (window.addEventListener) {
      // Need to resize boxes when the page has fully loaded.
      window.addEventListener('load', resizeBoxes);
      window.addEventListener('resize', resizeBoxes);
    }
    else {
      window.attachEvent('load', resizeBoxes);
      window.attachEvent('resize', resizeBoxes);
    }
  }

  Readmore.prototype = {
    init: function() {
      var current = $(this.element);

      current.data({
        defaultHeight: this.options.collapsedHeight,
        heightMargin: this.options.heightMargin
      });

      setBoxHeights(current);

      var collapsedHeight = current.data('collapsedHeight'),
          heightMargin = current.data('heightMargin');

      if (current.outerHeight(true) <= collapsedHeight + heightMargin) {
        // The block is shorter than the limit, so there's no need to truncate it.
        return true;
      }
      else {
        var id = current.attr('id') || uniqueId(),
            useLink = this.options.startOpen ? this.options.lessLink : this.options.moreLink;

        current.attr({
          'data-readmore': '',
          'aria-expanded': $this.options.startOpen,
          'id': id
        });

        current.after($(useLink)
          .on('click', (function(_this) {
            return function(event) {
              _this.toggle(this, current[0], event);
            };
          })(this))
          .attr({
            'data-readmore-toggle': '',
            'aria-controls': id
          }));

        if (! this.options.startOpen) {
          current.css({
            height: collapsedHeight
          });
        }
      }
    },

    toggle: function(trigger, element, event) {
      if (event) {
        event.preventDefault();
      }

      if (! trigger) {
        trigger = $('[aria-controls="' + _this.element.id + '"]')[0];
      }

      if (! element) {
        element = _this.element;
      }

      var $element = $(element),
          newHeight = '',
          newLink = '',
          expanded = false,
          collapsedHeight = $element.data('collapsedHeight');

      if ($element.height() <= collapsedHeight) {
        newHeight = $element.data('expandedHeight') + 'px';
        newLink = 'lessLink';
        expanded = true;
      }
      else {
        newHeight = collapsedHeight;
        newLink = 'moreLink';
      }

      // Fire beforeToggle callback
      // Since we determined the new "expanded" state above we're now out of sync
      // with our true current state, so we need to flip the value of `expanded`
      this.options.beforeToggle(trigger, $element, ! expanded);

      $element.css({'height': newHeight});

      // Fire afterToggle callback
      $element.on('transitionend', (function(_this) {
        return function() {
          _this.options.afterToggle(trigger, $element, expanded);

          $(this).attr({
            'aria-expanded': expanded
          }).off('transitionend');
        }
      })(this));

      $(trigger).replaceWith($(this.options[newLink])
        .on('click', (function(_this) {
            return function(event) {
              _this.toggle(this, element, event);
            };
          })(this))
        .attr({
          'data-readmore-toggle': '',
          'aria-controls': $element.attr('id')
        }));
    },

    destroy: function() {
      $(this.element).each(function() {
        var current = $(this);

        current.attr({
          'data-readmore': null,
          'aria-expanded': null
        })
          .css({
            maxHeight: '',
            height: ''
          })
          .next('[data-readmore-toggle]')
          .remove();

        current.removeData();
      });
    }
  };

  $.fn.readmore = function(options) {
    var args = arguments,
        selector = this.selector;

    options = options || {};

    if (typeof options === 'object') {
      return this.each(function() {
        if ($.data(this, 'plugin_' + readmore)) {
          var instance = $.data(this, 'plugin_' + readmore);
          instance.destroy.apply(instance);
        }

        options.selector = selector;

        $.data(this, 'plugin_' + readmore, new Readmore(this, options));
      });
    }
    else if (typeof options === 'string' && options[0] !== '_' && options !== 'init') {
      return this.each(function () {
        var instance = $.data(this, 'plugin_' + readmore);
        if (instance instanceof Readmore && typeof instance[options] === 'function') {
          instance[options].apply(instance, Array.prototype.slice.call(args, 1));
        }
      });
    }
  };

}));

<commit_msg>Fix merge conflict<commit_after>/*!
 * @preserve
 *
 * Readmore.js jQuery plugin
 * Author: @jed_foster
 * Project home: http://jedfoster.github.io/Readmore.js
 * Licensed under the MIT license
 *
 * Debounce function from http://davidwalsh.name/javascript-debounce-function
 */

/* global jQuery */

(function(factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD
    define(['jquery'], factory);
  } else if (typeof exports === 'object') {
    // CommonJS
    module.exports = factory(require('jquery'));
  } else {
    // Browser globals
    factory(jQuery);
  }
}(function($) {
  'use strict';

  var readmore = 'readmore',
      defaults = {
        speed: 100,
        collapsedHeight: 200,
        heightMargin: 16,
        moreLink: 'Read More',
        lessLink: 'Close',
        embedCSS: true,
        blockCSS: 'display: block; width: 100%;',
        startOpen: false,

        // callbacks
        beforeToggle: function(){},
        afterToggle: function(){}
      },
      cssEmbedded = {},
      uniqueIdCounter = 0;

  function debounce(func, wait, immediate) {
    var timeout;

    return function() {
      var context = this, args = arguments;
      var later = function() {
        timeout = null;
        if (! immediate) {
          func.apply(context, args);
        }
      };
      var callNow = immediate && !timeout;

      clearTimeout(timeout);
      timeout = setTimeout(later, wait);

      if (callNow) {
        func.apply(context, args);
      }
    };
  }

  function uniqueId(prefix) {
    var id = ++uniqueIdCounter;

    return String(prefix == null ? 'rmjs-' : prefix) + id;
  }

  function setBoxHeights(element) {
    var el = element.clone().css({
          height: 'auto',
          width: element.width(),
          maxHeight: 'none',
          overflow: 'hidden'
        }).insertAfter(element),
        expandedHeight = el.outerHeight(),
        cssMaxHeight = parseInt(el.css({maxHeight: ''}).css('max-height').replace(/[^-\d\.]/g, ''), 10),
        defaultHeight = element.data('defaultHeight');

    el.remove();

    var collapsedHeight = cssMaxHeight || element.data('collapsedHeight') || defaultHeight;

    // Store our measurements.
    element.data({
      expandedHeight: expandedHeight,
      maxHeight: cssMaxHeight,
      collapsedHeight: collapsedHeight
    })
    // and disable any `max-height` property set in CSS
    .css({
      maxHeight: 'none'
    });
  }

  var resizeBoxes = debounce(function() {
    $('[data-readmore]').each(function() {
      var current = $(this),
          isExpanded = (current.attr('aria-expanded') === 'true');

      setBoxHeights(current);

      current.css({
        height: current.data( (isExpanded ? 'expandedHeight' : 'collapsedHeight') )
      });
    });
  }, 100);

  function embedCSS(options) {
    if (! cssEmbedded[options.selector]) {
      var styles = ' ';

      if (options.embedCSS && options.blockCSS !== '') {
        styles += options.selector + ' + [data-readmore-toggle], ' +
          options.selector + '[data-readmore]{' +
            options.blockCSS +
          '}';
      }

      // Include the transition CSS even if embedCSS is false
      styles += options.selector + '[data-readmore]{' +
        'transition: height ' + options.speed + 'ms;' +
        'overflow: hidden;' +
      '}';

      (function(d, u) {
        var css = d.createElement('style');
        css.type = 'text/css';

        if (css.styleSheet) {
          css.styleSheet.cssText = u;
        }
        else {
          css.appendChild(d.createTextNode(u));
        }

        d.getElementsByTagName('head')[0].appendChild(css);
      }(document, styles));

      cssEmbedded[options.selector] = true;
    }
  }

  function Readmore(element, options) {
    this.element = element;

    this.options = $.extend({}, defaults, options);

    embedCSS(this.options);

    this._defaults = defaults;
    this._name = readmore;

    this.init();

    // IE8 chokes on `window.addEventListener`, so need to test for support.
    if (window.addEventListener) {
      // Need to resize boxes when the page has fully loaded.
      window.addEventListener('load', resizeBoxes);
      window.addEventListener('resize', resizeBoxes);
    }
    else {
      window.attachEvent('load', resizeBoxes);
      window.attachEvent('resize', resizeBoxes);
    }
  }

  Readmore.prototype = {
    init: function() {
      var current = $(this.element);

      current.data({
        defaultHeight: this.options.collapsedHeight,
        heightMargin: this.options.heightMargin
      });

      setBoxHeights(current);

      var collapsedHeight = current.data('collapsedHeight'),
          heightMargin = current.data('heightMargin');

      if (current.outerHeight(true) <= collapsedHeight + heightMargin) {
        // The block is shorter than the limit, so there's no need to truncate it.
        return true;
      }
      else {
        var id = current.attr('id') || uniqueId(),
            useLink = this.options.startOpen ? this.options.lessLink : this.options.moreLink;

        current.attr({
          'data-readmore': '',
          'aria-expanded': this.options.startOpen,
          'id': id
        });

        current.after($(useLink)
          .on('click', (function(_this) {
            return function(event) {
              _this.toggle(this, current[0], event);
            };
          })(this))
          .attr({
            'data-readmore-toggle': '',
            'aria-controls': id
          }));

        if (! this.options.startOpen) {
          current.css({
            height: collapsedHeight
          });
        }
      }
    },

    toggle: function(trigger, element, event) {
      if (event) {
        event.preventDefault();
      }

      if (! trigger) {
        trigger = $('[aria-controls="' + _this.element.id + '"]')[0];
      }

      if (! element) {
        element = _this.element;
      }

      var $element = $(element),
          newHeight = '',
          newLink = '',
          expanded = false,
          collapsedHeight = $element.data('collapsedHeight');

      if ($element.height() <= collapsedHeight) {
        newHeight = $element.data('expandedHeight') + 'px';
        newLink = 'lessLink';
        expanded = true;
      }
      else {
        newHeight = collapsedHeight;
        newLink = 'moreLink';
      }

      // Fire beforeToggle callback
      // Since we determined the new "expanded" state above we're now out of sync
      // with our true current state, so we need to flip the value of `expanded`
      this.options.beforeToggle(trigger, $element, ! expanded);

      $element.css({'height': newHeight});

      // Fire afterToggle callback
      $element.on('transitionend', (function(_this) {
        return function() {
          _this.options.afterToggle(trigger, $element, expanded);

          $(this).attr({
            'aria-expanded': expanded
          }).off('transitionend');
        }
      })(this));

      $(trigger).replaceWith($(this.options[newLink])
        .on('click', (function(_this) {
            return function(event) {
              _this.toggle(this, element, event);
            };
          })(this))
        .attr({
          'data-readmore-toggle': '',
          'aria-controls': $element.attr('id')
        }));
    },

    destroy: function() {
      $(this.element).each(function() {
        var current = $(this);

        current.attr({
          'data-readmore': null,
          'aria-expanded': null
        })
          .css({
            maxHeight: '',
            height: ''
          })
          .next('[data-readmore-toggle]')
          .remove();

        current.removeData();
      });
    }
  };

  $.fn.readmore = function(options) {
    var args = arguments,
        selector = this.selector;

    options = options || {};

    if (typeof options === 'object') {
      return this.each(function() {
        if ($.data(this, 'plugin_' + readmore)) {
          var instance = $.data(this, 'plugin_' + readmore);
          instance.destroy.apply(instance);
        }

        options.selector = selector;

        $.data(this, 'plugin_' + readmore, new Readmore(this, options));
      });
    }
    else if (typeof options === 'string' && options[0] !== '_' && options !== 'init') {
      return this.each(function () {
        var instance = $.data(this, 'plugin_' + readmore);
        if (instance instanceof Readmore && typeof instance[options] === 'function') {
          instance[options].apply(instance, Array.prototype.slice.call(args, 1));
        }
      });
    }
  };

}));

<|endoftext|>


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

    var PageController = ['$scope', '$state', function($scope, $state) {

    }]

    return {
        PageController: PageController,
    };
})<commit_msg>Redirect old game board links to new /questions route.<commit_after>/**
 * Copyright 2015 Ian Davies
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 *
 * You may obtain a copy of the License at
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
define([], function() {

    var PageController = ['$scope', '$state', '$location', function($scope, $state, $location) {

        // Check whether someone has arrived at the homepage trying to load a game board. If so,
        // redirect them to the new /questions route.
        var hash = $location.hash();

        if (hash) {
            console.debug("HASH", hash);
            $location.replace();
            $location.url("/questions#" + hash);
        }
    }]

    return {
        PageController: PageController,
    };
})<|endoftext|>


<commit_before>chrome.webRequest.onBeforeRequest.addListener(
    function(details) {
        console.log('original url: ' + details.url);
        if (details.url.slice(-15) === 'crossdomain.xml') {
            console.log("direct return");
            return {};
        }

        var target_host = details.url.match(/:\/\/(.[^\/]+)/)[1];
        var target_path = details.url.slice('http://'.length + target_host.length);
        var redirect_url = 'http://' + target_host + '.unblock-youku-api.zhuzhu.org' + target_path;
        console.log('redirect url: ' + redirect_url);

        return {redirectUrl: redirect_url};
    },

    {
        urls: [
            'http://hot.vrs.sohu.com/*',
            'http://hot.vrs.letv.com/*',
            'http://data.video.qiyi.com/*',
            'http://vv.video.qq.com/*',
            'http://geo.js.kankan.xunlei.com/*',
            'http://v2.tudou.com/*',
            'http://web-play.pptv.com/*',
            'http://dyn.ugc.pps.tv/*',
            'http://s.plcloud.music.qq.com/*',
            'http://inner.kandian.com/*',
            'http://ipservice.163.com/*',
            'http://zb.s.qq.com/*',

            'http://v.youku.com/player/*',
            'http://v.iask.com/v_play.php*'
            //'http://*.gougou.com/*'
        ]
    },

    ["blocking"]);
<commit_msg>fixed a server-side bug; most sites are working now<commit_after>chrome.webRequest.onBeforeRequest.addListener(
    function(details) {
        console.log('original url: ' + details.url);
        if (details.url.slice(-15) === 'crossdomain.xml') {
            console.log('directly pass');
            return {};
        }

        var target_host = details.url.match(/:\/\/(.[^\/]+)/)[1];
        var target_path = details.url.slice('http://'.length + target_host.length);
        var redirect_url = 'http://' + target_host + '.unblock-youku-api.zhuzhu.org' + target_path;
        console.log('redirect url: ' + redirect_url);

        return {redirectUrl: redirect_url};
    },

    {
        urls: [
            'http://hot.vrs.sohu.com/*',
            'http://hot.vrs.letv.com/*',
            'http://data.video.qiyi.com/*',
            'http://vv.video.qq.com/*',
            'http://geo.js.kankan.xunlei.com/*',
            'http://v2.tudou.com/*',
            'http://web-play.pptv.com/*',
            'http://dyn.ugc.pps.tv/*',
            'http://s.plcloud.music.qq.com/*',
            'http://inner.kandian.com/*',
            'http://ipservice.163.com/*',
            'http://zb.s.qq.com/*',
            'http://ip.kankan.xunlei.com/*',

            'http://v.youku.com/player/*',
            'http://v.iask.com/v_play.php*'
            //'http://*.gougou.com/*'
        ]
    },

    ["blocking"]);
<|endoftext|>


<commit_before>'use strict';
const vscode = require('vscode'),
    beautify = require('js-beautify'),
	path = require('path'),
	os = require('os'),
	fs = require('fs'),
	minimatch = require('minimatch'),
    options = require('./options');

const dumpError = e => {
	if (e) console.log('beautify err:', e);
	return [];
};

exports.activate = context => {
    context.subscriptions.push(vscode.commands.registerCommand('HookyQR.beautify', () => {
		const active = vscode.window.activeTextEditor;
		if (!active || !active.document) return;
		let range = fullRange(active.document);
		return beautifyDoc(active.document, range)
			.then(newText => active.edit(editor => editor.replace(range, newText)), dumpError);
	}));
};

<commit_msg>remove junk file<commit_after><|endoftext|>


<commit_before>(function () {
    'use strict';

    // Define object config of properties for this chart directive
    var BubbleChartDefaults = {
        plotWidth: 500,
        plotHeight:500,
        bubblePadding: 25,
        lazyLoad: true,
        transitionTime: 500
    };

    /**
     * ngInject
     */
    function bubbleChart (BubbleChartDefaults, CartoConfig, MOSColors) {

        var PLOT_CLASS = 'mos-bubblechart';

        // Private vars
        var chart = null;
        var pack = null;
        var tip = null;

        // Begin directive module definition
        var module = {};

        module.restrict = 'EA';
        module.templateUrl = 'scripts/charting/bubblechart-partial.html';

        module.controller = 'ChartingController';

        module.scope = {
            data: '=',              // Required
            id: '@',                // Required
            plotWidth: '@',
            plotHeight: '@',
            bubblePadding: '@',
            lazyLoad: '@',
            transitionTime: '@'
        };

        module.link = function ($scope, element, attrs) {
            $scope.SELECT_CLASS = PLOT_CLASS + '-select';

            $scope.configure(BubbleChartDefaults);
            var config = $scope.config;

            $scope.bubbleSeries = 'count'; // Default to number of buildings in bubble
            $scope.selectOptions = { // CartoConfig labels require more config than they're worth
                count: 'Building Count',
                totalenergy: 'Total Energy (kBtu)',
                emissions: 'Total Emissions (MtCO2e)',
                energystar: 'Mean Energy Star',
            };

            element.addClass(PLOT_CLASS);
            chart = d3.select('#' + attrs.id + ' .chart')
                    .attr('width', config.plotWidth)
                    .attr('height', config.plotHeight);

            pack = d3.layout.pack()
                    .size([config.plotWidth, config.plotHeight])
                    .padding(config.bubblePadding);
            tip = d3.tip()
                .attr('class', 'd3-tip')
                .offset([-10, 0]);
            chart.call(tip);

            $scope.changeSeries = function (key) {
                $scope.bubbleSeries = key;
            };

            $scope.$watch('bubbleSeries', function () {
                $scope.plotComplete = false;
                $scope.redraw($scope.data);
            });
            // Overridden ChartingController method
            $scope.plot = function(data) {
                var node;
                var series = $scope.bubbleSeries;
                if (!series) {
                    return;
                }

                tip.html(function (d) {
                    return '
' + d.name + '
' +
                           '
' +
                           $scope.selectOptions[series] + ': ' +
                           Math.round(d[series]).toLocaleString() + '
';
                });
                pack.sort(null)
                    .value(function (d) { return d[series] || 0; });

                node = chart.selectAll('g')
                                 .data(pack.nodes({ children: data }));

                // Add
                node.enter().append('g')
                        .filter(function (d) { return d.depth === 1; })
                        .attr('transform', function(d) { return 'translate(' + d.x +
                                                                ',' + d.y + ')'; })
                        .append('circle')
                        // Radius of zero initially so it can be animated on load
                        .attr('r', 0)
                        .attr('class', 'bubble')
                        .style('fill', function (d) { return MOSColors[d.name] || MOSColors.Unknown; })
                        .on('mouseover', tip.show)
                        .on('mouseout', tip.hide);

                // Update
                node.transition().duration(config.transitionTime)
                    .attr('transform', function(d) { return 'translate(' + d.x +
                                                            ',' + d.y + ')'; })
                    .selectAll('circle')
                    .attr('r', function (d) { return d.r; });
            };
        };

        return module;
    }

    angular.module('mos.charting')
    .constant('BubbleChartDefaults', BubbleChartDefaults)
    .directive('mosBubblechart', bubbleChart);

})();
<commit_msg>Show sector labels on bubble chart if they fit the bubble.<commit_after>(function () {
    'use strict';

    // Define object config of properties for this chart directive
    var BubbleChartDefaults = {
        plotWidth: 500,
        plotHeight:500,
        bubblePadding: 25,
        lazyLoad: true,
        transitionTime: 500
    };

    /**
     * ngInject
     */
    function bubbleChart (BubbleChartDefaults, CartoConfig, MOSColors) {

        var PLOT_CLASS = 'mos-bubblechart';

        // Private vars
        var chart = null;
        var pack = null;
        var tip = null;

        // Begin directive module definition
        var module = {};

        module.restrict = 'EA';
        module.templateUrl = 'scripts/charting/bubblechart-partial.html';

        module.controller = 'ChartingController';

        module.scope = {
            data: '=',              // Required
            id: '@',                // Required
            plotWidth: '@',
            plotHeight: '@',
            bubblePadding: '@',
            lazyLoad: '@',
            transitionTime: '@'
        };

        module.link = function ($scope, element, attrs) {
            $scope.SELECT_CLASS = PLOT_CLASS + '-select';

            $scope.configure(BubbleChartDefaults);
            var config = $scope.config;

            $scope.bubbleSeries = 'count'; // Default to number of buildings in bubble
            $scope.selectOptions = { // CartoConfig labels require more config than they're worth
                count: 'Building Count',
                totalenergy: 'Total Energy (kBtu)',
                emissions: 'Total Emissions (MtCO2e)',
                energystar: 'Mean Energy Star',
            };

            element.addClass(PLOT_CLASS);
            chart = d3.select('#' + attrs.id + ' .chart')
                    .attr('width', config.plotWidth)
                    .attr('height', config.plotHeight);

            pack = d3.layout.pack()
                    .size([config.plotWidth, config.plotHeight])
                    .padding(config.bubblePadding);
            tip = d3.tip()
                .attr('class', 'd3-tip')
                .offset([-10, 0]);
            chart.call(tip);

            $scope.changeSeries = function (key) {
                $scope.bubbleSeries = key;
            };

            $scope.$watch('bubbleSeries', function () {
                $scope.plotComplete = false;
                $scope.redraw($scope.data);
            });
            // Overridden ChartingController method
            $scope.plot = function(data) {
                var node;
                var series = $scope.bubbleSeries;
                if (!series) {
                    return;
                }

                tip.html(function (d) {
                    return '
' + d.name + '
' +
                           '
' +
                           $scope.selectOptions[series] + ': ' +
                           Math.round(d[series]).toLocaleString() + '
';
                });
                pack.sort(null)
                    .value(function (d) { return d[series] || 0; });

                node = chart.selectAll('g')
                                 .data(pack.nodes({ children: data }));

                // Add
                var nodeEnter = node.enter().append('g')
                    .filter(function (d) { return d.depth === 1; })
                        .attr('transform', function(d) {
                            return 'translate(' + d.x + ',' + d.y + ')';
                        })
                    .on('mouseover', tip.show)
                    .on('mouseout', tip.hide);

                nodeEnter.append('circle')
                    // Radius of zero initially so it can be animated on load
                    .attr('r', 0)
                    .attr('class', 'bubble')
                    .style('fill', function (d) { return MOSColors[d.name] || MOSColors.Unknown; });

                nodeEnter.append('text')
                    .attr('dy', '.35em')
                    .attr('text-anchor', 'middle')
                    .text(function (d) { return d.name; })
                    .style('opacity', 0);

                // Update
                node.transition().duration(config.transitionTime)
                    .attr('transform', function(d) { return 'translate(' + d.x + ',' + d.y + ')'; })
                    .selectAll('circle')
                    .attr('r', function (d) { return d.r; });

                node.select('text').transition().duration(config.transitionTime).style('opacity', function (d) {
                        // only show sector labels on bubble if bubble is bigger than text box
                        var bbox = this.getBBox();
                        return bbox.width < ((d.r * 2) - 5) ? 1 : 0;
                    });
            };
        };

        return module;
    }

    angular.module('mos.charting')
    .constant('BubbleChartDefaults', BubbleChartDefaults)
    .directive('mosBubblechart', bubbleChart);

})();
<|endoftext|>


<commit_before>'use strict';

angular.module('openhimWebui2App')
  .controller('TransactionDetailsCtrl', function ($scope, $modal, $location, $routeParams, Api, Alerting) {

    /***************************************************/
    /**         Initial page load functions           **/
    /***************************************************/

    var querySuccess = function(transactionDetails){
      $scope.transactionDetails = transactionDetails;

      // get the channel object for the transactions details page
      $scope.channel = Api.Channels.get({ channelId: transactionDetails.channelID });

      // get the client object for the transactions details page
      $scope.client = Api.Clients.get({ clientId: transactionDetails.clientID });

    };

    var queryError = function(err){
      // on error - add server error alert
      Alerting.AlertAddServerMsg(err.status);
    };

    //get the Data for the supplied ID and store in 'transactionsDetails' object
    Api.Transactions.get({ transactionId: $routeParams.transactionId }, querySuccess, queryError);

    /***************************************************/
    /**         Initial page load functions           **/
    /***************************************************/

    /*******************************************************************/
    /**         Transactions List and Detail view functions           **/
    /*******************************************************************/

    //setup filter options
    $scope.returnFilterObject = function(){
      var filtersObject = {};

      filtersObject.filterPage = 0;
      filtersObject.filterLimit = 0;
      filtersObject.parentID = $routeParams.transactionId;
      return filtersObject;
    };

    //Refresh transactions list
    $scope.fetchChildTransactions = function () {

      Api.Transactions.query( $scope.returnFilterObject(), function (values) {
        // on success
        $scope.childTransactions = values;
      },
      function (err) {
        $scope.returnError(err.status);
      });

    };
    //run the transaction list view for the first time
    $scope.fetchChildTransactions();

    //location provider - load transaction details
    $scope.viewTransactionDetails = function (path) {
      //do transactions details redirection when clicked on TD
      $location.path(path);
    };

    /*******************************************************************/
    /**         Transactions List and Detail view functions           **/
    /*******************************************************************/

    /****************************************************************/
    /**               Transactions ReRun Functions                 **/
    /****************************************************************/

    $scope.confirmRerunTransactions = function(){
      var transactionsSelected = [$scope.transactionDetails._id];
      $modal.open({
        templateUrl: 'views/transactionsRerunModal.html',
        controller: 'TransactionsRerunModalCtrl',
        resolve: {
          transactionsSelected: function () {
            return transactionsSelected;
          }
        }
      });
    };

    /****************************************************************/
    /**               Transactions ReRun Functions                 **/
    /****************************************************************/

    /*********************************************************************/
    /**               Transactions View Route Functions                 **/
    /*********************************************************************/

    $scope.viewRouteDetails = function(route){
      $modal.open({
        templateUrl: 'views/transactionsRouteModal.html',
        controller: 'TransactionsRouteModalCtrl',
        resolve: {
          route: function () {
            return route;
          }
        }
      });
    };

    /*********************************************************************/
    /**               Transactions View Route Functions                 **/
    /*********************************************************************/

  });
<commit_msg>Fixed bug in transactionDetails controller<commit_after>'use strict';

angular.module('openhimWebui2App')
  .controller('TransactionDetailsCtrl', function ($scope, $modal, $location, $routeParams, Api, Alerting) {

    /***************************************************/
    /**         Initial page load functions           **/
    /***************************************************/

    var querySuccess = function(transactionDetails){
      $scope.transactionDetails = transactionDetails;

      // get the channel object for the transactions details page
      $scope.channel = Api.Channels.get({ channelId: transactionDetails.channelID });

      // get the client object for the transactions details page
      $scope.client = Api.Clients.get({ clientId: transactionDetails.clientID });

    };

    var queryError = function(err){
      // on error - add server error alert
      Alerting.AlertAddServerMsg(err.status);
    };

    //get the Data for the supplied ID and store in 'transactionsDetails' object
    Api.Transactions.get({ transactionId: $routeParams.transactionId }, querySuccess, queryError);

    /***************************************************/
    /**         Initial page load functions           **/
    /***************************************************/

    /*******************************************************************/
    /**         Transactions List and Detail view functions           **/
    /*******************************************************************/

    //setup filter options
    $scope.returnFilterObject = function(){
      var filtersObject = {};

      filtersObject.filterPage = 0;
      filtersObject.filterLimit = 0;
      filtersObject.parentID = $routeParams.transactionId;
      return filtersObject;
    };

    //Refresh transactions list
    $scope.fetchChildTransactions = function () {

      Api.Transactions.query( $scope.returnFilterObject(), function (values) {
        // on success
        $scope.childTransactions = values;
      },
      function (err) {
        $scope.returnError(err.status);
      });

    };
    //run the transaction list view for the first time
    $scope.fetchChildTransactions();

    //location provider - load transaction details
    $scope.viewTransactionDetails = function (path) {
      //do transactions details redirection when clicked on TD
      $location.path(path);
    };

    /*******************************************************************/
    /**         Transactions List and Detail view functions           **/
    /*******************************************************************/

    /****************************************************************/
    /**               Transactions ReRun Functions                 **/
    /****************************************************************/

    $scope.confirmRerunTransactions = function(){
      var transactionsSelected = [$scope.transactionDetails._id];
      var rerunTransactionsSelected = 0;

      if ($scope.transactionDetails.parentID){
        rerunTransactionsSelected = 1;
      }

      $modal.open({
        templateUrl: 'views/transactionsRerunModal.html',
        controller: 'TransactionsRerunModalCtrl',
        resolve: {
          transactionsSelected: function () {
            return transactionsSelected;
          },
          rerunTransactionsSelected: function () {
            return rerunTransactionsSelected;
          }
        }
      });
    };

    /****************************************************************/
    /**               Transactions ReRun Functions                 **/
    /****************************************************************/

    /*********************************************************************/
    /**               Transactions View Route Functions                 **/
    /*********************************************************************/

    $scope.viewRouteDetails = function(route){
      $modal.open({
        templateUrl: 'views/transactionsRouteModal.html',
        controller: 'TransactionsRouteModalCtrl',
        resolve: {
          route: function () {
            return route;
          }
        }
      });
    };

    /*********************************************************************/
    /**               Transactions View Route Functions                 **/
    /*********************************************************************/

  });
<|endoftext|>


<commit_before>define([
	"dcl/dcl",
	"dojo/has"
], function (dcl, has) {
	'use strict';

	var doc = document;

	// Does platform have native support for document.register() or a polyfill to simulate it?
	has.add('document-register', document.register);

	// Can we use __proto__ to reset the prototype of DOMNodes?
	// It's not available on IE<11, and even on IE11 it makes the node's attributes (ex: node.attributes, node.textContent)
	// disappear, so disabling it on IE11 for now.
	has.add('dom-proto-set', function(){
		var node = document.createElement("div");
		if(!node.__proto__){ return false; }
		node.__proto__ = {};
		return !!node.attributes;
	});

	/**
	 * List of selectors that the parser needs to search for as possible upgrade targets.  Mainly contains
	 * the widget custom tags like d-accordion, but also selectors like button[is='d-button'] to find <button is="...">
	 * @type {String[]}
	 */
	var selectors = [];

	/**
	 * Internal registry of widget class metadata.
	 * Key is custom widget tag name, used as Element tag name like <d-accordion> or "is" attribute like
	 * <button is="d-accordion">).
	 * Value is metadata about the widget, including its prototype, ex: {prototype: object, extends: "button", ... }
	 * @type {Object}
	 */
	var registry = {};

	/**
	 * Create an Element.  Equivalent to document.createElement(), but if tag is the name of a widget defined by
	 * register(), then it upgrades the Element to be a widget.
	 * @param {String} tag
	 * @returns {Element} The DOMNode
	 */
	function createElement(tag){
		var base = registry[tag] ? registry[tag].extends : null,
			element = doc.createElement(base || tag);
		if (base) {
			element.setAttribute('is', tag);
		}

		upgrade(element);

		return element;
	}

	function getPropDescriptors(proto) {
		// summary:
		//		Generate metadata about all the properties in proto, both direct and inherited.
		//		On IE<=10, these properties will be applied to a DOMNode via Object.defineProperties().
		//		Skips properties in the base element (HTMLElement, HTMLButtonElement, etc.)

		var props = {};

		do {
			var keys = Object.getOwnPropertyNames(proto);	// better than Object.keys() because finds hidden props too
			for (var i=0, k; k=keys[i]; i++) {
				if (!props[k]) {
					props[k] = Object.getOwnPropertyDescriptor(proto, k);
				}
			}
			proto = Object.getPrototypeOf(proto);
		} while (!/HTML[a-zA-Z]*Element/.test(proto.toString()));

		return props;
	}

	/**
	 * Converts plain DOMNode of custom type into widget, by adding the widget's custom methods, etc.
	 * Does nothing if the DOMNode has already been converted or if it doesn't correspond to a custom widget.
	 * Roughly equivalent to dojo/parser::instantiate(), but for a single node, not an array
	 * @param {Element} inElement The DOMNode
	 */
	function upgrade(element){
		if (!element.__upgraded__) {
			var widget = registry[element.getAttribute('is') || element.nodeName.toLowerCase()];
			if (widget) {
				if (has("dom-proto-set")) {
					// Redefine Element's prototype to point to widget's methods etc.
					element.__proto__ = widget.prototype;
				}
				else {
					// Mixin all the widget's methods etc. into Element
					Object.defineProperties(element, widget.props);
				}
				element.__upgraded__ = true;
				element._constructor = widget.constructor;	// _constructor b/c constructor is read-only on iOS
				if (element.createdCallback) {
					element.createdCallback.call(element, widget.prototype);
				}
				if (element.enteredViewCallback && doc.documentElement.contains(element)) {
					// Note: if app inserts an element manually it needs to call enteredViewCallback() manually
					element.enteredViewCallback.call(element, widget.prototype);
				}
			}
		}
	}

	/**
	 * Hash mapping of HTMLElement interfaces to tag names
	 * @type {Object}
	 */
	var tags = {
		HTMLAnchorElement: 'a',
		HTMLAppletElement: 'applet',
		HTMLAreaElement: 'area',
		HTMLAudioElement: 'audio',
		HTMLBaseElement: 'base',
		HTMLBRElement: 'br',
		HTMLButtonElement: 'button',
		HTMLCanvasElement: 'canvas',
		HTMLDataElement: 'data',
		HTMLDataListElement: 'datalist',
		HTMLDivElement: 'div',
		HTMLDListElement: 'dl',
		HTMLDirectoryElement: 'directory',
		HTMLEmbedElement: 'embed',
		HTMLFieldSetElement: 'fieldset',
		HTMLFontElement: 'font',
		HTMLFormElement: 'form',
		HTMLHeadElement: 'head',
		HTMLHeadingElement: 'h1',
		HTMLHtmlElement: 'html',
		HTMLHRElement: 'hr',
		HTMLIFrameElement: 'iframe',
		HTMLImageElement: 'img',
		HTMLInputElement: 'input',
		HTMLKeygenElement: 'keygen',
		HTMLLabelElement: 'label',
		HTMLLegendElement: 'legend',
		HTMLLIElement: 'li',
		HTMLLinkElement: 'link',
		HTMLMapElement: 'map',
		HTMLMediaElement: 'media',
		HTMLMenuElement: 'menu',
		HTMLMetaElement: 'meta',
		HTMLMeterElement: 'meter',
		HTMLModElement: 'ins',
		HTMLObjectElement: 'object',
		HTMLOListElement: 'ol',
		HTMLOptGroupElement: 'optgroup',
		HTMLOptionElement: 'option',
		HTMLOutputElement: 'output',
		HTMLParagraphElement: 'p',
		HTMLParamElement: 'param',
		HTMLPreElement: 'pre',
		HTMLProgressElement: 'progress',
		HTMLQuoteElement: 'quote',
		HTMLScriptElement: 'script',
		HTMLSelectElement: 'select',
		HTMLSourceElement: 'source',
		HTMLSpanElement: 'span',
		HTMLStyleElement: 'style',
		HTMLTableElement: 'table',
		HTMLTableCaptionElement: 'caption',
		HTMLTableDataCellElement: 'td',
		HTMLTableHeaderCellElement: 'th',
		HTMLTableColElement: 'col',
		HTMLTableRowElement: 'tr',
		HTMLTableSectionElement: 'tbody',
		HTMLTextAreaElement: 'textarea',
		HTMLTimeElement: 'time',
		HTMLTitleElement: 'title',
		HTMLTrackElement: 'track',
		HTMLUListElement: 'ul',
		HTMLUnknownElement: 'blink',
		HTMLVideoElement: 'video'
	};

	/**
	 * For a constructor function, attempt to determine name of the "class"
	 * @param  {Function} base The constructor function to identify
	 * @return {String}	       The string name of the class
	 */
	function getBaseName(base) {
		// Try to use Function.name if available
		if (base && base.name) {
			return base.name;
		}
		var matches;
		// Attempt to determine the name of the "class" by either getting it from the "function Name()" or the
		// .toString() of the constructor function.  This is required on IE due to the fact that function.name is
		// not a standard property and is not implemented on IE
		if ((matches = base.toString().match(/^(?:function\s(\S+)\(\)\s|\[\S+\s(\S+)\])/))) {
			return matches[1] || matches[2];
		}
	}

	/**
	 * Registers the tag with the current document, and save tag information in registry.
	 * Handles situations where the base constructor inherits from
	 * HTMLElement but is not HTMLElement.
	 * @param  {String}   tag      The custom tag name for the element, or the "is" attribute value.
	 * @param  {String}   baseName The base "class" name that this custom element is being built on
	 * @param  {Function} baseCtor The constructor function
	 * @return {Function}          The "new" constructor function that can create instances of the custom element
	 */
	function getTagConstructor(tag, baseName, baseCtor) {
		var proto = baseCtor.prototype,
			config = registry[tag] = {
				constructor: baseCtor,
				prototype: proto
			};
		if (baseName !== 'HTMLElement') {
			config.extends = tags[baseName];
		}

		// If platform natively support document.register, we can call it here.
		var tagConstructor;

		if (has("document-register")) {
			tagConstructor = doc.register(tag, config);
		} else {
			if(!has("dom-proto-set")) {
				// Get descriptors for all the properties in the prototype.  This is needed on IE<=10 in upgrade().
				config.props = getPropDescriptors(proto);
			}

			// Register the selector to find this custom element
			selectors.push( config.extends ? config.extends + '[is="' + tag + '"]' : tag);

			// Note: if we wanted to support registering new types after the parser was called, then here we should
			// scan the document for the new type (selectors[length-1]) and upgrade any nodes found.

			// Create a constructor method to return a DOMNode representing this widget.
			tagConstructor = function(params, srcNodeRef){
				// Create new widget node or upgrade existing node to widget
				var node;
				if(srcNodeRef){
					node = typeof srcNodeRef == "string" ? document.getElementById(srcNodeRef) : srcNodeRef;
					upgrade(node);
				}else{
					node = createElement(tag);
				}

				// Set parameters on node
				for(var name in params || {}){
					if(!(name in node) && /^on[A-Z]/.test(name) && node.on){
						// convert parameters like onMouseMove to on() calls
						node.on(name.substring(2).toLowerCase(), params[name]);
					}else{
						node[name] = params[name];
					}
				}

				return node;
			};
		}

		// Add some flags for debugging and return the new constructor
		tagConstructor.tag = tag;
		tagConstructor._ctor = baseCtor;
		return tagConstructor;
	}

	/**
	 * Restore the "true" constructor when trying to recombine custom elements
	 * @param  {Function} extension A constructor function that might have a shadow property that contains the
	 *                              original constructor
	 * @return {Function}           The original construction function or the existing function/object
	 */
	function restore(extension) {
		return (extension && extension._ctor) || extension;
	}

	/**
	 * Declare a widget and register as a custom element.
	 *
	 * props{} can provide custom setters/getters for widget properties, which are called automatically when
	 * the widget properties are set.
	 * For a property XXX, define methods _setXXXAttr() and/or _getXXXAttr().
	 *
	 * @param  {String}               tag             The custom element's tag name
	 * @param  {Objects}              [extensions...] Any number of extensions to be built into the custom element
	 *                                                constructor.   But first one must be [descendant] of HTMLElement.
	 * @param  {Object}               props           Properties of this widget class
	 * @return {Function}                             A constructor function that will create an instance of the custom
	 *                                                element
	 */
	function register (tag, superclasses, props) {
		// Create the widget class by extending specified superclasses and adding specified properties.

		// Make sure all the bases have their proper constructors for being composited.
		// I.E. remove the wrapper added by getTagConstructor().
		var bases = (superclasses instanceof Array ? superclasses : superclasses ? [superclasses] : []).map(restore);

		var baseName, baseElement = bases[0];

		// Check to see if the custom tag is already registered
		if (tag in registry) {
			throw new TypeError('A widget is already registered with tag "' + tag + '".');
		}
		// Get name of root class: "HTMLElement", "HTMLInputElement", etc.
		if (!(baseName = (baseElement.prototype && baseElement.prototype._baseName) || getBaseName(baseElement))) {
			throw new TypeError(tag + ': Cannot determine class of baseElement');
		}
		baseName = baseName.replace(/Constructor$/, "");	// normalize HTMLElementConstructor --> HTMLElement on iOS

		// Check to see if baseElement is appropriate
		if (!/^HTML.*Element$/.test(baseName)) {
			throw new TypeError(tag + ': baseElement must have HTMLElement in its prototype chain');
		}

		props = props || {};
		props.tag = props.declaredClass = tag;	// for debugging

		// Get a composited constructor
		var ctor = dcl(bases, props),
			proto = ctor.prototype;
		proto._ctor = ctor;
		proto._baseName = baseName;

		// Run introspection to add ES5 getters/setters.
		// Doesn't happen automatically because Stateful's constructor isn't called.
		// Also, on IE this needs to happen before the getTagConstructor() call,
		// since getTagConstructor() scans all the properties on the widget prototype.
		proto._introspect(ctor);
		ctor._introspected = true;

		// Save widget metadata to the registry and return constructor that creates an upgraded DOMNode for the widget
		/* jshint boss:true */
		return getTagConstructor(tag, baseName, ctor);
	}

	/**
	 * Parse the given DOM tree for any DOMNodes that need to be upgraded to widgets.
	 * @param {Element?} Root DOMNode to parse from
	 */
	function parse(root){
		if(has("document-register")){
			// If there's native support for custom elements then they are parsed automatically
			return;
		}

		// Otherwise, parse manually
		var node, idx = 0, nodes = (root || doc).querySelectorAll(selectors);
		while(node = nodes[idx++]){
			upgrade(node);
		}

		// Call startup() on top level nodes.  Since I don't know which nodes are top level,
		// just call startup on all widget nodes.  Most of the calls will be ignored since the nodes
		// have already been started.
		idx = 0;
		while(node = nodes[idx++]){
			if(node.startup){
				node.startup();
			}
		}

	}

	// Setup return value as register() method, with other methods hung off it.
	register.upgrade = upgrade;
	register.createElement = createElement;

	// Add helpers from dcl for declaring classes.
	register.after = dcl.after;
	register.before = dcl.before;
	register.around = dcl.around;
	register.parse = parse;

	return register;
});
<commit_msg>getPropDescriptors() should check name of constructor, not prototype<commit_after>define([
	"dcl/dcl",
	"dojo/has"
], function (dcl, has) {
	'use strict';

	var doc = document;

	// Does platform have native support for document.register() or a polyfill to simulate it?
	has.add('document-register', document.register);

	// Can we use __proto__ to reset the prototype of DOMNodes?
	// It's not available on IE<11, and even on IE11 it makes the node's attributes (ex: node.attributes, node.textContent)
	// disappear, so disabling it on IE11 for now.
	has.add('dom-proto-set', function(){
		var node = document.createElement("div");
		if(!node.__proto__){ return false; }
		node.__proto__ = {};
		return !!node.attributes;
	});

	/**
	 * List of selectors that the parser needs to search for as possible upgrade targets.  Mainly contains
	 * the widget custom tags like d-accordion, but also selectors like button[is='d-button'] to find <button is="...">
	 * @type {String[]}
	 */
	var selectors = [];

	/**
	 * Internal registry of widget class metadata.
	 * Key is custom widget tag name, used as Element tag name like <d-accordion> or "is" attribute like
	 * <button is="d-accordion">).
	 * Value is metadata about the widget, including its prototype, ex: {prototype: object, extends: "button", ... }
	 * @type {Object}
	 */
	var registry = {};

	/**
	 * Create an Element.  Equivalent to document.createElement(), but if tag is the name of a widget defined by
	 * register(), then it upgrades the Element to be a widget.
	 * @param {String} tag
	 * @returns {Element} The DOMNode
	 */
	function createElement(tag){
		var base = registry[tag] ? registry[tag].extends : null,
			element = doc.createElement(base || tag);
		if (base) {
			element.setAttribute('is', tag);
		}

		upgrade(element);

		return element;
	}

	function getPropDescriptors(proto) {
		// summary:
		//		Generate metadata about all the properties in proto, both direct and inherited.
		//		On IE<=10, these properties will be applied to a DOMNode via Object.defineProperties().
		//		Skips properties in the base element (HTMLElement, HTMLButtonElement, etc.)

		var props = {};

		do {
			var keys = Object.getOwnPropertyNames(proto);	// better than Object.keys() because finds hidden props too
			for (var i=0, k; k=keys[i]; i++) {
				if (!props[k]) {
					props[k] = Object.getOwnPropertyDescriptor(proto, k);
				}
			}
			proto = Object.getPrototypeOf(proto);
		} while (!/HTML[a-zA-Z]*Element/.test(proto.constructor.toString()));

		return props;
	}

	/**
	 * Converts plain DOMNode of custom type into widget, by adding the widget's custom methods, etc.
	 * Does nothing if the DOMNode has already been converted or if it doesn't correspond to a custom widget.
	 * Roughly equivalent to dojo/parser::instantiate(), but for a single node, not an array
	 * @param {Element} inElement The DOMNode
	 */
	function upgrade(element){
		if (!element.__upgraded__) {
			var widget = registry[element.getAttribute('is') || element.nodeName.toLowerCase()];
			if (widget) {
				if (has("dom-proto-set")) {
					// Redefine Element's prototype to point to widget's methods etc.
					element.__proto__ = widget.prototype;
				}
				else {
					// Mixin all the widget's methods etc. into Element
					Object.defineProperties(element, widget.props);
				}
				element.__upgraded__ = true;
				element._constructor = widget.constructor;	// _constructor b/c constructor is read-only on iOS
				if (element.createdCallback) {
					element.createdCallback.call(element, widget.prototype);
				}
				if (element.enteredViewCallback && doc.documentElement.contains(element)) {
					// Note: if app inserts an element manually it needs to call enteredViewCallback() manually
					element.enteredViewCallback.call(element, widget.prototype);
				}
			}
		}
	}

	/**
	 * Hash mapping of HTMLElement interfaces to tag names
	 * @type {Object}
	 */
	var tags = {
		HTMLAnchorElement: 'a',
		HTMLAppletElement: 'applet',
		HTMLAreaElement: 'area',
		HTMLAudioElement: 'audio',
		HTMLBaseElement: 'base',
		HTMLBRElement: 'br',
		HTMLButtonElement: 'button',
		HTMLCanvasElement: 'canvas',
		HTMLDataElement: 'data',
		HTMLDataListElement: 'datalist',
		HTMLDivElement: 'div',
		HTMLDListElement: 'dl',
		HTMLDirectoryElement: 'directory',
		HTMLEmbedElement: 'embed',
		HTMLFieldSetElement: 'fieldset',
		HTMLFontElement: 'font',
		HTMLFormElement: 'form',
		HTMLHeadElement: 'head',
		HTMLHeadingElement: 'h1',
		HTMLHtmlElement: 'html',
		HTMLHRElement: 'hr',
		HTMLIFrameElement: 'iframe',
		HTMLImageElement: 'img',
		HTMLInputElement: 'input',
		HTMLKeygenElement: 'keygen',
		HTMLLabelElement: 'label',
		HTMLLegendElement: 'legend',
		HTMLLIElement: 'li',
		HTMLLinkElement: 'link',
		HTMLMapElement: 'map',
		HTMLMediaElement: 'media',
		HTMLMenuElement: 'menu',
		HTMLMetaElement: 'meta',
		HTMLMeterElement: 'meter',
		HTMLModElement: 'ins',
		HTMLObjectElement: 'object',
		HTMLOListElement: 'ol',
		HTMLOptGroupElement: 'optgroup',
		HTMLOptionElement: 'option',
		HTMLOutputElement: 'output',
		HTMLParagraphElement: 'p',
		HTMLParamElement: 'param',
		HTMLPreElement: 'pre',
		HTMLProgressElement: 'progress',
		HTMLQuoteElement: 'quote',
		HTMLScriptElement: 'script',
		HTMLSelectElement: 'select',
		HTMLSourceElement: 'source',
		HTMLSpanElement: 'span',
		HTMLStyleElement: 'style',
		HTMLTableElement: 'table',
		HTMLTableCaptionElement: 'caption',
		HTMLTableDataCellElement: 'td',
		HTMLTableHeaderCellElement: 'th',
		HTMLTableColElement: 'col',
		HTMLTableRowElement: 'tr',
		HTMLTableSectionElement: 'tbody',
		HTMLTextAreaElement: 'textarea',
		HTMLTimeElement: 'time',
		HTMLTitleElement: 'title',
		HTMLTrackElement: 'track',
		HTMLUListElement: 'ul',
		HTMLUnknownElement: 'blink',
		HTMLVideoElement: 'video'
	};

	/**
	 * For a constructor function, attempt to determine name of the "class"
	 * @param  {Function} base The constructor function to identify
	 * @return {String}	       The string name of the class
	 */
	function getBaseName(base) {
		// Try to use Function.name if available
		if (base && base.name) {
			return base.name;
		}
		var matches;
		// Attempt to determine the name of the "class" by either getting it from the "function Name()" or the
		// .toString() of the constructor function.  This is required on IE due to the fact that function.name is
		// not a standard property and is not implemented on IE
		if ((matches = base.toString().match(/^(?:function\s(\S+)\(\)\s|\[\S+\s(\S+)\])/))) {
			return matches[1] || matches[2];
		}
	}

	/**
	 * Registers the tag with the current document, and save tag information in registry.
	 * Handles situations where the base constructor inherits from
	 * HTMLElement but is not HTMLElement.
	 * @param  {String}   tag      The custom tag name for the element, or the "is" attribute value.
	 * @param  {String}   baseName The base "class" name that this custom element is being built on
	 * @param  {Function} baseCtor The constructor function
	 * @return {Function}          The "new" constructor function that can create instances of the custom element
	 */
	function getTagConstructor(tag, baseName, baseCtor) {
		var proto = baseCtor.prototype,
			config = registry[tag] = {
				constructor: baseCtor,
				prototype: proto
			};
		if (baseName !== 'HTMLElement') {
			config.extends = tags[baseName];
		}

		// If platform natively support document.register, we can call it here.
		var tagConstructor;

		if (has("document-register")) {
			tagConstructor = doc.register(tag, config);
		} else {
			if(!has("dom-proto-set")) {
				// Get descriptors for all the properties in the prototype.  This is needed on IE<=10 in upgrade().
				config.props = getPropDescriptors(proto);
			}

			// Register the selector to find this custom element
			selectors.push( config.extends ? config.extends + '[is="' + tag + '"]' : tag);

			// Note: if we wanted to support registering new types after the parser was called, then here we should
			// scan the document for the new type (selectors[length-1]) and upgrade any nodes found.

			// Create a constructor method to return a DOMNode representing this widget.
			tagConstructor = function(params, srcNodeRef){
				// Create new widget node or upgrade existing node to widget
				var node;
				if(srcNodeRef){
					node = typeof srcNodeRef == "string" ? document.getElementById(srcNodeRef) : srcNodeRef;
					upgrade(node);
				}else{
					node = createElement(tag);
				}

				// Set parameters on node
				for(var name in params || {}){
					if(!(name in node) && /^on[A-Z]/.test(name) && node.on){
						// convert parameters like onMouseMove to on() calls
						node.on(name.substring(2).toLowerCase(), params[name]);
					}else{
						node[name] = params[name];
					}
				}

				return node;
			};
		}

		// Add some flags for debugging and return the new constructor
		tagConstructor.tag = tag;
		tagConstructor._ctor = baseCtor;
		return tagConstructor;
	}

	/**
	 * Restore the "true" constructor when trying to recombine custom elements
	 * @param  {Function} extension A constructor function that might have a shadow property that contains the
	 *                              original constructor
	 * @return {Function}           The original construction function or the existing function/object
	 */
	function restore(extension) {
		return (extension && extension._ctor) || extension;
	}

	/**
	 * Declare a widget and register as a custom element.
	 *
	 * props{} can provide custom setters/getters for widget properties, which are called automatically when
	 * the widget properties are set.
	 * For a property XXX, define methods _setXXXAttr() and/or _getXXXAttr().
	 *
	 * @param  {String}               tag             The custom element's tag name
	 * @param  {Objects}              [extensions...] Any number of extensions to be built into the custom element
	 *                                                constructor.   But first one must be [descendant] of HTMLElement.
	 * @param  {Object}               props           Properties of this widget class
	 * @return {Function}                             A constructor function that will create an instance of the custom
	 *                                                element
	 */
	function register (tag, superclasses, props) {
		// Create the widget class by extending specified superclasses and adding specified properties.

		// Make sure all the bases have their proper constructors for being composited.
		// I.E. remove the wrapper added by getTagConstructor().
		var bases = (superclasses instanceof Array ? superclasses : superclasses ? [superclasses] : []).map(restore);

		var baseName, baseElement = bases[0];

		// Check to see if the custom tag is already registered
		if (tag in registry) {
			throw new TypeError('A widget is already registered with tag "' + tag + '".');
		}
		// Get name of root class: "HTMLElement", "HTMLInputElement", etc.
		if (!(baseName = (baseElement.prototype && baseElement.prototype._baseName) || getBaseName(baseElement))) {
			throw new TypeError(tag + ': Cannot determine class of baseElement');
		}
		baseName = baseName.replace(/Constructor$/, "");	// normalize HTMLElementConstructor --> HTMLElement on iOS

		// Check to see if baseElement is appropriate
		if (!/^HTML.*Element$/.test(baseName)) {
			throw new TypeError(tag + ': baseElement must have HTMLElement in its prototype chain');
		}

		props = props || {};
		props.tag = props.declaredClass = tag;	// for debugging

		// Get a composited constructor
		var ctor = dcl(bases, props),
			proto = ctor.prototype;
		proto._ctor = ctor;
		proto._baseName = baseName;

		// Run introspection to add ES5 getters/setters.
		// Doesn't happen automatically because Stateful's constructor isn't called.
		// Also, on IE this needs to happen before the getTagConstructor() call,
		// since getTagConstructor() scans all the properties on the widget prototype.
		proto._introspect(ctor);
		ctor._introspected = true;

		// Save widget metadata to the registry and return constructor that creates an upgraded DOMNode for the widget
		/* jshint boss:true */
		return getTagConstructor(tag, baseName, ctor);
	}

	/**
	 * Parse the given DOM tree for any DOMNodes that need to be upgraded to widgets.
	 * @param {Element?} Root DOMNode to parse from
	 */
	function parse(root){
		if(has("document-register")){
			// If there's native support for custom elements then they are parsed automatically
			return;
		}

		// Otherwise, parse manually
		var node, idx = 0, nodes = (root || doc).querySelectorAll(selectors);
		while(node = nodes[idx++]){
			upgrade(node);
		}

		// Call startup() on top level nodes.  Since I don't know which nodes are top level,
		// just call startup on all widget nodes.  Most of the calls will be ignored since the nodes
		// have already been started.
		idx = 0;
		while(node = nodes[idx++]){
			if(node.startup){
				node.startup();
			}
		}

	}

	// Setup return value as register() method, with other methods hung off it.
	register.upgrade = upgrade;
	register.createElement = createElement;

	// Add helpers from dcl for declaring classes.
	register.after = dcl.after;
	register.before = dcl.before;
	register.around = dcl.around;
	register.parse = parse;

	return register;
});
<|endoftext|>


<commit_before>define('bforms-form', [
    'jquery',
    'bforms-extensions',
    'jquery-ui-core',
    'bforms-validate-unobtrusive',
    'bforms-initUI',
    'bforms-ajax',
    'amplify'
], function () {

    var Form = function (opt) {
        this.options = opt;
        this._create();
    };

    Form.prototype.options = {
        uniqueName: null,
        hasGroupToggle: true,
        style: {},
        focusFirst: true,
        // save opened group containers in localstorage and retreive it later
        saveGroupContainerState: true,
        appendUrlToUniqueName :true,
        groupToggleSelector: '.bs-group_toggle',
        groupToggleContainerSelector: '.bs-group_toggle_container',
        groupToggleUp: 'glyphicon-chevron-up',
        groupToggleDown: 'glyphicon-chevron-down',
        glyphClass: '.glyphicon',
        actions: [],
        refreshUrl: null
    };

    //#region init
    Form.prototype._init = function () {

        if (!this.options.uniqueName){
            this.options.uniqueName = this.element.attr('id');
        }

        if (!this.options.uniqueName) {
            throw 'form needs a unique name or the element on which it is aplied has to have an id attr';
        }

        this._buttons = new Array();

        this._initSelectors();

        this._addDelegates();

        this._initAmplifyStore();

        this._addActions(this.options.actions);

        var initUIPromise = this.$form.bsInitUI(this.options.style);
        initUIPromise.done($.proxy(function() {
            this._trigger('afterInitUI', 0, {
                name: this.options.uniqueName,
                form: this.$form
            });
        }, this));

    };

    Form.prototype._initSelectors = function () {

        this.$form = this.element.is('form') ? this.element : this.element.find('form');

    };

    Form.prototype._addDelegates = function () {

        if (this.options.hasGroupToggle) {
            this.element.on('click', this.options.groupToggleSelector, $.proxy(function (e) {
                var $elem = $(e.currentTarget);
                this.toggleGroup($elem);
            }, this));
        }
    };

    Form.prototype._initAmplifyStore = function () {

        if (this.options.saveGroupContainerState) {
            var amplifyKey = this._getKeyForGroupContainer();

            if (amplify.store(amplifyKey)) {
                try {
                    var savedGroupContainerValues = amplify.store(amplifyKey);
                    var context = this;
                    this.$form.find(this.options.groupToggleSelector).each(function (index) {
                        if (savedGroupContainerValues[index]) {
                            context.showGroup($(this));
                        } else {
                            context.hideGroup($(this));
                        }
                    });
                }
                catch (err) {
                    console.warn('Error on saving on local storage:'+err);
                }
            }
        }
    };

    Form.prototype._addActions = function (actions) {

        if (actions) {
            for (var i = 0; i < actions.length; i++) {
                this._addAction(actions[i]);
            }
        }

    };

    Form.prototype._addAction = function (buttonOpt) {

        var $elem = this.element.find(buttonOpt.selector);

        if ($elem.length == 0) {
            throw 'element with selector ' + buttonOpt.selector + ' is not found in form container ' + this.options.uniqueName;
        }

        $elem.on('click', {
            buttonOpt: buttonOpt,
            handlerContext: this.options.handlerContext
        }, $.proxy(this._evBtnClick, this));

        this._buttons.push({
            name: buttonOpt.name,
            elem: $elem
        });

    };
    //#endregion

    //#region events
    Form.prototype._evBtnClick = function (e) {

        e.preventDefault();

        var $me = $(e.currentTarget);
        var buttonOpt = e.data.buttonOpt;
        var handlerContext = e.data.handlerContext;

        if (buttonOpt.validate && !this._validate()) {
            return;
        }

        var validatedForm = this.$form.validate();

        var data;
        if (buttonOpt.parse) {
            data = this._parse();
            if (typeof buttonOpt.getExtraData === 'function') {
                buttonOpt.getExtraData.call(this, data);
            }

            this._trigger('beforeFormSubmit', 0, {
                $button: $me,
                buttonOpt: buttonOpt,
                data: data
            });
        }

        var action = $me.data('action') || buttonOpt.actionUrl;
        if (action) {
            $.bforms.ajax({
                name: this.options.uniqueName,
                url: action,
                data: data,
                callbackData: {
                    handler: buttonOpt.handler,
                    handlerContext: handlerContext,
                    sent: data
                },
                context: this,
                success: $.proxy(this._btnClickAjaxSuccess, this),
                error: $.proxy(this._btnClickAjaxError, this),
                loadingElement: this.element,
                loadingClass: 'loading',
                validationError: function (response) {

                    if (response != null && response.Errors != null) {

                        if (typeof validatedForm === "undefined") {
                            $.validator.unobtrusive.parse(this.$form);
                            validatedForm = this.$form.validate();
                        }

                        validatedForm.showErrors(response.Errors,true);
                    }
                }
            });
        } else {
            if (typeof buttonOpt.handler !== 'function') {
                throw 'action ' + buttonOpt.name + ' must implement an event handler or have an url option';
            }
            buttonOpt.handler.call(this, data);
        }

    };
    //#endregion

    //#region private methods
    Form.prototype._parse = function () {
        return this.element.parseForm(this.options.prefix ? this.options.prefix : '');
    };

    Form.prototype._saveGroupContainer = function () {
        if (this.options.saveGroupContainerState) {
            try {
                var arrayGroupContainers = [];
                var amplifyKey = this._getKeyForGroupContainer();

                this.$form.find(this.options.groupToggleContainerSelector).each(function () {
                    arrayGroupContainers.push($(this).next().is(":visible"));
                });

                amplify.store(amplifyKey, arrayGroupContainers);
            }
            catch (err) {
                console.warn('Error on saving on local storage:' + err);
            }
        }
    };

    Form.prototype._validate = function () {

        this.$form.removeData('validator').removeData('unobtrusiveValidation');

        $.validator.unobtrusive.parse(this.$form);

        var validatedForm = this.$form.validate();

        this._trigger('beforeFormValidation', 0, {
            validator: validatedForm,
            form: this.$form,
            name: this.options.uniqueName
        });

        return this.$form.valid();
    };

    Form.prototype._getAction = function (action) {

        return $.grep(this._buttons, function(elem, idx) {
            return elem.name == action;
        })[0];

    };

    Form.prototype._refresh = function (data) {
        var deferred = $.Deferred();

        return $.bforms.ajax({
            name: 'BsForm|Refresh|' + this.options.uniqueName,
            url: this.options.refreshUrl,
            data: data,
            callbackData: {
                deferred: deferred
            },
            context: this,
            success: this._onRefreshSuccess,
            error: this._onRefreshError,
            loadingElement: this.$form,
            loadingClass: 'loading'
        });
    };

    Form.prototype._getKeyForGroupContainer = function () {
        return this.options.appendUrlToUniqueName ? 'groupContainer|' + this.options.uniqueName + "|" + location.host + location.pathname : 'groupContainer|' + this.options.uniqueName;
    };
    //#endregion

    //#region ajax
    Form.prototype._btnClickAjaxSuccess = function (data, callbackData) {
        if (typeof callbackData.handler === 'function') {
            callbackData.handler.call(this, callbackData.sent, data, this);
        }
    };

    Form.prototype._btnClickAjaxError = function (data) {
        if (data.Message) {
            var validatedForm = this.$form.data('validator');
            validatedForm.showSummaryError(data.Message);
        }
    };

    Form.prototype._onRefreshSuccess = function (response) {

        var $html = $(response.Html);
        this.$form.html($html.html());

        this._initSelectors();
        this._initAmplifyStore();
        this._addActions(this.options.actions);

        this.reset();

        var initUIPromise = this.$form.bsInitUI(this.options.style);
        initUIPromise.done($.proxy(function () {
            this._trigger('afterInitUI', 0, {
                name: this.options.uniqueName,
                form: this.$form
            });
            callbackData.deferred.resolve();
        }, this));
    };

    Form.prototype._onRefreshError = function (data) {

        if (data.Message) {
            var validatedForm = this.$form.data('validator');
            validatedForm.showSummaryError(data.Message);
        }
    };
    //#endregion

    //#region public methods
    Form.prototype.getFormData = function (data) {

        var form = this.element.find('form');

        form.removeData("validator");
        form.removeData("unobtrusiveValidation");
        $.validator.unobtrusive.parse(form);

        var validatedForm = form.validate();
        this._trigger('beforeFormValidation', 0, {
            validator: validatedForm,
            form: form,
            name: this.options.uniqueName
        });

        if (form.valid()) {
            data = this._parse();
        }

    };

    Form.prototype.parse = function(e) {
        return this._parse();
    };

    Form.prototype.triggerAction = function(actionName) {

        var action = this._getAction(actionName);

        if (action != null) {
            action.elem.trigger('click');
        }

    };

    Form.prototype.refresh = function (data) {
        return this._refresh(data);
    };

    Form.prototype.reset = function (e) {
        this.element.bsResetForm(this.options.focusFirst);
    };

    Form.prototype.toggleGroup = function ($elem) {
        if (this.options.hasGroupToggle) {
            $elem.find(this.options.glyphClass).toggleClass(this.options.groupToggleUp).toggleClass(this.options.groupToggleDown);
            $elem.toggleClass('open').closest(this.options.groupToggleContainerSelector).next().stop().slideToggle($.proxy(this._saveGroupContainer, this));
        }
    };

    Form.prototype.showGroup = function ($elem) {
        if (this.options.hasGroupToggle) {
            $elem.find(this.options.glyphClass).removeClass(this.options.groupToggleUp).addClass(this.options.groupToggleDown);
            $elem.addClass('open').closest(this.options.groupToggleContainerSelector).next().stop().slideDown($.proxy(this._saveGroupContainer, this));
        }
    };

    Form.prototype.hideGroup = function ($elem) {
        if (this.options.hasGroupToggle) {
            $elem.find(this.options.glyphClass).addClass(this.options.groupToggleUp).removeClass(this.options.groupToggleDown);
            $elem.removeClass('open').closest(this.options.groupToggleContainerSelector).next().stop().slideUp($.proxy(this._saveGroupContainer, this));
        }
    };

    //#endregion

    $.widget('bforms.bsForm', Form.prototype);

    return Form;
});
<commit_msg>Added callBackData to BsForm Refresh<commit_after>define('bforms-form', [
    'jquery',
    'bforms-extensions',
    'jquery-ui-core',
    'bforms-validate-unobtrusive',
    'bforms-initUI',
    'bforms-ajax',
    'amplify'
], function () {

    var Form = function (opt) {
        this.options = opt;
        this._create();
    };

    Form.prototype.options = {
        uniqueName: null,
        hasGroupToggle: true,
        style: {},
        focusFirst: true,
        // save opened group containers in localstorage and retreive it later
        saveGroupContainerState: true,
        appendUrlToUniqueName :true,
        groupToggleSelector: '.bs-group_toggle',
        groupToggleContainerSelector: '.bs-group_toggle_container',
        groupToggleUp: 'glyphicon-chevron-up',
        groupToggleDown: 'glyphicon-chevron-down',
        glyphClass: '.glyphicon',
        actions: [],
        refreshUrl: null
    };

    //#region init
    Form.prototype._init = function () {

        if (!this.options.uniqueName){
            this.options.uniqueName = this.element.attr('id');
        }

        if (!this.options.uniqueName) {
            throw 'form needs a unique name or the element on which it is aplied has to have an id attr';
        }

        this._buttons = new Array();

        this._initSelectors();

        this._addDelegates();

        this._initAmplifyStore();

        this._addActions(this.options.actions);

        var initUIPromise = this.$form.bsInitUI(this.options.style);
        initUIPromise.done($.proxy(function() {
            this._trigger('afterInitUI', 0, {
                name: this.options.uniqueName,
                form: this.$form
            });
        }, this));

    };

    Form.prototype._initSelectors = function () {

        this.$form = this.element.is('form') ? this.element : this.element.find('form');

    };

    Form.prototype._addDelegates = function () {

        if (this.options.hasGroupToggle) {
            this.element.on('click', this.options.groupToggleSelector, $.proxy(function (e) {
                var $elem = $(e.currentTarget);
                this.toggleGroup($elem);
            }, this));
        }
    };

    Form.prototype._initAmplifyStore = function () {

        if (this.options.saveGroupContainerState) {
            var amplifyKey = this._getKeyForGroupContainer();

            if (amplify.store(amplifyKey)) {
                try {
                    var savedGroupContainerValues = amplify.store(amplifyKey);
                    var context = this;
                    this.$form.find(this.options.groupToggleSelector).each(function (index) {
                        if (savedGroupContainerValues[index]) {
                            context.showGroup($(this));
                        } else {
                            context.hideGroup($(this));
                        }
                    });
                }
                catch (err) {
                    console.warn('Error on saving on local storage:'+err);
                }
            }
        }
    };

    Form.prototype._addActions = function (actions) {

        if (actions) {
            for (var i = 0; i < actions.length; i++) {
                this._addAction(actions[i]);
            }
        }

    };

    Form.prototype._addAction = function (buttonOpt) {

        var $elem = this.element.find(buttonOpt.selector);

        if ($elem.length == 0) {
            throw 'element with selector ' + buttonOpt.selector + ' is not found in form container ' + this.options.uniqueName;
        }

        $elem.on('click', {
            buttonOpt: buttonOpt,
            handlerContext: this.options.handlerContext
        }, $.proxy(this._evBtnClick, this));

        this._buttons.push({
            name: buttonOpt.name,
            elem: $elem
        });

    };
    //#endregion

    //#region events
    Form.prototype._evBtnClick = function (e) {

        e.preventDefault();

        var $me = $(e.currentTarget);
        var buttonOpt = e.data.buttonOpt;
        var handlerContext = e.data.handlerContext;

        if (buttonOpt.validate && !this._validate()) {
            return;
        }

        var validatedForm = this.$form.validate();

        var data;
        if (buttonOpt.parse) {
            data = this._parse();
            if (typeof buttonOpt.getExtraData === 'function') {
                buttonOpt.getExtraData.call(this, data);
            }

            this._trigger('beforeFormSubmit', 0, {
                $button: $me,
                buttonOpt: buttonOpt,
                data: data
            });
        }

        var action = $me.data('action') || buttonOpt.actionUrl;
        if (action) {
            $.bforms.ajax({
                name: this.options.uniqueName,
                url: action,
                data: data,
                callbackData: {
                    handler: buttonOpt.handler,
                    handlerContext: handlerContext,
                    sent: data
                },
                context: this,
                success: $.proxy(this._btnClickAjaxSuccess, this),
                error: $.proxy(this._btnClickAjaxError, this),
                loadingElement: this.element,
                loadingClass: 'loading',
                validationError: function (response) {

                    if (response != null && response.Errors != null) {

                        if (typeof validatedForm === "undefined") {
                            $.validator.unobtrusive.parse(this.$form);
                            validatedForm = this.$form.validate();
                        }

                        validatedForm.showErrors(response.Errors,true);
                    }
                }
            });
        } else {
            if (typeof buttonOpt.handler !== 'function') {
                throw 'action ' + buttonOpt.name + ' must implement an event handler or have an url option';
            }
            buttonOpt.handler.call(this, data);
        }

    };
    //#endregion

    //#region private methods
    Form.prototype._parse = function () {
        return this.element.parseForm(this.options.prefix ? this.options.prefix : '');
    };

    Form.prototype._saveGroupContainer = function () {
        if (this.options.saveGroupContainerState) {
            try {
                var arrayGroupContainers = [];
                var amplifyKey = this._getKeyForGroupContainer();

                this.$form.find(this.options.groupToggleContainerSelector).each(function () {
                    arrayGroupContainers.push($(this).next().is(":visible"));
                });

                amplify.store(amplifyKey, arrayGroupContainers);
            }
            catch (err) {
                console.warn('Error on saving on local storage:' + err);
            }
        }
    };

    Form.prototype._validate = function () {

        this.$form.removeData('validator').removeData('unobtrusiveValidation');

        $.validator.unobtrusive.parse(this.$form);

        var validatedForm = this.$form.validate();

        this._trigger('beforeFormValidation', 0, {
            validator: validatedForm,
            form: this.$form,
            name: this.options.uniqueName
        });

        return this.$form.valid();
    };

    Form.prototype._getAction = function (action) {

        return $.grep(this._buttons, function(elem, idx) {
            return elem.name == action;
        })[0];

    };

    Form.prototype._refresh = function (data) {
        var deferred = $.Deferred();

        return $.bforms.ajax({
            name: 'BsForm|Refresh|' + this.options.uniqueName,
            url: this.options.refreshUrl,
            data: data,
            callbackData: {
                deferred: deferred
            },
            context: this,
            success: this._onRefreshSuccess,
            error: this._onRefreshError,
            loadingElement: this.$form,
            loadingClass: 'loading'
        });
    };

    Form.prototype._getKeyForGroupContainer = function () {
        return this.options.appendUrlToUniqueName ? 'groupContainer|' + this.options.uniqueName + "|" + location.host + location.pathname : 'groupContainer|' + this.options.uniqueName;
    };
    //#endregion

    //#region ajax
    Form.prototype._btnClickAjaxSuccess = function (data, callbackData) {
        if (typeof callbackData.handler === 'function') {
            callbackData.handler.call(this, callbackData.sent, data, this);
        }
    };

    Form.prototype._btnClickAjaxError = function (data) {
        if (data.Message) {
            var validatedForm = this.$form.data('validator');
            validatedForm.showSummaryError(data.Message);
        }
    };

    Form.prototype._onRefreshSuccess = function (response, callbackData) {

        var $html = $(response.Html);
        this.$form.html($html.html());

        this._initSelectors();
        this._initAmplifyStore();
        this._addActions(this.options.actions);

        this.reset();

        var initUIPromise = this.$form.bsInitUI(this.options.style);
        initUIPromise.done($.proxy(function () {
            this._trigger('afterInitUI', 0, {
                name: this.options.uniqueName,
                form: this.$form
            });
            callbackData.deferred.resolve();
        }, this));
    };

    Form.prototype._onRefreshError = function (data) {

        if (data.Message) {
            var validatedForm = this.$form.data('validator');
            validatedForm.showSummaryError(data.Message);
        }
    };
    //#endregion

    //#region public methods
    Form.prototype.getFormData = function (data) {

        var form = this.element.find('form');

        form.removeData("validator");
        form.removeData("unobtrusiveValidation");
        $.validator.unobtrusive.parse(form);

        var validatedForm = form.validate();
        this._trigger('beforeFormValidation', 0, {
            validator: validatedForm,
            form: form,
            name: this.options.uniqueName
        });

        if (form.valid()) {
            data = this._parse();
        }

    };

    Form.prototype.parse = function(e) {
        return this._parse();
    };

    Form.prototype.triggerAction = function(actionName) {

        var action = this._getAction(actionName);

        if (action != null) {
            action.elem.trigger('click');
        }

    };

    Form.prototype.refresh = function (data) {
        return this._refresh(data);
    };

    Form.prototype.reset = function (e) {
        this.element.bsResetForm(this.options.focusFirst);
    };

    Form.prototype.toggleGroup = function ($elem) {
        if (this.options.hasGroupToggle) {
            $elem.find(this.options.glyphClass).toggleClass(this.options.groupToggleUp).toggleClass(this.options.groupToggleDown);
            $elem.toggleClass('open').closest(this.options.groupToggleContainerSelector).next().stop().slideToggle($.proxy(this._saveGroupContainer, this));
        }
    };

    Form.prototype.showGroup = function ($elem) {
        if (this.options.hasGroupToggle) {
            $elem.find(this.options.glyphClass).removeClass(this.options.groupToggleUp).addClass(this.options.groupToggleDown);
            $elem.addClass('open').closest(this.options.groupToggleContainerSelector).next().stop().slideDown($.proxy(this._saveGroupContainer, this));
        }
    };

    Form.prototype.hideGroup = function ($elem) {
        if (this.options.hasGroupToggle) {
            $elem.find(this.options.glyphClass).addClass(this.options.groupToggleUp).removeClass(this.options.groupToggleDown);
            $elem.removeClass('open').closest(this.options.groupToggleContainerSelector).next().stop().slideUp($.proxy(this._saveGroupContainer, this));
        }
    };

    //#endregion

    $.widget('bforms.bsForm', Form.prototype);

    return Form;
});
<|endoftext|>