This repository has been archived by the owner on Sep 20, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 210
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
4dedab2
commit b6db4cf
Showing
20 changed files
with
3,304 additions
and
610 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
(function(angular, undefined){ | ||
"use strict"; | ||
var mod_core = angular.module("ct.ui.router.extras.core", [ "ui.router" ]); | ||
|
||
var internalStates = {}, stateRegisteredCallbacks = []; | ||
mod_core.config([ '$stateProvider', '$injector', function ($stateProvider, $injector) { | ||
// Decorate any state attribute in order to get access to the internal state representation. | ||
$stateProvider.decorator('parent', function (state, parentFn) { | ||
// Capture each internal UI-Router state representations as opposed to the user-defined state object. | ||
// The internal state is, e.g., the state returned by $state.$current as opposed to $state.current | ||
internalStates[state.self.name] = state; | ||
// Add an accessor for the internal state from the user defined state | ||
state.self.$$state = function () { | ||
return internalStates[state.self.name]; | ||
}; | ||
|
||
angular.forEach(stateRegisteredCallbacks, function(callback) { callback(state); }); | ||
return parentFn(state); | ||
}); | ||
}]); | ||
|
||
var DEBUG = false; | ||
|
||
var forEach = angular.forEach; | ||
var extend = angular.extend; | ||
var isArray = angular.isArray; | ||
|
||
var map = function (collection, callback) { | ||
"use strict"; | ||
var result = []; | ||
forEach(collection, function (item, index) { | ||
result.push(callback(item, index)); | ||
}); | ||
return result; | ||
}; | ||
|
||
var keys = function (collection) { | ||
"use strict"; | ||
return map(collection, function (collection, key) { | ||
return key; | ||
}); | ||
}; | ||
|
||
var filter = function (collection, callback) { | ||
"use strict"; | ||
var result = []; | ||
forEach(collection, function (item, index) { | ||
if (callback(item, index)) { | ||
result.push(item); | ||
} | ||
}); | ||
return result; | ||
}; | ||
|
||
var filterObj = function (collection, callback) { | ||
"use strict"; | ||
var result = {}; | ||
forEach(collection, function (item, index) { | ||
if (callback(item, index)) { | ||
result[index] = item; | ||
} | ||
}); | ||
return result; | ||
}; | ||
|
||
// Duplicates code in UI-Router common.js | ||
function ancestors(first, second) { | ||
var path = []; | ||
|
||
for (var n in first.path) { | ||
if (first.path[n] !== second.path[n]) break; | ||
path.push(first.path[n]); | ||
} | ||
return path; | ||
} | ||
|
||
// Duplicates code in UI-Router common.js | ||
function objectKeys(object) { | ||
if (Object.keys) { | ||
return Object.keys(object); | ||
} | ||
var result = []; | ||
|
||
angular.forEach(object, function (val, key) { | ||
result.push(key); | ||
}); | ||
return result; | ||
} | ||
|
||
/** | ||
* like objectKeys, but includes keys from prototype chain. | ||
* @param object the object whose prototypal keys will be returned | ||
* @param ignoreKeys an array of keys to ignore | ||
*/ | ||
// Duplicates code in UI-Router common.js | ||
function protoKeys(object, ignoreKeys) { | ||
var result = []; | ||
for (var key in object) { | ||
if (!ignoreKeys || ignoreKeys.indexOf(key) === -1) | ||
result.push(key); | ||
} | ||
return result; | ||
} | ||
|
||
// Duplicates code in UI-Router common.js | ||
function arraySearch(array, value) { | ||
if (Array.prototype.indexOf) { | ||
return array.indexOf(value, Number(arguments[2]) || 0); | ||
} | ||
var len = array.length >>> 0, from = Number(arguments[2]) || 0; | ||
from = (from < 0) ? Math.ceil(from) : Math.floor(from); | ||
|
||
if (from < 0) from += len; | ||
|
||
for (; from < len; from++) { | ||
if (from in array && array[from] === value) return from; | ||
} | ||
return -1; | ||
} | ||
|
||
// Duplicates code in UI-Router common.js | ||
// Added compatibility code (isArray check) to support both 0.2.x and 0.3.x series of UI-Router. | ||
function inheritParams(currentParams, newParams, $current, $to) { | ||
var parents = ancestors($current, $to), parentParams, inherited = {}, inheritList = []; | ||
|
||
for (var i in parents) { | ||
if (!parents[i].params) continue; | ||
// This test allows compatibility with 0.2.x and 0.3.x (optional and object params) | ||
parentParams = isArray(parents[i].params) ? parents[i].params : objectKeys(parents[i].params); | ||
if (!parentParams.length) continue; | ||
|
||
for (var j in parentParams) { | ||
if (arraySearch(inheritList, parentParams[j]) >= 0) continue; | ||
inheritList.push(parentParams[j]); | ||
inherited[parentParams[j]] = currentParams[parentParams[j]]; | ||
} | ||
} | ||
return extend({}, inherited, newParams); | ||
} | ||
|
||
function inherit(parent, extra) { | ||
return extend(new (extend(function () { }, {prototype: parent}))(), extra); | ||
} | ||
|
||
function onStateRegistered(callback) { stateRegisteredCallbacks.push(callback); } | ||
|
||
mod_core.provider("uirextras_core", function() { | ||
var core = { | ||
internalStates: internalStates, | ||
onStateRegistered: onStateRegistered, | ||
forEach: forEach, | ||
extend: extend, | ||
isArray: isArray, | ||
map: map, | ||
keys: keys, | ||
filter: filter, | ||
filterObj: filterObj, | ||
ancestors: ancestors, | ||
objectKeys: objectKeys, | ||
protoKeys: protoKeys, | ||
arraySearch: arraySearch, | ||
inheritParams: inheritParams, | ||
inherit: inherit | ||
}; | ||
|
||
angular.extend(this, core); | ||
|
||
this.$get = function() { | ||
return core; | ||
}; | ||
}); | ||
|
||
|
||
})(angular); |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
(function(angular, undefined){ | ||
"use strict"; | ||
var ignoreDsr; | ||
function resetIgnoreDsr() { | ||
ignoreDsr = undefined; | ||
} | ||
|
||
// Decorate $state.transitionTo to gain access to the last transition.options variable. | ||
// This is used to process the options.ignoreDsr option | ||
angular.module('ct.ui.router.extras.dsr', [ 'ct.ui.router.extras.core' ]).config([ "$provide", function ($provide) { | ||
var $state_transitionTo; | ||
$provide.decorator("$state", ['$delegate', '$q', function ($state, $q) { | ||
$state_transitionTo = $state.transitionTo; | ||
$state.transitionTo = function (to, toParams, options) { | ||
if (options.ignoreDsr) { | ||
ignoreDsr = options.ignoreDsr; | ||
} | ||
|
||
return $state_transitionTo.apply($state, arguments).then( | ||
function (result) { | ||
resetIgnoreDsr(); | ||
return result; | ||
}, | ||
function (err) { | ||
resetIgnoreDsr(); | ||
return $q.reject(err); | ||
} | ||
); | ||
}; | ||
return $state; | ||
}]); | ||
}]); | ||
|
||
angular.module('ct.ui.router.extras.dsr').service("$deepStateRedirect", [ '$rootScope', '$state', '$injector', function ($rootScope, $state, $injector) { | ||
var lastSubstate = {}; | ||
var deepStateRedirectsByName = {}; | ||
|
||
var REDIRECT = "Redirect", ANCESTOR_REDIRECT = "AncestorRedirect"; | ||
|
||
function computeDeepStateStatus(state) { | ||
var name = state.name; | ||
if (deepStateRedirectsByName.hasOwnProperty(name)) | ||
return deepStateRedirectsByName[name]; | ||
recordDeepStateRedirectStatus(name); | ||
} | ||
|
||
function getConfig(state) { | ||
var declaration = state.deepStateRedirect || state.dsr; | ||
if (!declaration) return { dsr: false }; | ||
var dsrCfg = { dsr: true }; | ||
|
||
if (angular.isFunction(declaration)) { | ||
dsrCfg.fn = declaration; | ||
} else if (angular.isObject(declaration)) { | ||
dsrCfg = angular.extend(dsrCfg, declaration); | ||
} | ||
|
||
if (angular.isString(dsrCfg.default)) { | ||
dsrCfg.default = { state: dsrCfg.default }; | ||
} | ||
|
||
if (!dsrCfg.fn) { | ||
dsrCfg.fn = [ '$dsr$', function($dsr$) { | ||
return $dsr$.redirect.state != $dsr$.to.state; | ||
} ]; | ||
} | ||
return dsrCfg; | ||
} | ||
|
||
function recordDeepStateRedirectStatus(stateName) { | ||
var state = $state.get(stateName); | ||
if (!state) return false; | ||
var cfg = getConfig(state); | ||
if (cfg.dsr) { | ||
deepStateRedirectsByName[state.name] = REDIRECT; | ||
if (lastSubstate[stateName] === undefined) | ||
lastSubstate[stateName] = {}; | ||
} | ||
|
||
var parent = state.$$state && state.$$state().parent; | ||
if (parent) { | ||
var parentStatus = recordDeepStateRedirectStatus(parent.self.name); | ||
if (parentStatus && deepStateRedirectsByName[state.name] === undefined) { | ||
deepStateRedirectsByName[state.name] = ANCESTOR_REDIRECT; | ||
} | ||
} | ||
return deepStateRedirectsByName[state.name] || false; | ||
} | ||
|
||
function getMatchParams(params, dsrParams) { | ||
if (dsrParams === true) dsrParams = Object.keys(params); | ||
if (dsrParams === null || dsrParams === undefined) dsrParams = []; | ||
|
||
var matchParams = {}; | ||
angular.forEach(dsrParams.sort(), function(name) { matchParams[name] = params[name]; }); | ||
return matchParams; | ||
} | ||
|
||
function getParamsString(params, dsrParams) { | ||
var matchParams = getMatchParams(params, dsrParams); | ||
function safeString(input) { return !input ? input : input.toString(); } | ||
var paramsToString = {}; | ||
angular.forEach(matchParams, function(val, name) { paramsToString[name] = safeString(val); }); | ||
return angular.toJson(paramsToString); | ||
} | ||
|
||
$rootScope.$on("$stateChangeStart", function (event, toState, toParams, fromState, fromParams) { | ||
var cfg = getConfig(toState); | ||
if (ignoreDsr || (computeDeepStateStatus(toState) !== REDIRECT) && !cfg.default) return; | ||
// We're changing directly to one of the redirect (tab) states. | ||
// Get the DSR key for this state by calculating the DSRParams option | ||
var key = getParamsString(toParams, cfg.params); | ||
var redirect = lastSubstate[toState.name][key] || cfg.default; | ||
if (!redirect) return; | ||
|
||
// we have a last substate recorded | ||
var $dsr$ = { redirect: { state: redirect.state, params: redirect.params}, to: { state: toState.name, params: toParams } }; | ||
var result = $injector.invoke(cfg.fn, toState, { $dsr$: $dsr$ }); | ||
if (!result) return; | ||
if (result.state) redirect = result; | ||
event.preventDefault(); | ||
var redirectParams = getMatchParams(toParams, cfg.params); | ||
$state.go(redirect.state, angular.extend(redirectParams, redirect.params)); | ||
}); | ||
|
||
$rootScope.$on("$stateChangeSuccess", function (event, toState, toParams, fromState, fromParams) { | ||
var deepStateStatus = computeDeepStateStatus(toState); | ||
if (deepStateStatus) { | ||
var name = toState.name; | ||
angular.forEach(lastSubstate, function (redirect, dsrState) { | ||
// update Last-SubState¶ms for each DSR that this transition matches. | ||
var cfg = getConfig($state.get(dsrState)); | ||
var key = getParamsString(toParams, cfg.params); | ||
if (name == dsrState || name.indexOf(dsrState + ".") != -1) { | ||
lastSubstate[dsrState][key] = { state: name, params: angular.copy(toParams) }; | ||
} | ||
}); | ||
} | ||
}); | ||
|
||
return { | ||
reset: function(stateOrName, params) { | ||
if (!stateOrName) { | ||
angular.forEach(lastSubstate, function(redirect, dsrState) { lastSubstate[dsrState] = {}; }); | ||
} else { | ||
var state = $state.get(stateOrName); | ||
if (!state) throw new Error("Unknown state: " + stateOrName); | ||
if (lastSubstate[state.name]) { | ||
if (params) { | ||
var key = getParamsString(params, getConfig(state).params); | ||
delete lastSubstate[state.name][key]; | ||
} else { | ||
lastSubstate[state.name] = {}; | ||
} | ||
} | ||
} | ||
} | ||
}; | ||
}]); | ||
|
||
angular.module('ct.ui.router.extras.dsr').run(['$deepStateRedirect', function ($deepStateRedirect) { | ||
// Make sure $deepStateRedirect is instantiated | ||
}]); | ||
|
||
})(angular); |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Oops, something went wrong.