<commit_before>'use strict';

(function() {

var eventPrefix = 'oidcauth:';

var unauthorizedEvent =          eventPrefix + 'unauthorized';
var tokenExpiredEvent =          eventPrefix + 'tokenExpired';
var tokenMissingEvent =          eventPrefix + 'tokenMissing';
var tokenExpiresSoonEvent =      eventPrefix + 'tokenExpires';

var loggedInEvent =              eventPrefix + 'loggedIn';
var loggedOutEvent =             eventPrefix + 'loggedOut';

var silentRefreshStartedEvent =  eventPrefix + 'silentRefreshStarted';
var silentRefreshSuceededEvent = eventPrefix + 'silentRefreshSucceded';
var silentRefreshFailedEvent =   eventPrefix + 'silentRefreshFailed';
var silentRefreshTimeoutEvent =  eventPrefix + 'silentRefreshTimeout';

// Module registrarion
var oidcmodule = angular.module('oidc-angular', ['base64', 'ngStorage', 'ngRoute']);

oidcmodule.config(['$httpProvider', '$routeProvider', function($httpProvider, $routeProvider) {
    $httpProvider.interceptors.push('oidcHttpInterceptor');

    // Register callback route
    $routeProvider.
        when('/auth/callback/:data', {
            template: '',
            controller: ['$auth', '$routeParams', function ($auth, $routeParams) {
                console.debug('oidc-angular: handling login-callback');
                $auth.handleSignInCallback($routeParams.data);
            }]
        }).
        when('/auth/clear', {
            template: '',
            controller: ['$auth', function ($auth) {
                console.debug('oidc-angular: handling logout-callback');
                $auth.handleSignOutCallback();
            }]
        });

    console.debug('oidc-angular: callback routes registered.')
}]);

oidcmodule.factory('oidcHttpInterceptor', ['$rootScope', '$q', '$auth', 'tokenService', function($rootScope, $q, $auth, tokenService) {
      return {

        'request': function(request) {

         if (request.url.startsWith($auth.config.apiUrl)) {

              if (tokenService.hasToken()) {

                  if (tokenService.hasValidToken())
                  {
                      var token = tokenService.getIdToken();
                      request.headers['Authorization'] = 'Bearer ' + token;
                  }
                  else {
                      //$rootScope.$broadcast(tokenExpiredEvent);
                  }
              }
              else {
                  //$rootScope.$broadcast(tokenMissingEvent);
              }
          }

          // do something on success
          return request;
        },

        'response': function(response) {

            if (response.status == 401) {
              if (!tokenService.hasToken()) {
                  // There was probably no token attached, because there is none
                  $rootScope.$broadcast(tokenMissingEvent);
              }
              else if (!tokenService.hasValidToken()) {
                  // Seems the token is not valid anymore
                  $rootScope.$broadcast(tokenExpiredEvent);
              }
              else {
                  // any other
                  $rootScope.$broadcast(unauthorizedEvent);
              }
            }
            else {
                // Proactive check if the token will expire soo
                $auth.validateExpirity();
            }

            return response;
            }
      };
    }]);

oidcmodule.service('tokenService', ['$base64', '$localStorage', function ($base64, $localStorage) {

    var service = this;

    var padBase64 = function (base64data) {
        while (base64data.length % 4 !== 0) {
            base64data += "=";
        }
        return base64data;
    };

    service.getPayloadFromRawToken = function(raw)
    {
        var tokenParts = raw.split(".");
        return tokenParts[1];
    };

    service.deserializeClaims = function(raw) {
        var claimsBase64 = padBase64(raw);
        var claimsJson = $base64.decode(claimsBase64);

        var claims = JSON.parse(claimsJson);

        return claims;
    };

    service.convertToClaims = function(id_token) {
        var payload = service.getPayloadFromRawToken(id_token);
        var claims = service.deserializeClaims(payload);

        return claims;
    };

    service.saveToken = function (id_token) {
        $localStorage['idToken'] =  id_token;

        var idClaims = service.convertToClaims(id_token);
        $localStorage['cached-claims'] =  idClaims;
    };

    service.hasToken = function() {

        var claims = service.allClaims();

        if (!(claims && claims.hasOwnProperty("iat") && claims.hasOwnProperty('exp'))) {
            return false;
        }

        return true;
    };

    service.hasValidToken = function() {
        if (!this.hasToken()) return false;

        var claims = service.allClaims();

        var now = Date.now();
        var issuedAtMSec = claims.iat * 1000;
        var expiresAtMSec = claims.exp * 1000;

        if (issuedAtMSec > now || expiresAtMSec < now) {
            return false;
        }

        return true;
    }

    service.allClaims = function() {
        var cachedClaims = $localStorage['cached-claims'];

        if (!cachedClaims) {
            var id_token = service.getIdToken();

            if (id_token) {
                var claims = service.convertToClaims(id_token);

                var idClaims = service.convertToClaims(id_token);
                $localStorage['cached-claims'] =  idClaims;

                return claims;
            }
        }

        return cachedClaims;
    };

    service.getIdToken = function() {
        return $localStorage['idToken'];
    };

    service.clearTokens = function() {
        delete $localStorage['cached-claims'];
        delete $localStorage['idToken'];
    }
}]);

oidcmodule.provider("$auth", ['$routeProvider', function ($routeProvider) {

    // Default configuration
    var config = {
        issuer: null,
        basePath: null,
        clientId: null,
        apiUrl: '/api/',
        responseType: 'id_token',
        scope: "openid profile",
        redirectUri: (window.location.origin || window.location.protocol + '//' + window.location.host) + window.location.pathname + '#/auth/callback/',
        logoutUri: (window.location.origin || window.location.protocol + '//' + window.location.host) + window.location.pathname + '#/auth/clear',
        state: "",
        jwksUri :              '.well-known/jwks',
        authorizationEndpoint:  'connect/authorize',
        revocationEndpoint:     'connect/revocation',
        endSessionEndpoint:     'connect/endsession',
        advanceRefresh:         300,
      };

    return {

        // Service configuration
        configure: function (params) {
            angular.extend(config, params);
        },

        // Service itself
        $get: ['$q', '$document', '$rootScope', '$localStorage', '$location', 'tokenService', function ($q, $document, $rootScope, $localStorage, $location, tokenService) {

            var init = function() {

                if ($localStorage['logoutActive']) {
                    delete $localStorage['logoutActive'];

                    tokenService.clearTokens();
                }

                if ($localStorage['refreshRunning']) {
                    delete $localStorage['refreshRunning'];
                }
            };

            var createLoginUrl = function (nonce, state) {

                var hasPathDelimiter = config.basePath.endsWith('/');
                var appendChar = (hasPathDelimiter) ? '' : '/';

                var currentClaims = tokenService.allClaims();
                if (currentClaims) {
                    var idpClaimValue = currentClaims["idp"];
                }

                var baseUrl = config.basePath + appendChar;
                var url = baseUrl + config.authorizationEndpoint
                                  + "?response_type="
                                  + encodeURIComponent(config.responseType)
                                  + "&client_id="
                                  + encodeURIComponent(config.clientId)
                                  + "&state="
                                  + encodeURIComponent(state || config.state)
                                  + "&redirect_uri="
                                  + encodeURIComponent(config.redirectUri)
                                  + "&scope="
                                  + encodeURIComponent(config.scope)
                                  + "&nonce="
                                   + encodeURIComponent(nonce);

                if (idpClaimValue) {
                    url = url + "&acr_values="
                              + encodeURIComponent("idp:" + idpClaimValue);
                }

                return url;
            };

            var createLogoutUrl = function(state) {

                var idToken = tokenService.getIdToken();

                var hasPathDelimiter = config.basePath.endsWith('/');
                var appendChar = (hasPathDelimiter) ? '' : '/';

                var baseUrl = config.basePath + appendChar;
                var url = baseUrl + config.endSessionEndpoint
                                  + "?id_token_hint="
                                  + encodeURIComponent(idToken)
                                  + "&post_logout_redirect_uri="
                                  + encodeURIComponent(config.logoutUri)
                                  + "&state="
                                  + encodeURIComponent(state || config.state)
                return url;
            }

            var startImplicitFlow = function (localRedirect) {

                $localStorage['localRedirect'] = localRedirect;

                var url = createLoginUrl("dummynonce");
                window.location.replace(url);
            };

            var startLogout = function () {
                var url = createLogoutUrl();
                $localStorage['logoutActive'] = true;

                window.location.replace(url);
            };

            var handleImplicitFlowCallback = function(id_token) {

                tokenService.saveToken(id_token);

                var localRedirect = $localStorage['localRedirect'];

                if (localRedirect) {
                    $location.path(localRedirect);
                    delete $localStorage['localRedirect'];
                }
                else {
                    $location.path('/');
                }

                $rootScope.$broadcast(loggedInEvent);
                return true;
            };

            var handleSilentRefreshCallback = function(newIdToken) {

                delete $localStorage['refreshRunning'];

                var currentIdToken = tokenService.getIdToken();
                var currentClaims = tokenService.allClaims();

                var newClaims = tokenService.convertToClaims(newIdToken)

                if (currentClaims.exp && newClaims.exp && newClaims.exp > currentClaims.exp) {

                    tokenService.saveToken(newIdToken);

                    $rootScope.$broadcast(silentRefreshSuceededEvent);
                }
                else {
                    $rootScope.$broadcast(silentRefreshFailedEvent);
                }
            };

            var trySilentRefresh = function() {

                if ($localStorage['refreshRunning']) {
                    return;
                }

                $localStorage['refreshRunning'] = true;

                $rootScope.$broadcast(silentRefreshStartedEvent);

                var url = createLoginUrl('dummynonce', 'refresh');

                var html = "<iframe src='" + url + "' height='400' width='100%' id='oauthFrame' style='display:none;visibility:hidden;'></iframe>";
                var elem = angular.element(html);

                $document.find("body").append(elem);

                setTimeout(function() {
                    if ($localStorage['refreshRunning']) {
                        $rootScope.$broadcast(silentRefreshTimeoutEvent);
                        delete $localStorage['refreshRunning']
                    }

                    $document.find("#oauthFrame").remove();
                }, 5000);
            };

            var handleSignInCallback = function(data) {

                if (!data && window.location.hash.indexOf("#") === 0) {
                    data = window.location.hash.substr(16)
                }

                var fragments = {}
                if (data) {
                    fragments = parseQueryString(data);
                }
                else {
                    throw Error("Unable to process callback. No data given!");
                }

                console.debug("oidc-angular: Processing callback information", data);

                var id_token     = fragments['id_token'];
                var state        = fragments['state'];

                if (id_token) {
                    if (state === 'refresh') {
                        handleSilentRefreshCallback(id_token);
                    }
                    else {
                        handleImplicitFlowCallback(id_token);
                    }
                }
            };

            var handleSignOutCallback = function() {

                delete $localStorage['logoutActive'];

                tokenService.clearTokens();
                $location.path('/');

                $rootScope.$broadcast(loggedOutEvent);
            };

            var tokenIsValidAt = function(date) {
                var claims = tokenService.allClaims();

                var expiresAtMSec = claims.exp * 1000;

                if (date <= expiresAtMSec) {
                    return true;
                }

                return false;
            }

            var validateExpirity = function() {
                if (!tokenService.hasToken()) return;
                if (!tokenService.hasValidToken()) return;

                var now = Date.now();

                if (!tokenIsValidAt(now + config.advanceRefresh)) {
                    $rootScope.$broadcast(tokenExpiresSoonEvent);
                    trySilentRefresh();
                }
            };

            init();

            return {
                config: config,

                handleSignInCallback : handleSignInCallback,

                handleSignOutCallback : handleSignOutCallback,

                validateExpirity: validateExpirity,

                isAuthenticated : function() {
                    return tokenService.hasValidToken();
                },

                isAuthenticatedIn : function(milliseconds) {
                    return tokenService.hasValidToken() && tokenIsValidAt(new Date().getTime() + milliseconds);
                },

                signIn : function(localRedirect) {
                    startImplicitFlow(localRedirect);
                },

                signOut : function() {
                    startLogout();
                },

                silentRefresh : function() {
                    trySilentRefresh();
                }

            };
        }]
    };
}]);

/* Helpers & Polyfills */
function parseQueryString(queryString) {
    var data = {}, pairs, pair, separatorIndex, escapedKey, escapedValue, key, value;

    if (queryString === null) {
        return data;
    }

    pairs = queryString.split("&");

    for (var i = 0; i < pairs.length; i++) {
        pair = pairs[i];
        separatorIndex = pair.indexOf("=");

        if (separatorIndex === -1) {
            escapedKey = pair;
            escapedValue = null;
        } else {
            escapedKey = pair.substr(0, separatorIndex);
            escapedValue = pair.substr(separatorIndex + 1);
        }

        key = decodeURIComponent(escapedKey);
        value = decodeURIComponent(escapedValue);

        if (key.substr(0, 1) === '/')
            key = key.substr(1);

        data[key] = value;
    }

    return data;
 };

if (!String.prototype.endsWith) {
    String.prototype.endsWith = function (searchString, position) {
        var subjectString = this.toString();
        if (position === undefined || position > subjectString.length) {
            position = subjectString.length;
        }
        position -= searchString.length;
        var lastIndex = subjectString.indexOf(searchString, position);
        return lastIndex !== -1 && lastIndex === position;
    };
}

if (!String.prototype.startsWith) {
  String.prototype.startsWith = function(searchString, position) {
    position = position || 0;
    return this.lastIndexOf(searchString, position) === position;
  };
}

})();<commit_msg>splitted to have more detailed information for debugging reasons<commit_after>'use strict';

(function() {

var eventPrefix = 'oidcauth:';

var unauthorizedEvent =          eventPrefix + 'unauthorized';
var tokenExpiredEvent =          eventPrefix + 'tokenExpired';
var tokenMissingEvent =          eventPrefix + 'tokenMissing';
var tokenExpiresSoonEvent =      eventPrefix + 'tokenExpires';

var loggedInEvent =              eventPrefix + 'loggedIn';
var loggedOutEvent =             eventPrefix + 'loggedOut';

var silentRefreshStartedEvent =  eventPrefix + 'silentRefreshStarted';
var silentRefreshSuceededEvent = eventPrefix + 'silentRefreshSucceded';
var silentRefreshFailedEvent =   eventPrefix + 'silentRefreshFailed';
var silentRefreshTimeoutEvent =  eventPrefix + 'silentRefreshTimeout';

// Module registrarion
var oidcmodule = angular.module('oidc-angular', ['base64', 'ngStorage', 'ngRoute']);

oidcmodule.config(['$httpProvider', '$routeProvider', function($httpProvider, $routeProvider) {
    $httpProvider.interceptors.push('oidcHttpInterceptor');

    // Register callback route
    $routeProvider.
        when('/auth/callback/:data', {
            template: '',
            controller: ['$auth', '$routeParams', function ($auth, $routeParams) {
                console.debug('oidc-angular: handling login-callback');
                $auth.handleSignInCallback($routeParams.data);
            }]
        }).
        when('/auth/clear', {
            template: '',
            controller: ['$auth', function ($auth) {
                console.debug('oidc-angular: handling logout-callback');
                $auth.handleSignOutCallback();
            }]
        });

    console.debug('oidc-angular: callback routes registered.')
}]);

oidcmodule.factory('oidcHttpInterceptor', ['$rootScope', '$q', '$auth', 'tokenService', function($rootScope, $q, $auth, tokenService) {
      return {

        'request': function(request) {

         if (request.url.startsWith($auth.config.apiUrl)) {

              if (tokenService.hasToken()) {

                  if (tokenService.hasValidToken())
                  {
                      var token = tokenService.getIdToken();
                      request.headers['Authorization'] = 'Bearer ' + token;
                  }
                  else {
                      //$rootScope.$broadcast(tokenExpiredEvent);
                  }
              }
              else {
                  //$rootScope.$broadcast(tokenMissingEvent);
              }
          }

          // do something on success
          return request;
        },

        'response': function(response) {

            if (response.status == 401) {
              if (!tokenService.hasToken()) {
                  // There was probably no token attached, because there is none
                  $rootScope.$broadcast(tokenMissingEvent);
              }
              else if (!tokenService.hasValidToken()) {
                  // Seems the token is not valid anymore
                  $rootScope.$broadcast(tokenExpiredEvent);
              }
              else {
                  // any other
                  $rootScope.$broadcast(unauthorizedEvent);
              }
            }
            else {
                // Proactive check if the token will expire soo
                $auth.validateExpirity();
            }

            return response;
            }
      };
    }]);

oidcmodule.service('tokenService', ['$base64', '$localStorage', function ($base64, $localStorage) {

    var service = this;

    var padBase64 = function (base64data) {
        while (base64data.length % 4 !== 0) {
            base64data += "=";
        }
        return base64data;
    };

    service.getPayloadFromRawToken = function(raw)
    {
        var tokenParts = raw.split(".");
        return tokenParts[1];
    };

    service.deserializeClaims = function(raw) {
        var claimsBase64 = padBase64(raw);
        var claimsJson = $base64.decode(claimsBase64);

        var claims = JSON.parse(claimsJson);

        return claims;
    };

    service.convertToClaims = function(id_token) {
        var payload = service.getPayloadFromRawToken(id_token);
        var claims = service.deserializeClaims(payload);

        return claims;
    };

    service.saveToken = function (id_token) {
        $localStorage['idToken'] =  id_token;

        var idClaims = service.convertToClaims(id_token);
        $localStorage['cached-claims'] =  idClaims;
    };

    service.hasToken = function() {

        var claims = service.allClaims();

        if (!(claims && claims.hasOwnProperty("iat") && claims.hasOwnProperty('exp'))) {
            return false;
        }

        return true;
    };

    service.hasValidToken = function() {
        if (!this.hasToken()) return false;

        var claims = service.allClaims();

        var now = Date.now();
        var issuedAtMSec = claims.iat * 1000;
        var expiresAtMSec = claims.exp * 1000;

        if (issuedAtMSec > now) {
            console.log('oidc-connect: Token is not yet valid!')
            return false
        }

        if (expiresAtMSec < now) {
            console.log('oidc-connect: Token has expired!')
            return false;
        }

        return true;
    }

    service.allClaims = function() {
        var cachedClaims = $localStorage['cached-claims'];

        if (!cachedClaims) {
            var id_token = service.getIdToken();

            if (id_token) {
                var claims = service.convertToClaims(id_token);

                var idClaims = service.convertToClaims(id_token);
                $localStorage['cached-claims'] =  idClaims;

                return claims;
            }
        }

        return cachedClaims;
    };

    service.getIdToken = function() {
        return $localStorage['idToken'];
    };

    service.clearTokens = function() {
        delete $localStorage['cached-claims'];
        delete $localStorage['idToken'];
    }
}]);

oidcmodule.provider("$auth", ['$routeProvider', function ($routeProvider) {

    // Default configuration
    var config = {
        issuer: null,
        basePath: null,
        clientId: null,
        apiUrl: '/api/',
        responseType: 'id_token',
        scope: "openid profile",
        redirectUri: (window.location.origin || window.location.protocol + '//' + window.location.host) + window.location.pathname + '#/auth/callback/',
        logoutUri: (window.location.origin || window.location.protocol + '//' + window.location.host) + window.location.pathname + '#/auth/clear',
        state: "",
        jwksUri :              '.well-known/jwks',
        authorizationEndpoint:  'connect/authorize',
        revocationEndpoint:     'connect/revocation',
        endSessionEndpoint:     'connect/endsession',
        advanceRefresh:         300,
      };

    return {

        // Service configuration
        configure: function (params) {
            angular.extend(config, params);
        },

        // Service itself
        $get: ['$q', '$document', '$rootScope', '$localStorage', '$location', 'tokenService', function ($q, $document, $rootScope, $localStorage, $location, tokenService) {

            var init = function() {

                if ($localStorage['logoutActive']) {
                    delete $localStorage['logoutActive'];

                    tokenService.clearTokens();
                }

                if ($localStorage['refreshRunning']) {
                    delete $localStorage['refreshRunning'];
                }
            };

            var createLoginUrl = function (nonce, state) {

                var hasPathDelimiter = config.basePath.endsWith('/');
                var appendChar = (hasPathDelimiter) ? '' : '/';

                var currentClaims = tokenService.allClaims();
                if (currentClaims) {
                    var idpClaimValue = currentClaims["idp"];
                }

                var baseUrl = config.basePath + appendChar;
                var url = baseUrl + config.authorizationEndpoint
                                  + "?response_type="
                                  + encodeURIComponent(config.responseType)
                                  + "&client_id="
                                  + encodeURIComponent(config.clientId)
                                  + "&state="
                                  + encodeURIComponent(state || config.state)
                                  + "&redirect_uri="
                                  + encodeURIComponent(config.redirectUri)
                                  + "&scope="
                                  + encodeURIComponent(config.scope)
                                  + "&nonce="
                                   + encodeURIComponent(nonce);

                if (idpClaimValue) {
                    url = url + "&acr_values="
                              + encodeURIComponent("idp:" + idpClaimValue);
                }

                return url;
            };

            var createLogoutUrl = function(state) {

                var idToken = tokenService.getIdToken();

                var hasPathDelimiter = config.basePath.endsWith('/');
                var appendChar = (hasPathDelimiter) ? '' : '/';

                var baseUrl = config.basePath + appendChar;
                var url = baseUrl + config.endSessionEndpoint
                                  + "?id_token_hint="
                                  + encodeURIComponent(idToken)
                                  + "&post_logout_redirect_uri="
                                  + encodeURIComponent(config.logoutUri)
                                  + "&state="
                                  + encodeURIComponent(state || config.state)
                return url;
            }

            var startImplicitFlow = function (localRedirect) {

                $localStorage['localRedirect'] = localRedirect;

                var url = createLoginUrl("dummynonce");
                window.location.replace(url);
            };

            var startLogout = function () {
                var url = createLogoutUrl();
                $localStorage['logoutActive'] = true;

                window.location.replace(url);
            };

            var handleImplicitFlowCallback = function(id_token) {

                tokenService.saveToken(id_token);

                var localRedirect = $localStorage['localRedirect'];

                if (localRedirect) {
                    $location.path(localRedirect);
                    delete $localStorage['localRedirect'];
                }
                else {
                    $location.path('/');
                }

                $rootScope.$broadcast(loggedInEvent);
                return true;
            };

            var handleSilentRefreshCallback = function(newIdToken) {

                delete $localStorage['refreshRunning'];

                var currentIdToken = tokenService.getIdToken();
                var currentClaims = tokenService.allClaims();

                var newClaims = tokenService.convertToClaims(newIdToken)

                if (currentClaims.exp && newClaims.exp && newClaims.exp > currentClaims.exp) {

                    tokenService.saveToken(newIdToken);

                    $rootScope.$broadcast(silentRefreshSuceededEvent);
                }
                else {
                    $rootScope.$broadcast(silentRefreshFailedEvent);
                }
            };

            var trySilentRefresh = function() {

                if ($localStorage['refreshRunning']) {
                    return;
                }

                $localStorage['refreshRunning'] = true;

                $rootScope.$broadcast(silentRefreshStartedEvent);

                var url = createLoginUrl('dummynonce', 'refresh');

                var html = "<iframe src='" + url + "' height='400' width='100%' id='oauthFrame' style='display:none;visibility:hidden;'></iframe>";
                var elem = angular.element(html);

                $document.find("body").append(elem);

                setTimeout(function() {
                    if ($localStorage['refreshRunning']) {
                        $rootScope.$broadcast(silentRefreshTimeoutEvent);
                        delete $localStorage['refreshRunning']
                    }

                    $document.find("#oauthFrame").remove();
                }, 5000);
            };

            var handleSignInCallback = function(data) {

                if (!data && window.location.hash.indexOf("#") === 0) {
                    data = window.location.hash.substr(16)
                }

                var fragments = {}
                if (data) {
                    fragments = parseQueryString(data);
                }
                else {
                    throw Error("Unable to process callback. No data given!");
                }

                console.debug("oidc-angular: Processing callback information", data);

                var id_token     = fragments['id_token'];
                var state        = fragments['state'];

                if (id_token) {
                    if (state === 'refresh') {
                        handleSilentRefreshCallback(id_token);
                    }
                    else {
                        handleImplicitFlowCallback(id_token);
                    }
                }
            };

            var handleSignOutCallback = function() {

                delete $localStorage['logoutActive'];

                tokenService.clearTokens();
                $location.path('/');

                $rootScope.$broadcast(loggedOutEvent);
            };

            var tokenIsValidAt = function(date) {
                var claims = tokenService.allClaims();

                var expiresAtMSec = claims.exp * 1000;

                if (date <= expiresAtMSec) {
                    return true;
                }

                return false;
            }

            var validateExpirity = function() {
                if (!tokenService.hasToken()) return;
                if (!tokenService.hasValidToken()) return;

                var now = Date.now();

                if (!tokenIsValidAt(now + config.advanceRefresh)) {
                    $rootScope.$broadcast(tokenExpiresSoonEvent);
                    trySilentRefresh();
                }
            };

            init();

            return {
                config: config,

                handleSignInCallback : handleSignInCallback,

                handleSignOutCallback : handleSignOutCallback,

                validateExpirity: validateExpirity,

                isAuthenticated : function() {
                    return tokenService.hasValidToken();
                },

                isAuthenticatedIn : function(milliseconds) {
                    return tokenService.hasValidToken() && tokenIsValidAt(new Date().getTime() + milliseconds);
                },

                signIn : function(localRedirect) {
                    startImplicitFlow(localRedirect);
                },

                signOut : function() {
                    startLogout();
                },

                silentRefresh : function() {
                    trySilentRefresh();
                }

            };
        }]
    };
}]);

/* Helpers & Polyfills */
function parseQueryString(queryString) {
    var data = {}, pairs, pair, separatorIndex, escapedKey, escapedValue, key, value;

    if (queryString === null) {
        return data;
    }

    pairs = queryString.split("&");

    for (var i = 0; i < pairs.length; i++) {
        pair = pairs[i];
        separatorIndex = pair.indexOf("=");

        if (separatorIndex === -1) {
            escapedKey = pair;
            escapedValue = null;
        } else {
            escapedKey = pair.substr(0, separatorIndex);
            escapedValue = pair.substr(separatorIndex + 1);
        }

        key = decodeURIComponent(escapedKey);
        value = decodeURIComponent(escapedValue);

        if (key.substr(0, 1) === '/')
            key = key.substr(1);

        data[key] = value;
    }

    return data;
 };

if (!String.prototype.endsWith) {
    String.prototype.endsWith = function (searchString, position) {
        var subjectString = this.toString();
        if (position === undefined || position > subjectString.length) {
            position = subjectString.length;
        }
        position -= searchString.length;
        var lastIndex = subjectString.indexOf(searchString, position);
        return lastIndex !== -1 && lastIndex === position;
    };
}

if (!String.prototype.startsWith) {
  String.prototype.startsWith = function(searchString, position) {
    position = position || 0;
    return this.lastIndexOf(searchString, position) === position;
  };
}

})();<|endoftext|>


<commit_before>(function( w ){
    /* We can request an image at every possible width, but let's limit it to a reasonable number
       We can set these so they correspond to our more common sizes.
    */

    var RATIOS = {{ BETTY_RATIOS|safe }};
    var breakpoints = [0,{{ BETTY_WIDTHS|join:","}}];
    function tmpl(text, dict) {
        for (var k in dict) {
            text = text.replace("{" + k + "}", dict[k]);
        }
        return text;
    }
    w.picturefill = function(elements) {
        //don't need to do them all at once. can decide to do lazy load if needed
        if (elements instanceof Array) {
            var ps = elements;
        }
        else if (elements instanceof HTMLElement) {
            var ps = [ elements ];
        }
        else {
            var ps = w.document.getElementsByTagName( "div" );
        }
        var imageData = [];
        for( var i = 0, il = ps.length; i < il; i++ ){
            var el = ps[i];
            if(el.getAttribute( "data-type" ) !== "image" ){
                continue;
            }
            var div = el.getElementsByTagName( "div" )[0];
            if( el.getAttribute( "data-image-id" ) !== null ){
                var id = el.getAttribute( "data-image-id" ),
                    crop = el.getAttribute( "data-crop" );
                var _w = div.offsetWidth,
                    _h = div.offsetHeight;

                if (!crop || crop === "" || crop === "auto") {
                    crop = computeAspectRatio(_w, _h);
                }
                if (el.getAttribute("data-format")) {
                    format = el.getAttribute("data-format");
                }
                else {
                    format = "jpg";
                }

                var width = null;
                for (var j = 0; j < breakpoints.length; j++) {
                    if (_w <= breakpoints[j]) {
                        width = breakpoints[j];
                        break;
                    }
                }
                if (width === null) {
                  width = _w;
                }

                // Scale the image up to the pixel ratio
                if (w.devicePixelRatio) {
                  width = Math.round(w.devicePixelRatio * width);
                }

                // Find any existing img element in the picture element
                var picImg = div.getElementsByTagName( "img" )[ 0 ];

                if(!picImg){
                    // for performance reasons this will be added to the dom later
                    picImg = w.document.createElement( "img" );
                    picImg.alt = el.getAttribute( "data-alt" );
                }

                //picImg.className = "loading";
                picImg.onload = function() {
                    //this.className = "";
                };
                // if the existing image is larger (or the same) than the one we're about to load, do not update.
                //however if the crop changes, we need to reload.
                if (width > 0) {

                    //ie8 doesn't support natural width, always load.
                    if (typeof picImg.naturalWidth === "undefined" || picImg.naturalWidth < width ||
                        crop !== computeAspectRatio(picImg.naturalWidth, picImg.naturalHeight)) {
                        var id_str = "";
                        for(var ii=0; ii < id.length; ii++) {
                            if ((ii % 4) === 0) {
                                id_str += "/";
                            }
                            id_str += id.charAt(ii);
                        }
                        var url = "{{ BETTY_IMAGE_URL }}" + "/" + id_str + "/" + crop + "/" + width + "." + format;

                        imageData.push({
                            'div': div,
                            'img': picImg,
                            'url': url
                        });
                    }
                }
            }
        }
        // all DOM updates should probably go here
        for(var i = 0; i < imageData.length; i++) {
            var data = imageData[i];
            data.img.src = data.url;
            if (!data.img.parentNode) {
                data.div.appendChild(data.img);
            }
        }
    };

    function computeAspectRatio(_w, _h) {
        if (_w !== 0 && _h !== 0) {
            var aspectRatio = _w/_h;
            var difference = 10;
            for (var i in RATIOS) {
              if (difference > Math.abs(aspectRatio - RATIOS[i][1])) {
                difference = Math.abs(aspectRatio - RATIOS[i][1]);
              } else {
                return RATIOS[i][0];
              }
            }
        }
        else {
            return "16x9"
        }
    }

    // Run on resize and domready (w.load as a fallback)
    if (!w.IMAGE_LISTENERS_DISABLED) {
        if( w.addEventListener ){
            var pictureFillTimeout;
            w.addEventListener( "resize",
                function() {
                    clearTimeout(pictureFillTimeout);
                    pictureFillTimeout = setTimeout(w.picturefill, 100);
                }, false );

            w.addEventListener( "DOMContentLoaded", function(){
                w.picturefill();
                // Run once only
                w.removeEventListener( "load", w.picturefill, false );
            }, false );
            w.addEventListener( "load", w.picturefill, false );

        }
        else if( w.attachEvent ){
            w.attachEvent( "onload", w.picturefill );
        }
    }
}( this ));<commit_msg>computeAspectRatio computes aspect ratio correctly<commit_after>(function( w ){
    /* We can request an image at every possible width, but let's limit it to a reasonable number
       We can set these so they correspond to our more common sizes.
    */

    var RATIOS = {{ BETTY_RATIOS|safe }};
    var ASPECT_RATIO_TOLERANCE = .1; // 10% tolerance.

    var breakpoints = [0,{{ BETTY_WIDTHS|join:","}}];
    function tmpl(text, dict) {
        for (var k in dict) {
            text = text.replace("{" + k + "}", dict[k]);
        }
        return text;
    }
    w.picturefill = function(elements) {
        //don't need to do them all at once. can decide to do lazy load if needed
        if (elements instanceof Array) {
            var ps = elements;
        }
        else if (elements instanceof HTMLElement) {
            var ps = [ elements ];
        }
        else {
            var ps = w.document.getElementsByTagName( "div" );
        }
        var imageData = [];
        for( var i = 0, il = ps.length; i < il; i++ ){
            var el = ps[i];
            if(el.getAttribute( "data-type" ) !== "image" ){
                continue;
            }
            var div = el.getElementsByTagName( "div" )[0];
            if( el.getAttribute( "data-image-id" ) !== null ){
                var id = el.getAttribute( "data-image-id" ),
                    crop = el.getAttribute( "data-crop" );
                var _w = div.offsetWidth,
                    _h = div.offsetHeight;

                if (!crop || crop === "" || crop === "auto") {
                    crop = computeAspectRatio(_w, _h);
                }
                if (el.getAttribute("data-format")) {
                    format = el.getAttribute("data-format");
                }
                else {
                    format = "jpg";
                }

                var width = null;
                for (var j = 0; j < breakpoints.length; j++) {
                    if (_w <= breakpoints[j]) {
                        width = breakpoints[j];
                        break;
                    }
                }
                if (width === null) {
                  width = _w;
                }

                // Scale the image up to the pixel ratio
                if (w.devicePixelRatio) {
                  width = Math.round(w.devicePixelRatio * width);
                }

                // Find any existing img element in the picture element
                var picImg = div.getElementsByTagName( "img" )[ 0 ];

                if(!picImg){
                    // for performance reasons this will be added to the dom later
                    picImg = w.document.createElement( "img" );
                    picImg.alt = el.getAttribute( "data-alt" );
                }

                //picImg.className = "loading";
                picImg.onload = function() {
                    //this.className = "";
                };
                // if the existing image is larger (or the same) than the one we're about to load, do not update.
                //however if the crop changes, we need to reload.
                if (width > 0) {

                    //ie8 doesn't support natural width, always load.
                    if (typeof picImg.naturalWidth === "undefined" || picImg.naturalWidth < width ||
                        crop !== computeAspectRatio(picImg.naturalWidth, picImg.naturalHeight)) {
                        var id_str = "";
                        for(var ii=0; ii < id.length; ii++) {
                            if ((ii % 4) === 0) {
                                id_str += "/";
                            }
                            id_str += id.charAt(ii);
                        }
                        var url = "{{ BETTY_IMAGE_URL }}" + "/" + id_str + "/" + crop + "/" + width + "." + format;

                        imageData.push({
                            'div': div,
                            'img': picImg,
                            'url': url
                        });
                    }
                }
            }
        }
        // all DOM updates should probably go here
        for(var i = 0; i < imageData.length; i++) {
            var data = imageData[i];
            data.img.src = data.url;
            if (!data.img.parentNode) {
                data.div.appendChild(data.img);
            }
        }
    };

    function computeAspectRatio(_w, _h) {
        if (_w !== 0 && _h !== 0) {
            var aspectRatio = _w/_h;
            var ASPECT_RATIO_TOLERANCE = .1; // 10% tolerance.
            for (var i in RATIOS) {
              if (Math.abs(aspectRatio - RATIOS[i][1]) / RATIOS[i][1] < ASPECT_RATIO_TOLERANCE) {
                return RATIOS[i][0];
              }
            }
        }
        else {
            return "16x9"
        }
    }

    // Run on resize and domready (w.load as a fallback)
    if (!w.IMAGE_LISTENERS_DISABLED) {
        if( w.addEventListener ){
            var pictureFillTimeout;
            w.addEventListener( "resize",
                function() {
                    clearTimeout(pictureFillTimeout);
                    pictureFillTimeout = setTimeout(w.picturefill, 100);
                }, false );

            w.addEventListener( "DOMContentLoaded", function(){
                w.picturefill();
                // Run once only
                w.removeEventListener( "load", w.picturefill, false );
            }, false );
            w.addEventListener( "load", w.picturefill, false );

        }
        else if( w.attachEvent ){
            w.attachEvent( "onload", w.picturefill );
        }
    }
}( this ));<|endoftext|>


<commit_before>/*global */
/*jslint browser: true*/
var domready = require('domready');

var canny = (function () {
    "use strict";

    console.log('INITIALIZE CANNY MODULE');

    domready(function () {

        var gdModules = function () {
            var gdModuleChildren = [].slice.call(document.querySelectorAll('[canny-mod]'));

            gdModuleChildren.forEach(function (node) {
                var attribute = node.getAttribute('canny-mod'), attr, viewPart, attributes;

                attributes = attribute.split(' ');

                attributes.forEach(function (eachAttr) {
                    if (canny.hasOwnProperty(eachAttr)) {
                        if (node.getAttribute('canny-mod')) {
                            attr = node.getAttribute('canny-var').split("\'").join('\"');
                            if (/:/.test(attr)) {
                                // could be a JSON
                                viewPart = JSON.parse(attr);
                            } else {
                                viewPart = attr;
                            }
                        }
                        canny[eachAttr].add(node, viewPart);
                    }
                });
            });
        };

        gdModules();
        Object.keys(canny).forEach(function(module) {
            if (canny[module].hasOwnProperty('ready')) {
                canny[module].ready();
            }
        });
    });

    return {
        add : function (name, module) {
            if (!this.hasOwnProperty(name)) {
                this[name] = module;
            } else {
                console.error('canny: Try to register module with name ' + name + ' twice');
            }
        }
    };
}());

module.exports = canny;<commit_msg>make canny-var optional<commit_after>/*global */
/*jslint browser: true*/
var domready = require('domready');

var canny = (function () {
    "use strict";

    console.log('INITIALIZE CANNY MODULE');

    domready(function () {

        var gdModules = function () {
            var gdModuleChildren = [].slice.call(document.querySelectorAll('[canny-mod]'));

            gdModuleChildren.forEach(function (node) {
                var attribute = node.getAttribute('canny-mod'), attr, viewPart, attributes, cannyVar;

                attributes = attribute.split(' ');

                attributes.forEach(function (eachAttr) {
                    if (canny.hasOwnProperty(eachAttr)) {
                        if (node.getAttribute('canny-mod')) {
                            cannyVar = node.getAttribute('canny-var');
                            if (cannyVar) {
                                attr = cannyVar.split("\'").join('\"');
                                if (/:/.test(attr)) {
                                    // could be a JSON
                                    viewPart = JSON.parse(attr);
                                } else {
                                    viewPart = attr;
                                }
                            }
                        }
                        canny[eachAttr].add(node, viewPart);
                    }
                });
            });
        };

        gdModules();
        Object.keys(canny).forEach(function(module) {
            if (canny[module].hasOwnProperty('ready')) {
                canny[module].ready();
            }
        });
    });

    return {
        add : function (name, module) {
            if (!this.hasOwnProperty(name)) {
                this[name] = module;
            } else {
                console.error('canny: Try to register module with name ' + name + ' twice');
            }
        }
    };
}());

module.exports = canny;<|endoftext|>


<commit_before>/*
     Copyright 2015 Comcast Cable Communications Management, LLC

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

/* global _ */

/*
 * Scripted dashboard for traffic ops.
 *
 * Based on the grafana scripted.js script (which is ASF 2.0 licensed).
 */

// accessible variables in this scope
var window, document, ARGS, $, jQuery, moment, kbn;

// Setup some variables
var dashboard;

// All url parameters are available via the ARGS object
var ARGS;

// Intialize a skeleton with nothing but a rows array and service object
dashboard = {
  rows : [],
};

// Set default time
// time can be overriden in the url using from/to parameters, but this is
// handled automatically in grafana core during dashboard initialization
dashboard.time = {
  from: "now-6h",
  to: "now-60s"
};

var which = 'argName';

if(!_.isUndefined(ARGS.which)) {
  which = ARGS.which;
}

// Set a title
dashboard.title = which;
//set refresh interval
dashboard.refresh = "30s";

{
  dashboard.rows.push( {
      "height": "250px",
      "panels": [
        {
          "title": "total bandwidth (stacked)",
          "error": false,
          "span": 12,
          "editable": true,
          "type": "graph",
          "id": 1,
          "datasource": "cache_stats",
          "renderer": "flot",
          "x-axis": true,
          "y-axis": true,
          "y_formats": [
            "bps",
            "short"
          ],
          "grid": {
            "leftLogBase": 1,
            "leftMax": null,
            "rightMax": null,
            "leftMin": null,
            "rightMin": null,
            "rightLogBase": 1,
            "threshold1": null,
            "threshold2": null,
            "threshold1Color": "rgba(216, 200, 27, 0.27)",
            "threshold2Color": "rgba(234, 112, 112, 0.22)"
          },
          "lines": true,
          "fill": 1,
          "linewidth": 2,
          "points": false,
          "pointradius": 5,
          "bars": false,
          "stack": true,
          "percentage": false,
          "legend": {
            "show": true,
            "values": true,
            "min": false,
            "max": true,
            "current": true,
            "total": false,
            "avg": false
          },
          "nullPointMode": "connected",
          "steppedLine": false,
          "tooltip": {
            "value_type": "individual",
            "shared": true
          },
          "timeFrom": null,
          "timeShift": null,
          "targets": [
            {
              "rawQuery": true,
              "query": "SELECT sum(value)*1000 FROM \"monthly\".\"bandwidth.1min\" WHERE cachegroup='" + which + "' and $timeFilter GROUP BY time(60s), hostname",
              "alias": "$tag_hostname"
            }
          ],
          "aliasColors": {},
          "seriesOverrides": [],
          "links": []
        },
        {
          "title": "Connections (stacked)",
          "error": false,
          "span": 12,
          "editable": true,
          "type": "graph",
          "isNew": true,
          "id": 2,
          "targets": [
            {
              "refId": "A",
              "policy": "monthly",
              "dsType": "influxdb",
              "resultFormat": "time_series",
              "tags": [
                {
                  "key": "cachegroup",
                  "operator": "=",
                  "value": which
                }
              ],
              "groupBy": [
                {
                  "type": "time",
                  "params": [
                    "$interval"
                  ]
                },
                {
                  "type": "tag",
                  "params": [
                    "hostname"
                  ]
                },
                {
                  "type": "fill",
                  "params": [
                    "null"
                  ]
                }
              ],
              "select": [
                [
                  {
                    "type": "field",
                    "params": [
                      "value"
                    ]
                  },
                  {
                    "type": "mean",
                    "params": []
                  }
                ]
              ],
              "measurement": "connections.1min"
            }
          ],
          "datasource": "cache_stats",
          "renderer": "flot",
          "yaxes": [
            {
              "label": null,
              "show": true,
              "logBase": 1,
              "min": null,
              "max": null,
              "format": "short"
            },
            {
              "label": null,
              "show": true,
              "logBase": 1,
              "min": null,
              "max": null,
              "format": "short"
            }
          ],
          "xaxis": {
            "show": true
          },
          "grid": {
            "threshold1": null,
            "threshold2": null,
            "threshold1Color": "rgba(216, 200, 27, 0.27)",
            "threshold2Color": "rgba(234, 112, 112, 0.22)"
          },
          "lines": true,
          "fill": 1,
          "linewidth": 2,
          "points": false,
          "pointradius": 5,
          "bars": false,
          "stack": true,
          "percentage": false,
          "legend": {
            "show": true,
            "values": true,
            "min": false,
            "max": true,
            "current": true,
            "total": false,
            "avg": false,
            "hideEmpty": true,
            "hideZero": true
          },
          "nullPointMode": "connected",
          "steppedLine": false,
          "tooltip": {
            "value_type": "individual",
            "shared": true,
            "msResolution": true
          },
          "timeFrom": null,
          "timeShift": null,
          "aliasColors": {},
          "seriesOverrides": [],
          "links": []
        }
      ]
    }
  );
}
return dashboard;
<commit_msg>re-add tags that were accidentally deleted<commit_after>/*
     Copyright 2015 Comcast Cable Communications Management, LLC

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

/* global _ */

/*
 * Scripted dashboard for traffic ops.
 *
 * Based on the grafana scripted.js script (which is ASF 2.0 licensed).
 */

// accessible variables in this scope
var window, document, ARGS, $, jQuery, moment, kbn;

// Setup some variables
var dashboard;

// All url parameters are available via the ARGS object
var ARGS;

// Intialize a skeleton with nothing but a rows array and service object
dashboard = {
  rows : [],
};

// Set default time
// time can be overriden in the url using from/to parameters, but this is
// handled automatically in grafana core during dashboard initialization
dashboard.time = {
  from: "now-6h",
  to: "now-60s"
};

var which = 'argName';

if(!_.isUndefined(ARGS.which)) {
  which = ARGS.which;
}

// Set a title
dashboard.title = which;
//set refresh interval
dashboard.refresh = "30s";

{
  dashboard.rows.push( {
      "height": "250px",
      "panels": [
        {
          "title": "total bandwidth (stacked)",
          "error": false,
          "span": 12,
          "editable": true,
          "type": "graph",
          "id": 1,
          "datasource": "cache_stats",
          "renderer": "flot",
          "x-axis": true,
          "y-axis": true,
          "y_formats": [
            "bps",
            "short"
          ],
          "grid": {
            "leftLogBase": 1,
            "leftMax": null,
            "rightMax": null,
            "leftMin": null,
            "rightMin": null,
            "rightLogBase": 1,
            "threshold1": null,
            "threshold2": null,
            "threshold1Color": "rgba(216, 200, 27, 0.27)",
            "threshold2Color": "rgba(234, 112, 112, 0.22)"
          },
          "lines": true,
          "fill": 1,
          "linewidth": 2,
          "points": false,
          "pointradius": 5,
          "bars": false,
          "stack": true,
          "percentage": false,
          "legend": {
            "show": true,
            "values": true,
            "min": false,
            "max": true,
            "current": true,
            "total": false,
            "avg": false
          },
          "nullPointMode": "connected",
          "steppedLine": false,
          "tooltip": {
            "value_type": "individual",
            "shared": true
          },
          "timeFrom": null,
          "timeShift": null,
          "targets": [
            {
              "rawQuery": true,
              "query": "SELECT sum(value)*1000 FROM \"monthly\".\"bandwidth.1min\" WHERE cachegroup='" + which + "' and $timeFilter GROUP BY time(60s), hostname",
              "alias": "$tag_hostname"
            }
          ],
          "aliasColors": {},
          "seriesOverrides": [],
          "links": []
        },
        {
          "title": "Connections (stacked)",
          "error": false,
          "span": 12,
          "editable": true,
          "type": "graph",
          "isNew": true,
          "id": 2,
          "targets": [
            {
              "refId": "A",
              "policy": "monthly",
              "dsType": "influxdb",
              "resultFormat": "time_series",
              "tags": [
                {
                  "key": "cachegroup",
                  "operator": "=",
                  "value": which
                }
              ],
              "groupBy": [
                {
                  "type": "time",
                  "params": [
                    "$interval"
                  ]
                },
                {
                  "type": "tag",
                  "params": [
                    "hostname"
                  ]
                },
                {
                  "type": "fill",
                  "params": [
                    "null"
                  ]
                }
              ],
              "select": [
                [
                  {
                    "type": "field",
                    "params": [
                      "value"
                    ]
                  },
                  {
                    "type": "mean",
                    "params": []
                  }
                ]
              ],
              "measurement": "connections.1min"
            }
          ],
          "datasource": "cache_stats",
          "renderer": "flot",
          "yaxes": [
            {
              "label": null,
              "show": true,
              "logBase": 1,
              "min": null,
              "max": null,
              "format": "short"
            },
            {
              "label": null,
              "show": true,
              "logBase": 1,
              "min": null,
              "max": null,
              "format": "short"
            }
          ],
          "xaxis": {
            "show": true
          },
          "grid": {
            "threshold1": null,
            "threshold2": null,
            "threshold1Color": "rgba(216, 200, 27, 0.27)",
            "threshold2Color": "rgba(234, 112, 112, 0.22)"
          },
          "lines": true,
          "fill": 1,
          "linewidth": 2,
          "points": false,
          "pointradius": 5,
          "bars": false,
          "stack": true,
          "percentage": false,
          "legend": {
            "show": true,
            "values": true,
            "min": false,
            "max": true,
            "current": true,
            "total": false,
            "avg": false,
            "hideEmpty": true,
            "hideZero": true
          },
          "nullPointMode": "connected",
          "steppedLine": false,
          "tooltip": {
            "value_type": "individual",
            "shared": true,
            "msResolution": true
          },
          "timeFrom": null,
          "timeShift": null,
          "aliasColors": {},
          "seriesOverrides": [],
          "links": []
        }
      ],
      "title": "Row",
      "collapse": false,
      "editable": true
    }
  );
}
return dashboard;
<|endoftext|>


<commit_before>/* global Ember, hebeutils, _ */
import DatamillStory from './../../story-types/datamill-story/component';

export default DatamillStory.extend({
    tagName: 'div',
    loaded: false,
    ragRating: 'green', // red, amber or green
    ragValue: '4337',
    ragDesc1: 'Parking fines',
    ragDesc2: 'Issued this month',

    didInsertElement: function() {
        this.setRating();
    },

    setRating: function() {
        var obj = this;

        if (this.ragRating == 'green') {
            obj.set('ragRating', '-lime');
        } else if (this.ragRating == 'amber') {
            obj.set('ragRating', '-yellow');
        } else {
            obj.set('ragRating', '-red');
        }
    }
});
<commit_msg>Removed redundant logic from Base RAG Tile story.<commit_after>/* global Ember, hebeutils, _ */
import DatamillStory from './../../story-types/datamill-story/component';

export default DatamillStory.extend({
    tagName: 'div',
    loaded: false,
    ragRating: '-lime', // -lime (green), -yellow (amber), -red
    ragValue: '4337',
    ragDesc1: 'Parking fines',
    ragDesc2: 'Issued this month',

    didInsertElement: function() {

    }
});
<|endoftext|>


<commit_before>/**
 * Created by Christian James 22-07-2014
 * This code was inspired by Andrew Davey at http://aboutcode.net/2012/11/15/twitter-bootstrap-modals-and-knockoutjs.html
 *
 * Requirements:
 *  - Knockout
 *  - knockout-amd-helpers
 *  - requirejs
 *  - bootstrap
 *  - jquery
 */

define(["knockout", "jquery"],
    function (ko, $) {

        ko.utils.openModal = function (options) {
            if (typeof options === "undefined") throw new Error("An options argument is required.");
            if (typeof options.viewModel !== "object") throw new Error("options.viewModel is required.");

            var viewModel = options.viewModel;
            var template = options.template || viewModel.template;
            var context = options.context;

            if (!template) throw new Error("options.template or options.viewModel.template is required.");

            return createModalElement(template, viewModel)
                .pipe($) // jQueryify the DOM element
                .pipe(function ($ui) {
                    var deferredModalResult = $.Deferred();
                    showTwitterBootstrapModal($ui);
                    return deferredModalResult;
                });

            // Helper functions

            function createModalElement(templateName, viewModel) {
                var temporaryDiv = addHiddenDivToBody();
                var deferredElement = $.Deferred();
                ko.renderTemplate(
                    templateName,
                    viewModel,
                    // We need to know when the template has been rendered,
                    // so we can get the resulting DOM element.
                    // The resolve function receives the element.
                    {
                        afterRender: function (nodes) {
                            // Ignore any #text nodes before and after the modal element.
                            var elements = nodes.filter(function (node) {
                                return node.nodeType === 1; // Element
                            });
                            deferredElement.resolve(elements[0]);
                        }
                    },
                    // The temporary div will get replaced by the rendered template output.
                    temporaryDiv,
                    "replaceNode"
                );
                // Return the deferred DOM element so callers can wait until it's ready for use.
                return deferredElement;
            };

            function addHiddenDivToBody() {
                var div = document.createElement("div");
                div.style.display = "none";
                document.body.appendChild(div);
                return div;
            };

            function showTwitterBootstrapModal($ui) {

                // Display the modal UI using Twitter Bootstrap's modal plug-in.
                $ui.modal({
                    // Clicking the backdrop, or pressing Escape, shouldn't automatically close the modal by default.
                    // The view model should remain in control of when to close.
                    backdrop: "static",
                    keyboard: false
                });

                $ui.on("hidden.bs.modal", function (e) {
                    ko.cleanNode($ui[0]);
                    $ui.remove();
                });

            };
        };

    });

<commit_msg>- Added button options. - Added option for supplying model template and modal body/content in two seperate templates.<commit_after>/**
 * Created by Christian James 22-07-2014
 * This code was inspired by Andrew Davey at http://aboutcode.net/2012/11/15/twitter-bootstrap-modals-and-knockoutjs.html
 *
 * Requirements:
 *  - Knockout
 *  - knockout-amd-helpers
 *  - requirejs
 *  - bootstrap
 *  - jquery
 */

define(["knockout", "jquery"],
    function (ko, $) {

        ko.utils.showModal = function (options) {
            if (typeof options === "undefined") throw new Error("An options argument is required.");
            if (typeof options.viewModel !== "object") throw new Error("options.viewModel is required.");

            var viewModel = options.viewModel;
            var deferredModalResult = $.Deferred();
            var template;
            if (options.overrideBase) {
                template = options.template || viewModel.template;
            } else {
                template = "base-modal";
                viewModel.contentTemplate = function () {
                    return options.template;
                };
            }

            var modal_title = options.title || "Modal popup";

            var buttonsViewModel = options.buttons && options.buttons.length > 0 ? options.buttons : [];
            viewModel.modalOptions =
            {
                title: modal_title,
                buttons: buttonsViewModel,
                clickHandler: function (vm, event) {
                    if (event.target && event.target.tagName === "BUTTON") {
                        var targetViewModel = ko.dataFor(event.target);
                        deferredModalResult.resolve(targetViewModel, event.currentTarget);
                    }
                }
            };

            if (!template) throw new Error("options.template or options.viewModel.template is required.");

            return createModalElement(template, viewModel)
                .pipe($) // jQueryify the DOM element
                .pipe(function ($ui) {
                    showTwitterBootstrapModal($ui);
                    return deferredModalResult;
                });

            // Helper functions

            function createModalElement(templateName, viewModel) {
                var temporaryDiv = addHiddenDivToBody();
                var deferredElement = $.Deferred();
                ko.renderTemplate(
                    templateName,
                    viewModel,
                    // We need to know when the template has been rendered,
                    // so we can get the resulting DOM element.
                    // The resolve function receives the element.
                    {
                        afterRender: function (nodes) {
                            // Ignore any #text nodes before and after the modal element.
                            var elements = nodes.filter(function (node) {
                                return node.nodeType === 1; // Element
                            });
                            deferredElement.resolve(elements[0]);
                        }
                    },
                    // The temporary div will get replaced by the rendered template output.
                    temporaryDiv,
                    "replaceNode"
                );
                // Return the deferred DOM element so callers can wait until it's ready for use.
                return deferredElement;
            };

            function addHiddenDivToBody() {
                var div = document.createElement("div");
                div.style.display = "none";
                document.body.appendChild(div);
                return div;
            };

            function showTwitterBootstrapModal($ui) {

                // Display the modal UI using Twitter Bootstrap's modal plug-in.
                $ui.modal({
                    // Clicking the backdrop, or pressing Escape, shouldn't automatically close the modal by default.
                    // The view model should remain in control of when to close.
                    backdrop: "static",
                    keyboard: false
                });

                $ui.on("hidden.bs.modal", function (e) {

                    ko.cleanNode($ui[0]);
                    $ui.remove();
                    viewModel.modalOptions = null;
                });

            };
        };

    });

<|endoftext|>


<commit_before>import React from 'react';
import {render} from 'react-dom';
import InfiniteCalendar from '../../src';
import '../../styles.css';
import './demo.css';

render(<InfiniteCalendar />, document.querySelector('#demo'));
<commit_msg>Update demo<commit_after>import React from 'react';
import {render} from 'react-dom';
import InfiniteCalendar from '../../src';
import '../../styles.css';
import './demo.css';

render(
  <InfiniteCalendar
    width={Math.min(window.innerWidth, 400)}
  />
, document.querySelector('#demo'));
<|endoftext|>


<commit_before>// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

'use strict';

tvcm.require('tvcm.ui');
tvcm.require('tvcm.settings');

tvcm.exportTo('tvcm.ui', function() {

  function createSpan(opt_dictionary) {
    var spanEl = document.createElement('span');
    if (opt_dictionary) {
      if (opt_dictionary.className)
        spanEl.className = opt_dictionary.className;
      if (opt_dictionary.textContent)
        spanEl.textContent = opt_dictionary.textContent;
      if (opt_dictionary.parent)
        opt_dictionary.parent.appendChild(spanEl);
      if (opt_dictionary.bold)
        spanEl.style.fontWeight = 'bold';
    }
    return spanEl;
  };

  function createDiv(opt_dictionary) {
    var divEl = document.createElement('div');
    if (opt_dictionary) {
      if (opt_dictionary.className)
        divEl.className = opt_dictionary.className;
      if (opt_dictionary.parent)
        opt_dictionary.parent.appendChild(divEl);
    }
    return divEl;
  };

  function createScopedStyle(styleContent) {
    var styleEl = document.createElement('style');
    styleEl.scoped = true;
    styleEl.innerHTML = styleContent;
    return styleEl;
  }

  function createSelector(
      targetEl, targetElProperty,
      settingsKey, defaultValue,
      items) {
    var defaultValueIndex;
    for (var i = 0; i < items.length; i++) {
      var item = items[i];
      if (item.value == defaultValue) {
        defaultValueIndex = i;
        break;
      }
    }
    if (defaultValueIndex === undefined)
      throw new Error('defaultValue must be in the items list');

    var selectorEl = document.createElement('select');
    selectorEl.addEventListener('change', onChange);
    for (var i = 0; i < items.length; i++) {
      var item = items[i];
      var optionEl = document.createElement('option');
      optionEl.textContent = item.label;
      optionEl.targetPropertyValue = item.value;
      selectorEl.appendChild(optionEl);
    }
    function onChange(e) {
      var value = selectorEl.selectedOptions[0].targetPropertyValue;
      tvcm.Settings.set(settingsKey, value);
      targetEl[targetElProperty] = value;
    }
    var oldSetter = targetEl.__lookupSetter__('selectedIndex');
    selectorEl.__defineGetter__('selectedValue', function(v) {
      return selectorEl.children[selectorEl.selectedIndex].targetPropertyValue;
    });
    selectorEl.__defineSetter__('selectedValue', function(v) {
      for (var i = 0; i < selectorEl.children.length; i++) {
        var value = selectorEl.children[i].targetPropertyValue;
        if (value == v) {
          selectorEl.selectedIndex = i;
          onChange();
          return;
        }
      }
      throw new Error('Not a valid value');
    });

    var initialValue = tvcm.Settings.get(settingsKey, defaultValue);
    var didSet = false;
    for (var i = 0; i < selectorEl.children.length; i++) {
      if (selectorEl.children[i].targetPropertyValue == initialValue) {
        didSet = true;
        targetEl[targetElProperty] = initialValue;
        selectorEl.selectedIndex = i;
        break;
      }
    }
    if (!didSet) {
      selectorEl.selectedIndex = defaultValueIndex;
      targetEl[targetElProperty] = defaultValue;
    }

    return selectorEl;
  }

  var nextCheckboxId = 1;
  function createCheckBox(targetEl, targetElProperty,
                          settingsKey, defaultValue,
                          label) {
    var buttonEl = document.createElement('input');
    buttonEl.type = 'checkbox';

    var initialValue = tvcm.Settings.get(settingsKey, defaultValue);
    buttonEl.checked = !!initialValue;
    if (targetEl)
      targetEl[targetElProperty] = initialValue;

    function onChange() {
      tvcm.Settings.set(settingsKey, buttonEl.checked);
      if (targetEl)
        targetEl[targetElProperty] = buttonEl.checked;
    }

    buttonEl.addEventListener('change', onChange);

    var id = '#checkbox-' + nextCheckboxId++;

    var spanEl = createSpan({className: 'labeled-checkbox'});
    buttonEl.setAttribute('id', id);

    var labelEl = document.createElement('label');
    labelEl.textContent = label;
    labelEl.setAttribute('for', id);
    spanEl.appendChild(buttonEl);
    spanEl.appendChild(labelEl);

    spanEl.__defineSetter__('checked', function(opt_bool) {
      buttonEl.checked = !!opt_bool;
      onChange();
    });
    spanEl.__defineGetter__('checked', function() {
      return buttonEl.checked;
    });

    return spanEl;
  }

  function isElementAttachedToDocument(el) {
    var cur = el;
    while (cur.parentNode)
      cur = cur.parentNode;
    return cur == el.ownerDocument;
  }

  return {
    createSpan: createSpan,
    createDiv: createDiv,
    createScopedStyle: createScopedStyle,
    createSelector: createSelector,
    createCheckBox: createCheckBox,
    isElementAttachedToDocument: isElementAttachedToDocument
  };
});
<commit_msg>Don't call onChanged unless needed in checkbox/selector widgets<commit_after>// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

'use strict';

tvcm.require('tvcm.ui');
tvcm.require('tvcm.settings');

tvcm.exportTo('tvcm.ui', function() {

  function createSpan(opt_dictionary) {
    var spanEl = document.createElement('span');
    if (opt_dictionary) {
      if (opt_dictionary.className)
        spanEl.className = opt_dictionary.className;
      if (opt_dictionary.textContent)
        spanEl.textContent = opt_dictionary.textContent;
      if (opt_dictionary.parent)
        opt_dictionary.parent.appendChild(spanEl);
      if (opt_dictionary.bold)
        spanEl.style.fontWeight = 'bold';
    }
    return spanEl;
  };

  function createDiv(opt_dictionary) {
    var divEl = document.createElement('div');
    if (opt_dictionary) {
      if (opt_dictionary.className)
        divEl.className = opt_dictionary.className;
      if (opt_dictionary.parent)
        opt_dictionary.parent.appendChild(divEl);
    }
    return divEl;
  };

  function createScopedStyle(styleContent) {
    var styleEl = document.createElement('style');
    styleEl.scoped = true;
    styleEl.innerHTML = styleContent;
    return styleEl;
  }

  function createSelector(
      targetEl, targetElProperty,
      settingsKey, defaultValue,
      items) {
    var defaultValueIndex;
    for (var i = 0; i < items.length; i++) {
      var item = items[i];
      if (item.value == defaultValue) {
        defaultValueIndex = i;
        break;
      }
    }
    if (defaultValueIndex === undefined)
      throw new Error('defaultValue must be in the items list');

    var selectorEl = document.createElement('select');
    selectorEl.addEventListener('change', onChange);
    for (var i = 0; i < items.length; i++) {
      var item = items[i];
      var optionEl = document.createElement('option');
      optionEl.textContent = item.label;
      optionEl.targetPropertyValue = item.value;
      selectorEl.appendChild(optionEl);
    }
    function onChange(e) {
      var value = selectorEl.selectedOptions[0].targetPropertyValue;
      tvcm.Settings.set(settingsKey, value);
      targetEl[targetElProperty] = value;
    }
    var oldSetter = targetEl.__lookupSetter__('selectedIndex');
    selectorEl.__defineGetter__('selectedValue', function(v) {
      return selectorEl.children[selectorEl.selectedIndex].targetPropertyValue;
    });
    selectorEl.__defineSetter__('selectedValue', function(v) {
      for (var i = 0; i < selectorEl.children.length; i++) {
        var value = selectorEl.children[i].targetPropertyValue;
        if (value == v) {
          var changed = selectorEl.selectedIndex != i;
          if (changed) {
            selectorEl.selectedIndex = i;
            onChange();
          }
          return;
        }
      }
      throw new Error('Not a valid value');
    });

    var initialValue = tvcm.Settings.get(settingsKey, defaultValue);
    var didSet = false;
    for (var i = 0; i < selectorEl.children.length; i++) {
      if (selectorEl.children[i].targetPropertyValue == initialValue) {
        didSet = true;
        targetEl[targetElProperty] = initialValue;
        selectorEl.selectedIndex = i;
        break;
      }
    }
    if (!didSet) {
      selectorEl.selectedIndex = defaultValueIndex;
      targetEl[targetElProperty] = defaultValue;
    }

    return selectorEl;
  }

  var nextCheckboxId = 1;
  function createCheckBox(targetEl, targetElProperty,
                          settingsKey, defaultValue,
                          label) {
    var buttonEl = document.createElement('input');
    buttonEl.type = 'checkbox';

    var initialValue = tvcm.Settings.get(settingsKey, defaultValue);
    buttonEl.checked = !!initialValue;
    if (targetEl)
      targetEl[targetElProperty] = initialValue;

    function onChange() {
      tvcm.Settings.set(settingsKey, buttonEl.checked);
      if (targetEl)
        targetEl[targetElProperty] = buttonEl.checked;
    }

    buttonEl.addEventListener('change', onChange);

    var id = '#checkbox-' + nextCheckboxId++;

    var spanEl = createSpan({className: 'labeled-checkbox'});
    buttonEl.setAttribute('id', id);

    var labelEl = document.createElement('label');
    labelEl.textContent = label;
    labelEl.setAttribute('for', id);
    spanEl.appendChild(buttonEl);
    spanEl.appendChild(labelEl);

    spanEl.__defineSetter__('checked', function(opt_bool) {
      var changed = buttonEl.checked !== (!!opt_bool);
      if (!changed)
        return;

      buttonEl.checked = !!opt_bool;
      onChange();
    });
    spanEl.__defineGetter__('checked', function() {
      return buttonEl.checked;
    });

    return spanEl;
  }

  function isElementAttachedToDocument(el) {
    var cur = el;
    while (cur.parentNode)
      cur = cur.parentNode;
    return cur == el.ownerDocument;
  }

  return {
    createSpan: createSpan,
    createDiv: createDiv,
    createScopedStyle: createScopedStyle,
    createSelector: createSelector,
    createCheckBox: createCheckBox,
    isElementAttachedToDocument: isElementAttachedToDocument
  };
});
<|endoftext|>


<commit_before><commit_msg>Remove examples/usernotes/index.js shortcut file<commit_after><|endoftext|>


<commit_before>import { isObject } from '../../utils/isType';

// Attach handlers for changing the conditions of a question
export default function updateConditions(id) {
  const parent = $(`#${id}.question_container`);
  const content = parent.find('#content');
  content.html('');
  const addLogicButton = parent.find('a.add-logic[data-remote="true"]');

  // display conditions already saved
  if (addLogicButton.length > 0) {
    if (addLogicButton.attr('data-loaded').toString() === 'true') {
      addLogicButton.trigger('click');
    }
  }

  // set up selectpicker select boxes for condition options
  const setSelectPicker = () => {
    $('.selectpicker.narrow').selectpicker({ width: 120 });
    $('.selectpicker.regular').selectpicker({ width: 150 });
  };

  // test if a webhook is selected and set up if so
  const allowWebhook = (selectObject, webhook = false) => { // webhook false => new condition
    const condition = $(selectObject).closest('.condition-partial');
    if (webhook === false) {
      if ($(selectObject).val() === 'add_webhook') { // condition type is webhook
        condition.find('.pseudo-webhook-btn').trigger('click');
      } else { // condition type is remove
        condition.find('.remove-dropdown').show();
        condition.find('.webhook-replacement').hide();
      }
    } else { // loading already saved conditions
      // populate webhook inputs
      const nameString = condition.find('select.action-type').attr('name');
      const nameStart = nameString.substring(0, nameString.length - 13);
      const fields = ['name', 'email', 'subject', 'message'];
      fields.forEach((field, idx) => {
        let inputType = 'input';
        if (idx === 3) {
          inputType = 'textarea';
        }
        condition.find(`${inputType}[name="${nameStart}[webhook-${field}]"]`).val(JSON.parse(webhook)[`${field}`]);
      });
      $(selectObject).on('change', () => {
        allowWebhook(selectObject, undefined);
      });
    }
    // allow discarding of webhook data on click of exit symbol
    const exit = condition.find('.discard');
    exit.on('click', () => {
      exit.closest('.modal').find('.form-control').each((idx, field) => {
        $(field).val('');
      });
    });
    if ($(selectObject).val() === 'add_webhook') {
      // display edit email section
      condition.find('.remove-dropdown').hide();
      condition.find('.webhook-replacement').show();
      condition.find('.webhook-replacement').on('click', (event) => {
        event.preventDefault();
        condition.find('.pseudo-webhook-btn').trigger('click');
      });
    }
  };

  // setup when to test for a webhook selected
  const webhookSelected = (selectObject, webhook = false) => {
    if (webhook) { // current list of conditions
      allowWebhook(selectObject, webhook);
    } else { // new condition is added
      $(selectObject).on('change', () => {
        allowWebhook(selectObject, undefined);
      });
    }
  };

  // webhook form
  const webhookForm = (webhooks = false, selectObject = false) => {
    if (selectObject === false) {
      $('.selectpicker.action-type').each((idx, selectObject2) => {
        webhookSelected(selectObject2, webhooks[idx]);
      });
    } else {
      webhookSelected(selectObject, undefined);
    }
  };

  // display conditions (editing) upon click of 'Add Conditions'
  parent.on('ajax:success', 'a.add-logic[data-remote="true"]', (e) => {
    addLogicButton.attr('data-loaded', 'true');
    addLogicButton.addClass('disabled');
    addLogicButton.blur();
    addLogicButton.text('Conditions');
    if (isObject(content)) {
      content.html(e.detail[0].container);
    }
    setSelectPicker();
    webhookForm(data.webhooks, undefined);
  });

  // add condition
  parent.on('ajax:success', 'a.add-condition[data-remote="true"]', (e) => {
    const conditionList = $(e.target).closest('#condition-container').find('.condition-list');
    const addDiv = $(e.target).closest('#condition-container').find('.add-condition-div');
    if (isObject(conditionList)) {
      conditionList.attr('data-loaded', 'true');
      conditionList.append(e.detail[0].attachment_partial);
      addDiv.html(e.detail[0].add_link);
      conditionList.attr('data-loaded', 'false');
      setSelectPicker();
      const selectObject = conditionList.find('.selectpicker.action-type').last();
      webhookForm(undefined, selectObject);
    }
  });

  // remove condition
  parent.on('click', '.delete-condition', (e) => {
    e.preventDefault();
    const source = $(e.target).closest('.condition-partial');
    source.empty();
  });
}
<commit_msg>fix asset compilation issue due to dangling reference<commit_after>import { isObject } from '../../utils/isType';

// Attach handlers for changing the conditions of a question
export default function updateConditions(id) {
  const parent = $(`#${id}.question_container`);
  const content = parent.find('#content');
  content.html('');
  const addLogicButton = parent.find('a.add-logic[data-remote="true"]');

  // display conditions already saved
  if (addLogicButton.length > 0) {
    if (addLogicButton.attr('data-loaded').toString() === 'true') {
      addLogicButton.trigger('click');
    }
  }

  // set up selectpicker select boxes for condition options
  const setSelectPicker = () => {
    $('.selectpicker.narrow').selectpicker({ width: 120 });
    $('.selectpicker.regular').selectpicker({ width: 150 });
  };

  // test if a webhook is selected and set up if so
  const allowWebhook = (selectObject, webhook = false) => { // webhook false => new condition
    const condition = $(selectObject).closest('.condition-partial');
    if (webhook === false) {
      if ($(selectObject).val() === 'add_webhook') { // condition type is webhook
        condition.find('.pseudo-webhook-btn').trigger('click');
      } else { // condition type is remove
        condition.find('.remove-dropdown').show();
        condition.find('.webhook-replacement').hide();
      }
    } else { // loading already saved conditions
      // populate webhook inputs
      const nameString = condition.find('select.action-type').attr('name');
      const nameStart = nameString.substring(0, nameString.length - 13);
      const fields = ['name', 'email', 'subject', 'message'];
      fields.forEach((field, idx) => {
        let inputType = 'input';
        if (idx === 3) {
          inputType = 'textarea';
        }
        condition.find(`${inputType}[name="${nameStart}[webhook-${field}]"]`).val(JSON.parse(webhook)[`${field}`]);
      });
      $(selectObject).on('change', () => {
        allowWebhook(selectObject, undefined);
      });
    }
    // allow discarding of webhook data on click of exit symbol
    const exit = condition.find('.discard');
    exit.on('click', () => {
      exit.closest('.modal').find('.form-control').each((idx, field) => {
        $(field).val('');
      });
    });
    if ($(selectObject).val() === 'add_webhook') {
      // display edit email section
      condition.find('.remove-dropdown').hide();
      condition.find('.webhook-replacement').show();
      condition.find('.webhook-replacement').on('click', (event) => {
        event.preventDefault();
        condition.find('.pseudo-webhook-btn').trigger('click');
      });
    }
  };

  // setup when to test for a webhook selected
  const webhookSelected = (selectObject, webhook = false) => {
    if (webhook) { // current list of conditions
      allowWebhook(selectObject, webhook);
    } else { // new condition is added
      $(selectObject).on('change', () => {
        allowWebhook(selectObject, undefined);
      });
    }
  };

  // webhook form
  const webhookForm = (webhooks = false, selectObject = false) => {
    if (selectObject === false) {
      $('.selectpicker.action-type').each((idx, selectObject2) => {
        webhookSelected(selectObject2, webhooks[idx]);
      });
    } else {
      webhookSelected(selectObject, undefined);
    }
  };

  // display conditions (editing) upon click of 'Add Conditions'
  parent.on('ajax:success', 'a.add-logic[data-remote="true"]', (e) => {
    addLogicButton.attr('data-loaded', 'true');
    addLogicButton.addClass('disabled');
    addLogicButton.blur();
    addLogicButton.text('Conditions');
    if (isObject(content)) {
      content.html(e.detail[0].container);
    }
    setSelectPicker();
    webhookForm(e.detail[0].webhooks, undefined);
  });

  // add condition
  parent.on('ajax:success', 'a.add-condition[data-remote="true"]', (e) => {
    const conditionList = $(e.target).closest('#condition-container').find('.condition-list');
    const addDiv = $(e.target).closest('#condition-container').find('.add-condition-div');
    if (isObject(conditionList)) {
      conditionList.attr('data-loaded', 'true');
      conditionList.append(e.detail[0].attachment_partial);
      addDiv.html(e.detail[0].add_link);
      conditionList.attr('data-loaded', 'false');
      setSelectPicker();
      const selectObject = conditionList.find('.selectpicker.action-type').last();
      webhookForm(undefined, selectObject);
    }
  });

  // remove condition
  parent.on('click', '.delete-condition', (e) => {
    e.preventDefault();
    const source = $(e.target).closest('.condition-partial');
    source.empty();
  });
}
<|endoftext|>