Skip to content

Instantly share code, notes, and snippets.

@seanhess
Last active August 29, 2015 14:03
Show Gist options
  • Save seanhess/9e5998bed279f237480e to your computer and use it in GitHub Desktop.
Save seanhess/9e5998bed279f237480e to your computer and use it in GitHub Desktop.
import _ = require('lodash')
export interface ModalConfig {
modalUrl:string;
state:string;
}
export interface Modal {
modalUrl: string;
state: string;
}
export class ModalsProvider {
private $location:ng.ILocationService;
private $state:ng.ui.IStateService;
private modals:Modals;
constructor(
private $urlRouterProvider:ng.ui.IUrlRouterProvider
){
this.modals = new Modals()
}
// injected
$get($location, $state) {
this.modals.$location = $location
this.modals.$state = $state
return this.modals
}
// url needs to be a URL type,
modal(config:ModalConfig):Modal {
var modal:Modal = {
state: config.state,
modalUrl: config.modalUrl,
}
this.$urlRouterProvider.when(config.modalUrl, ($state, $location) => {
this.modals.handleUrl(modal, $state, $location)
})
this.modals.add(modal)
return modal
}
}
export class Modals {
public current:Modal;
public parentUrl:string;
private modals:Modal[];
// injected manually after constructor
public $location:ng.ILocationService;
public $state:ng.ui.IStateService;
constructor() {
this.modals = []
}
get(state:string):Modal {
return _.find(this.modals, (m:Modal) => m.state == state)
}
open(state:string, search:Object) {
this.parentUrl = this.$location.url()
this.current = this.get(state)
if (!this.current) {
throw new Error("Could not find modal: " + state)
}
this.$location.url(this.current.modalUrl).search(search).replace()
}
close(changeUrl?:boolean) {
// Pass 'true' to also change url. Leave blank or pass 'false' to close without changing url
if (changeUrl) this.closeUrl()
this.parentUrl = null
this.current = null
}
closeUrl() {
if (this.parentUrl) {
this.$location.url(this.parentUrl).replace()
}
else {
this.$state.go('home')
}
}
get isOpen() {
return !!this.current
}
add(modal:Modal) {
this.modals.push(modal)
}
handleUrl(modal:Modal, $state:ng.ui.IStateService, $location:ng.ILocationService) {
// TODO: would be better if this didn't always require search, but could work with paths
if (this.parentUrl) return null // because it is already open
$state.go(modal.state, $location.search())
}
}
export interface PageStackSettings {
url:string;
templateUrl?:string;
controller?:Function;
controllerAs?:string;
abstract?:boolean;
reloadOnSearch?:boolean;
}
var PAGE_STACK_PREFIX = "stack-"
var PAGE_STACK_REGEX = /\.stack.*$/
var PAGE_STACK_EMPTY = "empty"
export class PageStackProvider {
constructor(
private $urlRouterProvider,
private $stateProvider
) {}
stack(stateName:string, baseStates:string[], settings:PageStackSettings) {
// Add one url handler for the whole stacked state
// This gets called whenever the url is hit
// and we always use the url to get here
this.$urlRouterProvider.when(settings.url, function($match, $state) {
var nextState = stateName
var base = PAGE_STACK_EMPTY
if ($state.current.name) {
base = $state.current.name.split('.')[0]
if (baseStates.filter((name) => name == base).length == 0)
base = "empty"
}
nextState = base+".stack-" + stateName
$state.go(nextState, _.clone($match))
return true
})
// Add a state for each of the bases, in order
baseStates.forEach((baseState:string) => {
var localSettings:PageStackSettings = {
url: "^"+settings.url,
templateUrl: settings.templateUrl,
}
if (settings.controller) localSettings.controller = settings.controller
if (settings.controllerAs) localSettings.controllerAs = settings.controllerAs
if ('abstract' in settings) localSettings.abstract = settings.abstract
if ('reloadOnSearch' in settings) localSettings.reloadOnSearch = settings.reloadOnSearch
var fullStateName = baseState+"."+PAGE_STACK_PREFIX+stateName
// console.log("ADDING STATE", fullStateName, localSettings)
this.$stateProvider.state(fullStateName, localSettings)
})
return this
}
$get($state) {
return new PageStack($state)
}
}
export class PageStack {
constructor(private $state) {}
hide() {
console.log("HIDE")
var name = this.$state.current.name
var baseState = name.replace(PAGE_STACK_REGEX, "")
this.$state.go(baseState)
}
isShown() {
return this.isOverGallery() && !!this.$state.current.name.match(PAGE_STACK_REGEX)
}
isOverGallery() {
return !this.$state.current.name.match(PAGE_STACK_EMPTY)
}
}
import pageStackService = require('./PageStackService')
import modalUrlProvider = require('./ModalUrlProvider')
export var module = angular.module('app.services', ['ui.router'])
.provider("$stack", pageStackService.PageStackProvider)
.provider('Modals', modalUrlProvider.ModalsProvider)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment