<commit_before>var merge = require('lodash/object/merge');
var extend = require('lodash/object/extend');
var webpack = require('webpack');
var WebpackDevServer = require('webpack-dev-server');
var open = require('gulp-open');
var path = require('path');
var runSequence = require('run-sequence');

module.exports = function(gulp, options, webpackConfig, dist) {

  gulp.task('dev-preprocess', function(callback) {
    if (options.devPreprocess) {
      runSequence('preprocess', options.devPreprocess, callback);
    } else {
      runSequence('preprocess', callback);
    }
  });

  gulp.task('dev', ['dev-preprocess'], function() {

    var env = merge({}, options.env, {
      __DEV_MODE__: true
    });

    var devWebpackConfig = extend({}, webpackConfig, options.webpack || {}, {
      entry: {
        app: ['webpack/hot/dev-server', './' + options.mainJs]
      },

      output: {
        filename: 'index.js',
        path: dist,
        publicPath: '/'
      },

      devtool: 'inline-source-map',

      plugins: [
        new webpack.HotModuleReplacementPlugin(),
        new webpack.DefinePlugin(env)
      ]

    });

    if (!devWebpackConfig.resolve) {
      devWebpackConfig.resolve = {};
    }

    if (options.webpack.module && options.webpack.module.loaders) {
      webpackConfig.module.loaders.forEach(function(loader) {
        devWebpackConfig.module.loaders.push(loader);
      });
    }

    if (options.webpack.plugins) {
      options.webpack.plugins.forEach(function(plugin) {
        devWebpackConfig.plugins.push(plugin);
      });
    }

    devWebpackConfig.resolve.extensions = merge(devWebpackConfig.resolve.extensions || [],
      ['', '.js', '.json', '.htm', '.html', '.scss', '.md']);

    var devServerConfig = {
      contentBase: dist,
      hot: true,
      inline: true,
      stats: {
        colors: true
      },
      publicPath: devWebpackConfig.output.publicPath,
      historyApiFallback: true
    };

    if (options.watchOptions) {
      devServerConfig.watchOptions = options.watchOptions;
    }

    if (options.devServerProxy) {
      devServerConfig.proxy = options.devServerProxy;
    }

    var server = new WebpackDevServer(webpack(devWebpackConfig), devServerConfig);
    server.use('/', function(req, res, next) {

      var acceptLanguageHeader = req.headers['accept-language'];

      if (acceptLanguageHeader) {
        var acceptedLanguages = acceptLanguageHeader.match(/[a-zA-z\-]{2,10}/g);
        if (acceptedLanguages) {
          res.cookie('languages', JSON.stringify(acceptedLanguages));
        }
      }

      if (req.url.match(/.+index.js$/)) {
        res.redirect(301, '/index.js');
      } else if (req.url.match(/.+\/img\//)) { // img
        res.redirect(301, req.url.replace(/.*\/(img\/.*)$/, '/$1'));
      } else if (req.url.match(/\/img\//)) { // img
        next();
      } else if (req.url.match(/.+\/font\//)) { // font
        res.redirect(301, req.url.replace(/.*\/(font\/.*)$/, '/$1'));
      } else if (req.url.match(/\/font\//)) { // font
        next();
      } else if (req.url.match(/.+\/.*\.[^\/]*$/)) { // file
        res.redirect(301, req.url.replace(/.*\/([^\/]*)$/, '/$1'));
      } else {
        next();
      }
    });

    // Always open on all ports unless overridden
    var host = options.devServerHost || '0.0.0.0';

    server.listen(options.devServerPort || 8080, host, function(err) {
      if (err) {
        console.error('[webpack-dev-server] failed to start:', err);
      } else {
        var openHost = (host === '0.0.0.0') ? 'localhost' : host;
        console.log('[webpack-dev-server] started: opening the app in your default browser...');
        gulp.src(path.join(dist, 'index.html'))
        .pipe(open({
          uri: 'http://' + openHost + ':' + options.devServerPort + '/webpack-dev-server/'
        }));
      }
    });

  });
};
<commit_msg>Allowing custom filename for webpack bundles.<commit_after>var merge = require('lodash/object/merge');
var webpack = require('webpack');
var WebpackDevServer = require('webpack-dev-server');
var open = require('gulp-open');
var path = require('path');
var runSequence = require('run-sequence');

module.exports = function(gulp, options, webpackConfig, dist) {

  gulp.task('dev-preprocess', function(callback) {
    if (options.devPreprocess) {
      runSequence('preprocess', options.devPreprocess, callback);
    } else {
      runSequence('preprocess', callback);
    }
  });

  gulp.task('dev', ['dev-preprocess'], function() {

    var env = merge({}, options.env, {
      __DEV_MODE__: true
    });

    var devWebpackConfig = merge({}, webpackConfig, {
      entry: {
        app: ['webpack/hot/dev-server', './' + options.mainJs]
      },

      output: {
        filename: 'index.js',
        path: dist,
        publicPath: '/'
      },

      devtool: 'inline-source-map'

    }, options.webpack || {});

    if (!devWebpackConfig.resolve) {
      devWebpackConfig.resolve = {};
    }

    devWebpackConfig.module.loaders = webpackConfig.module.loaders;
    if (options.webpack.module && options.webpack.module.loaders) {
      options.webpack.module.loaders.forEach(function(loader) {
        devWebpackConfig.module.loaders.push(loader);
      });
    }

    devWebpackConfig.plugins = [
      new webpack.HotModuleReplacementPlugin(),
      new webpack.DefinePlugin(env)
    ];

    if (options.webpack.plugins) {
      options.webpack.plugins.forEach(function(plugin) {
        devWebpackConfig.plugins.push(plugin);
      });
    }

    devWebpackConfig.resolve.extensions = merge(devWebpackConfig.resolve.extensions || [],
      ['', '.js', '.json', '.htm', '.html', '.scss', '.md']);

    var devServerConfig = {
      contentBase: dist,
      hot: true,
      inline: true,
      stats: {
        colors: true
      },
      publicPath: devWebpackConfig.output.publicPath,
      historyApiFallback: true
    };

    if (options.watchOptions) {
      devServerConfig.watchOptions = options.watchOptions;
    }

    if (options.devServerProxy) {
      devServerConfig.proxy = options.devServerProxy;
    }

    var server = new WebpackDevServer(webpack(devWebpackConfig), devServerConfig);
    server.use('/', function(req, res, next) {

      var acceptLanguageHeader = req.headers['accept-language'];

      if (acceptLanguageHeader) {
        var acceptedLanguages = acceptLanguageHeader.match(/[a-zA-z\-]{2,10}/g);
        if (acceptedLanguages) {
          res.cookie('languages', JSON.stringify(acceptedLanguages));
        }
      }

      if (req.url.match(/.+\/img\//)) { // img
        res.redirect(301, req.url.replace(/.*\/(img\/.*)$/, '/$1'));
      } else if (req.url.match(/\/img\//)) { // img
        next();
      } else if (req.url.match(/.+\/font\//)) { // font
        res.redirect(301, req.url.replace(/.*\/(font\/.*)$/, '/$1'));
      } else if (req.url.match(/\/font\//)) { // font
        next();
      } else if (req.url.match(/.+\/.*\.[^\/]*$/)) { // file
        res.redirect(301, req.url.replace(/.*\/([^\/]*)$/, '/$1'));
      } else {
        next();
      }
    });

    // Always open on all ports unless overridden
    var host = options.devServerHost || '0.0.0.0';

    server.listen(options.devServerPort || 8080, host, function(err) {
      if (err) {
        console.error('[webpack-dev-server] failed to start:', err);
      } else {
        var openHost = (host === '0.0.0.0') ? 'localhost' : host;
        console.log('[webpack-dev-server] started: opening the app in your default browser...');
        gulp.src(path.join(dist, 'index.html'))
        .pipe(open({
          uri: 'http://' + openHost + ':' + options.devServerPort + '/webpack-dev-server/'
        }));
      }
    });

  });
};
<|endoftext|>


<commit_before>import Modal from 'v2/components/UI/Modal'
import ModalFullscreenDialog from 'v2/components/UI/ModalFullscreenDialog'
import { ModalFullBlock } from 'v2/components/ModalFullBlock'

export default ({ id, context }) => {
  // Filter out Channels, Groups, Users and duplicates; return just IDs
  const set =
    new Set() <
    string >
    context
      .filter(
        k =>
          k?.__typename !== 'Channel' &&
          k?.__typename !== 'Group' &&
          k?.__typename !== 'User' &&
          !!k?.id
      )
      .map(k => k.id.toString())

  const ids = Array.from(set)

  const currentTitle = document.title
  const onClose = () => {
    document.title = currentTitle
  }

  new Modal(
    ModalFullBlock,
    { id, ids, onClose },
    { Dialog: ModalFullscreenDialog }
  ).open()
}
<commit_msg>Fix block lightbox<commit_after>import Modal from 'v2/components/UI/Modal'
import ModalFullscreenDialog from 'v2/components/UI/ModalFullscreenDialog'
import { ModalFullBlock } from 'v2/components/ModalFullBlock'

export default ({ id, context }) => {
  // Filter out Channels, Groups, Users and duplicates; return just IDs
  const set = new Set(
    context
      .filter(
        k =>
          k?.__typename !== 'Channel' &&
          k?.__typename !== 'Group' &&
          k?.__typename !== 'User' &&
          !!k?.id
      )
      .map(k => k.id.toString())
  )

  const ids = Array.from(set)

  const currentTitle = document.title
  const onClose = () => {
    document.title = currentTitle
  }

  new Modal(
    ModalFullBlock,
    { id, ids, onClose },
    { Dialog: ModalFullscreenDialog }
  ).open()
}
<|endoftext|>


<commit_before>/* global angular, $, console, _ */
angular
	.module('todos', ['ui', 'indx'])
	.controller('todos', function ($scope, client, utils, staged) {
		'use strict';

		var urgencies = ['low', 'med', 'high', 'urgent'];

		var u = utils,
			newList,
			newTodo,
			app,
			box;

		var specialLists = [
			new Backbone.Model({ id: 'todo-list-all', title: ['All todos'], special: ['all'], todos: [] }),
			new Backbone.Model({ id: 'todo-list-completed', title: ['Completed'], special: ['completed'], todos: [] })
		];

		// Wait until user is logged in and a box has been selected
		var init = function (b) {
			console.log('init');

			box = b;
			$scope.box = b; // FIXME remove (just for console use)

			box.getObj('todoApp').then(function (a) {
				app = a;
				if (!app.has('lists')) { app.set('lists', []); }
				updateLists();
				app.on('change:lists', updateLists);
				u.safeApply($scope);
			});

		};

		// watches for login or box changes
		$scope.$watch('selectedBox + selectedUser', function () {
			delete $scope.msg;
			if (!$scope.selectedUser) {
				$scope.msg = 'Please log in.';
			} else if (!$scope.selectedBox) {
				$scope.msg = 'Please select a box.';
			} else {
				client.store.getBox($scope.selectedBox)
					.then(function (box) { init(box); })
					.fail(function (e) { u.error('error ', e); $scope.msg = 'An error occured.'; });
			}

		});

		// todo - check box is defined (or put in init)
		$scope.createList = function () {
			box.getObj('todoList-'  + u.uuid()).then(function (list) {
				list.set({ title: [''], 'todos': [] });
				newList = list;
				updateLists();
				list.isCreated = function () { return false; }
				$scope.editList(list);
			});
		};

		$scope.editList = function (list) {
			state.editingList = list;
			list.showDropdown = false;
		};

		$scope.selectList = function (list) {
			if (state.selectedList) {
				state.selectedList.off('change:todos', updateTodos);
			}
			state.selectedList = list;
			updateTodos();
			list.on('change:todos', updateTodos);
		};

		$scope.deleteList = function (list) {
			list.destroy().then(function () {
				var lists = [].concat(app.get('lists'));
				lists.splice(lists.indexOf(list), 1);
				app.save('lists', lists).then(function () {
					if (state.selectedList === list) {
						delete state.selectedList;
					}
					updateLists();
				});
			});
		};

		$scope.cancelEditList = function () {
			if (!state.editingList) { return; }
			console.log('cancel', state.editingList)
			state.editingList.staged.reset();
			delete state.editingList;
			newList = undefined;
			updateLists();
		};

		$scope.saveList = function (list) {
			var dfd = $.Deferred();
			list.loading = true;
			if (list.staged.get('title')[0] === '') {
				dfd.reject();
			} else {
				list.staged.save().then(function () {
					list.isCreated = function () { return true; }
					console.log('SAVED', list.get('title'),app.get('lists'), [list])
					if (list === newList) {
						newList = undefined;
						app.save('lists', app.get('lists').concat([list])).then(function () {
							dfd.resolve();
						});
					} else {
						dfd.resolve();
					}
				});
			}
			dfd.then(function () {
				delete state.editingList;
				updateLists();
			}).always(function () {
				delete list.loading;
			});
		};

		$scope.countTodos = function (list) {
			return list.get('todos').length;
		};

		var updateLists = function () {
			console.log('UPDATING LISTS', app.get('lists'));
			// update special lists;
			var specialAll = _.findWhere(specialLists, { id: 'todo-list-all' }),
				specialCompleted = _.findWhere(specialLists, { id: 'todo-list-completed' });

			specialAll.set('todos', _.reduce(app.get('lists'), function (memo, list) {
				return memo.concat(list.get('todos') || []);
			}, []));

			specialCompleted.set('todos', _.filter(specialAll.get('todos'), function (todo) {
				return (todo.get('completed') || [])[0];
			}));

			_.each(app.get('lists'), function (list) {
				if (!list.has('title')) { list.set('title', ['Untitled list']) }
				if (!list.has('todos')) { list.set('todos', []) }
				list.isCreated = function () { return true; }
			});

			$scope.lists = [].concat(app.get('lists'));
			$scope.normalLists = [].concat(app.get('lists'));

			delete state.isFirstList;
			if ($scope.lists.length === 0) {
				state.isFirstList = true;
			}
			if (newList) { $scope.lists.push(newList); }

			if ($scope.lists.length === 0) {
				$scope.createList();
				return;
			}

			$scope.lists = $scope.lists.concat(specialLists);

			_.each($scope.lists, function (list) {
				if (!list.staged) { staged(list); }
			})

			if (!state.selectedList) { $scope.selectList($scope.lists[0]); }

			$update();
		}

		var $update = function () {
			console.log('$UPDATE', state.editingList)
			u.safeApply($scope);
		};

		$scope.bodyClick = function () {
			console.log(this)
			$scope.lists.forEach(function (list) {
				list.showDropdown = false;
			});
		};

		// todo - check box is defined (or put in init)
		$scope.createTodoBefore = function (next) {
			box.getObj('todo-'  + u.uuid()).then(function (todo) {
				var nextOrder = next ? next.get('order')[0] : 0,
					prev = _.chain(state.selectedList.get('todos')).sortBy(function (_todo) {
						return -_todo.get('order')[0];
					}).find(function (_todo) {
						return !next || (_todo.get('order')[0] < nextOrder);
					}).value(),
					prevOrder = prev ? prev.get('order')[0] : 0,
					order = 0;

				if (next && prev) {
					order = prevOrder + (nextOrder - prevOrder) / 2
				} else if (prev) {
					order = prevOrder + 1;
				}

				console.log('NP', /*next, prev, */nextOrder, prevOrder, order)
				todo.set({ title: [''], order: [order] });
				newTodo = todo;
				updateTodos();
			});
		};

		$scope.cancelEditTodo = function (todo) {
			console.log(todo);
			if (!todo) { return; }
			todo.staged.reset();
			newTodo = undefined;
			updateTodos();
		};

		$scope.saveTodo = function (todo) {
			var dfd = $.Deferred(),
				list = state.selectedList;
			todo.loading = true;
			if (todo.staged.get('title')[0] === '') { // delete the todo
				if (todo === newTodo) {
					newTodo = undefined;
					dfd.resolve();
				} else {
					todo.destroy().then(function () {
						var todos = [].concat(list.get('todos'));
						todos.splice(todos.indexOf(todo), 1);
						list.save('todos', todos).then(function () {
							dfd.resolve();
						});
					});
				}
			} else {
				todo.staged.save().then(function () {
					console.log('SAVED', list.get('title'))
					if (todo === newTodo) {
						newTodo = undefined;
						list.save('todos', list.get('todos').concat([todo])).then(function () {
							dfd.resolve();
						});
					} else {
						dfd.resolve();
					}
				});
			}
			dfd.then(function () {
				delete todo.loading;
				updateTodos();
				updateLists();
			});
		}

		var updateTodos = function () {
			var list = state.selectedList,
				todos = _.map(list.get('todos'), function (todo) {
					if (!todo.has('title')) { todo.set('title', ['Untitled todo']) }
					if (!todo.has('completed')) { todo.set('completed', [false]); }
					if (!todo.has('order')) { todo.set('order', [0]); }
					return todo;
				});
			if (newTodo) { todos.push(newTodo); }
			todos = _.sortBy(todos, function (todo) {
				return todo.get('order')[0];
			});
			_.each(todos, function (todo) {
				if (!todo.staged) { staged(todo); }
			});
			$scope.todos = todos;
			$update();
		};

		$scope.toggleTodoCompleted = function (todo) {
			todo.loading = true;
			todo.save('completed', [!todo.get('completed')[0]]).then(function () {
				todo.loading = false;
				updateTodos();
				updateLists();
			});
		};

		var state = $scope.s = {};

		window.$scope = $scope;

	}).directive('setFocus', function($timeout) {
		return {
			link: function ($scope, elem, attrs) {
				$scope.$watch(attrs.setFocus, function (value) {
					if (value === true) {
						setTimeout(function () { elem[0].focus(); });
					}
				});
			}
		};
	}).directive('clickElsewhere', function($document){
		return {
			restrict: 'A',
			link: function (scope, elem, attr, ctrl) {
				elem.bind('click', function (e) {
					// this part keeps it from firing the click on the document.
					e.stopPropagation();
				});
				$document.bind('click', function() {
					// magic here.
					scope.$apply(attr.clickElsewhere);
				});
			}
		};
	}).directive('ngEscape', ['$parse', function($parse) {
		return function ($scope, elem, attr) {
			var fn = $parse(attr.ngEscape);
			elem.bind('keydown keypress', function (e) {
				if (e.keyCode === 27) {
					$scope.$apply(function() { fn($scope, {$event:e}); });
					setTimeout(function () { elem[0].blur(); });
					e.stopPropagation();
				} else if (e.keyCode === 13) {
					setTimeout(function () { elem[0].blur(); });
				}
			});
		}
	}]);<commit_msg>silly scoping errors<commit_after>/* global angular, $, console, _ */
angular
	.module('todos', ['ui', 'indx'])
	.controller('todos', function ($scope, client, utils, staged) {
		'use strict';

		var urgencies = ['low', 'med', 'high', 'urgent'];

		var u = utils,
			newList,
			newTodo,
			app,
			box;

		var specialLists = [
			new Backbone.Model({ id: 'todo-list-all', title: ['All todos'], special: ['all'], todos: [] }),
			new Backbone.Model({ id: 'todo-list-completed', title: ['Completed'], special: ['completed'], todos: [] })
		];

		// Wait until user is logged in and a box has been selected
		var init = function (b) {
			newList = undefined;
			newTodo = undefined;
			app = undefined;
			box = b;
			//$scope.box = b; // FIXME remove (just for console use)

			box.getObj('todoApp').then(function (a) {
				app = a;
				if (!app.has('lists')) { app.set('lists', []); }
				updateLists();
				app.on('change:lists', updateLists);
				u.safeApply($scope);
			});

		};

		// watches for login or box changes
		$scope.$watch('selectedBox + selectedUser', function () {
			delete $scope.msg;
			if (!$scope.selectedUser) {
				$scope.msg = 'Please log in.';
			} else if (!$scope.selectedBox) {
				$scope.msg = 'Please select a box.';
			} else {
				client.store.getBox($scope.selectedBox)
					.then(function (box) { init(box); })
					.fail(function (e) { u.error('error ', e); $scope.msg = 'An error occured.'; });
			}

		});

		// todo - check box is defined (or put in init)
		$scope.createList = function () {
			box.getObj('todoList-'  + u.uuid()).then(function (list) {
				list.set({ title: [''], 'todos': [] });
				newList = list;
				updateLists();
				list.isCreated = function () { return false; }
				$scope.editList(list);
			});
		};

		$scope.editList = function (list) {
			state.editingList = list;
			list.showDropdown = false;
		};

		$scope.selectList = function (list) {
			if (state.selectedList) {
				state.selectedList.off('change:todos', updateTodos);
			}
			state.selectedList = list;
			updateTodos();
			list.on('change:todos', updateTodos);
		};

		$scope.deleteList = function (list) {
			list.destroy().then(function () {
				var lists = [].concat(app.get('lists'));
				lists.splice(lists.indexOf(list), 1);
				app.save('lists', lists).then(function () {
					if (state.selectedList === list) {
						delete state.selectedList;
					}
					updateLists();
				});
			});
		};

		$scope.cancelEditList = function () {
			if (!state.editingList) { return; }
			console.log('cancel', state.editingList)
			state.editingList.staged.reset();
			delete state.editingList;
			newList = undefined;
			updateLists();
		};

		$scope.saveList = function (list) {
			var dfd = $.Deferred();
			list.loading = true;
			if (list.staged.get('title')[0] === '') {
				dfd.reject();
			} else {
				list.staged.save().then(function () {
					list.isCreated = function () { return true; }
					console.log('SAVED', list.get('title'),app.get('lists'), [list])
					if (list === newList) {
						newList = undefined;
						app.save('lists', app.get('lists').concat([list])).then(function () {
							dfd.resolve();
						});
					} else {
						dfd.resolve();
					}
				});
			}
			dfd.then(function () {
				delete state.editingList;
				updateLists();
			}).always(function () {
				delete list.loading;
			});
		};

		$scope.countTodos = function (list) {
			return list.get('todos').length;
		};

		var updateLists = function () {
			console.log('UPDATING LISTS', app.get('lists'));
			// update special lists;
			var specialAll = _.findWhere(specialLists, { id: 'todo-list-all' }),
				specialCompleted = _.findWhere(specialLists, { id: 'todo-list-completed' });

			specialAll.set('todos', _.reduce(app.get('lists'), function (memo, list) {
				return memo.concat(list.get('todos') || []);
			}, []));

			specialCompleted.set('todos', _.filter(specialAll.get('todos'), function (todo) {
				return (todo.get('completed') || [])[0];
			}));

			_.each(app.get('lists'), function (list) {
				if (!list.has('title')) { list.set('title', ['Untitled list']) }
				if (!list.has('todos')) { list.set('todos', []) }
				list.isCreated = function () { return true; }
			});

			$scope.lists = [].concat(app.get('lists'));
			$scope.normalLists = [].concat(app.get('lists'));

			delete state.isFirstList;
			if ($scope.lists.length === 0) {
				state.isFirstList = true;
			}
			if (newList) { $scope.lists.push(newList); }

			if ($scope.lists.length === 0) {
				$scope.createList();
				return;
			}

			$scope.lists = $scope.lists.concat(specialLists);

			_.each($scope.lists, function (list) {
				if (!list.staged) { staged(list); }
			})

			if (!state.selectedList) { $scope.selectList($scope.lists[0]); }

			$update();
		}

		var $update = function () {
			console.log('$UPDATE', state.editingList)
			u.safeApply($scope);
		};

		$scope.bodyClick = function () {
			console.log(this)
			$scope.lists.forEach(function (list) {
				list.showDropdown = false;
			});
		};

		// todo - check box is defined (or put in init)
		$scope.createTodoBefore = function (next) {
			box.getObj('todo-'  + u.uuid()).then(function (todo) {
				var nextOrder = next ? next.get('order')[0] : 0,
					prev = _.chain(state.selectedList.get('todos')).sortBy(function (_todo) {
						return -_todo.get('order')[0];
					}).find(function (_todo) {
						return !next || (_todo.get('order')[0] < nextOrder);
					}).value(),
					prevOrder = prev ? prev.get('order')[0] : 0,
					order = 0;

				if (next && prev) {
					order = prevOrder + (nextOrder - prevOrder) / 2
				} else if (prev) {
					order = prevOrder + 1;
				}

				console.log('NP', /*next, prev, */nextOrder, prevOrder, order)
				todo.set({ title: [''], order: [order] });
				newTodo = todo;
				updateTodos();
			});
		};

		$scope.cancelEditTodo = function (todo) {
			console.log(todo);
			if (!todo) { return; }
			todo.staged.reset();
			newTodo = undefined;
			updateTodos();
		};

		$scope.saveTodo = function (todo) {
			var dfd = $.Deferred(),
				list = state.selectedList;
			todo.loading = true;
			if (todo.staged.get('title')[0] === '') { // delete the todo
				if (todo === newTodo) {
					newTodo = undefined;
					dfd.resolve();
				} else {
					todo.destroy().then(function () {
						var todos = [].concat(list.get('todos'));
						todos.splice(todos.indexOf(todo), 1);
						list.save('todos', todos).then(function () {
							dfd.resolve();
						});
					});
				}
			} else {
				todo.staged.save().then(function () {
					console.log('SAVED', list.get('title'))
					if (todo === newTodo) {
						newTodo = undefined;
						list.save('todos', list.get('todos').concat([todo])).then(function () {
							dfd.resolve();
						});
					} else {
						dfd.resolve();
					}
				});
			}
			dfd.then(function () {
				delete todo.loading;
				updateTodos();
				updateLists();
			});
		}

		var updateTodos = function () {
			var list = state.selectedList,
				todos = _.map(list.get('todos'), function (todo) {
					if (!todo.has('title')) { todo.set('title', ['Untitled todo']) }
					if (!todo.has('completed')) { todo.set('completed', [false]); }
					if (!todo.has('order')) { todo.set('order', [0]); }
					return todo;
				});
			if (newTodo) { todos.push(newTodo); }
			todos = _.sortBy(todos, function (todo) {
				return todo.get('order')[0];
			});
			_.each(todos, function (todo) {
				if (!todo.staged) { staged(todo); }
			});
			$scope.todos = todos;
			$update();
		};

		$scope.toggleTodoCompleted = function (todo) {
			todo.loading = true;
			todo.save('completed', [!todo.get('completed')[0]]).then(function () {
				todo.loading = false;
				updateTodos();
				updateLists();
			});
		};

		var state = $scope.s = {};

		window.$scope = $scope;

	}).directive('setFocus', function($timeout) {
		return {
			link: function ($scope, elem, attrs) {
				$scope.$watch(attrs.setFocus, function (value) {
					if (value === true) {
						setTimeout(function () { elem[0].focus(); });
					}
				});
			}
		};
	}).directive('clickElsewhere', function($document){
		return {
			restrict: 'A',
			link: function (scope, elem, attr, ctrl) {
				elem.bind('click', function (e) {
					// this part keeps it from firing the click on the document.
					e.stopPropagation();
				});
				$document.bind('click', function() {
					// magic here.
					scope.$apply(attr.clickElsewhere);
				});
			}
		};
	}).directive('ngEscape', ['$parse', function($parse) {
		return function ($scope, elem, attr) {
			var fn = $parse(attr.ngEscape);
			elem.bind('keydown keypress', function (e) {
				if (e.keyCode === 27) {
					$scope.$apply(function() { fn($scope, {$event:e}); });
					setTimeout(function () { elem[0].blur(); });
					e.stopPropagation();
				} else if (e.keyCode === 13) {
					setTimeout(function () { elem[0].blur(); });
				}
			});
		}
	}]);<|endoftext|>


<commit_before>import path from 'path'
import fs from 'fs'
import {
  useFileName,
  useDisplayName,
  useSSR,
  useNamespace,
} from '../utils/options'
import getName from '../utils/getName'
import prefixLeadingDigit from '../utils/prefixDigit'
import hash from '../utils/hash'
import {
  isCreateGlobalStyleHelper,
  isCSSHelper,
  isStyled,
} from '../utils/detectors'

const addConfig = t => (path, displayName, componentId) => {
  if (!displayName && !componentId) {
    return
  }

  const withConfigProps = []

  if (displayName) {
    withConfigProps.push(
      t.objectProperty(
        t.identifier('displayName'),
        t.stringLiteral(displayName)
      )
    )
  }
  if (componentId) {
    withConfigProps.push(
      t.objectProperty(
        t.identifier('componentId'),
        t.stringLiteral(componentId)
      )
    )
  }

  const existingConfig = getExistingConfig(t)(path)

  if (
    existingConfig &&
    existingConfig.arguments.length &&
    !existingConfig.arguments[0].properties.some(prop =>
      ['displayName', 'componentId'].includes(prop.key.name)
    )
  ) {
    existingConfig.arguments[0].properties.push(...withConfigProps)
    return
  }

  if (
    path.node.callee &&
    t.isMemberExpression(path.node.callee.callee) &&
    path.node.callee.callee.property &&
    path.node.callee.callee.property.name &&
    path.node.callee.callee.property.name == 'withConfig' &&
    path.node.callee.arguments.length &&
    !path.node.callee.arguments[0].properties.some(prop =>
      ['displayName', 'componentId'].includes(prop.key.name)
    )
  ) {
    path.node.callee.arguments[0].properties.push(...withConfigProps)
    return
  }

  if (path.node.tag) {
    // Replace x`...` with x.withConfig({ })`...`
    path.node.tag = t.callExpression(
      t.memberExpression(path.node.tag, t.identifier('withConfig')),
      [t.objectExpression(withConfigProps)]
    )
  } else {
    path.replaceWith(
      t.callExpression(
        t.callExpression(
          t.memberExpression(path.node.callee, t.identifier('withConfig')),
          [t.objectExpression(withConfigProps)]
        ),
        path.node.arguments
      )
    )
  }
}

const getExistingConfig = t => path => {
  if (
    path.node.callee &&
    t.isMemberExpression(path.node.callee.callee) &&
    path.node.callee.callee.property &&
    path.node.callee.callee.property.name &&
    path.node.callee.callee.property.name == 'withConfig'
  ) {
    return path.node.callee
  }

  if (
    path.node.callee &&
    t.isMemberExpression(path.node.callee.callee) &&
    path.node.callee.callee.object &&
    path.node.callee.callee.object.callee &&
    path.node.callee.callee.object.callee.property &&
    path.node.callee.callee.object.callee.property.name === 'withConfig'
  ) {
    return path.node.callee.callee.object
  }
}

const getBlockName = file => {
  const name = path.basename(
    file.opts.filename,
    path.extname(file.opts.filename)
  )
  return name !== 'index'
    ? name
    : path.basename(path.dirname(file.opts.filename))
}

const getDisplayName = t => (path, state) => {
  const { file } = state
  const componentName = getName(t)(path)
  if (file) {
    const blockName = getBlockName(file)
    if (blockName === componentName) {
      return componentName
    }
    return componentName
      ? `${prefixLeadingDigit(blockName)}__${componentName}`
      : prefixLeadingDigit(blockName)
  } else {
    return componentName
  }
}

const findModuleRoot = filename => {
  if (!filename) {
    return null
  }
  let dir = path.dirname(filename)
  if (fs.existsSync(path.join(dir, 'package.json'))) {
    return dir
  } else if (dir !== filename) {
    return findModuleRoot(dir)
  } else {
    return null
  }
}

const FILE_HASH = 'styled-components-file-hash'
const COMPONENT_POSITION = 'styled-components-component-position'
const separatorRegExp = new RegExp(`\\${path.sep}`, 'g')

const getFileHash = state => {
  const { file } = state
  // hash calculation is costly due to fs operations, so we'll cache it per file.
  if (file.get(FILE_HASH)) {
    return file.get(FILE_HASH)
  }
  const filename = file.opts.filename
  // find module root directory
  const moduleRoot = findModuleRoot(filename)
  const filePath =
    moduleRoot &&
    path.relative(moduleRoot, filename).replace(separatorRegExp, '/')
  const moduleName =
    moduleRoot &&
    JSON.parse(fs.readFileSync(path.join(moduleRoot, 'package.json'))).name
  const code = file.code

  const stuffToHash = [moduleName]

  if (filePath) {
    stuffToHash.push(filePath)
  } else {
    stuffToHash.push(code)
  }

  const fileHash = hash(stuffToHash.join(''))
  file.set(FILE_HASH, fileHash)
  return fileHash
}

const getNextId = state => {
  const id = state.file.get(COMPONENT_POSITION) || 0
  state.file.set(COMPONENT_POSITION, id + 1)
  return id
}

const getComponentId = state => {
  // Prefix the identifier with a character because CSS classes cannot start with a number
  return `${useNamespace(state)}sc-${getFileHash(state)}-${getNextId(state)}`
}

export default t => (path, state) => {
  if (
    path.node.tag
      ? isStyled(t)(path.node.tag, state)
      : /* styled()`` */ (isStyled(t)(path.node.callee, state) &&
          path.node.callee.property &&
          path.node.callee.property.name !== 'withConfig') ||
        // styled(x)({})
        (isStyled(t)(path.node.callee, state) &&
          !t.isMemberExpression(path.node.callee.callee)) ||
        // styled(x).attrs()({})
        (isStyled(t)(path.node.callee, state) &&
          t.isMemberExpression(path.node.callee.callee) &&
          path.node.callee.callee.property &&
          path.node.callee.callee.property.name &&
          path.node.callee.callee.property.name !== 'withConfig') ||
        // styled(x).withConfig({})
        (isStyled(t)(path.node.callee, state) &&
          t.isMemberExpression(path.node.callee.callee) &&
          path.node.callee.callee.property &&
          path.node.callee.callee.property.name &&
          path.node.callee.callee.property.name === 'withConfig' &&
          !path.node.callee.arguments[0].properties.some(prop =>
            ['displayName', 'componentId'].includes(prop.key.name)
          ))
  ) {
    const displayName =
      useDisplayName(state) &&
      getDisplayName(t)(path, useFileName(state) && state)

    addConfig(t)(
      path,
      displayName && displayName.replace(/[^_a-zA-Z0-9-]/g, ''),
      useSSR(state) && getComponentId(state)
    )
  }
}
<commit_msg>add some guards<commit_after>import path from 'path'
import fs from 'fs'
import {
  useFileName,
  useDisplayName,
  useSSR,
  useNamespace,
} from '../utils/options'
import getName from '../utils/getName'
import prefixLeadingDigit from '../utils/prefixDigit'
import hash from '../utils/hash'
import {
  isCreateGlobalStyleHelper,
  isCSSHelper,
  isStyled,
} from '../utils/detectors'

const addConfig = t => (path, displayName, componentId) => {
  if (!displayName && !componentId) {
    return
  }

  const withConfigProps = []

  if (displayName) {
    withConfigProps.push(
      t.objectProperty(
        t.identifier('displayName'),
        t.stringLiteral(displayName)
      )
    )
  }
  if (componentId) {
    withConfigProps.push(
      t.objectProperty(
        t.identifier('componentId'),
        t.stringLiteral(componentId)
      )
    )
  }

  const existingConfig = getExistingConfig(t)(path)

  if (
    existingConfig &&
    existingConfig.arguments.length &&
    Array.isArray(existingConfig.arguments[0].properties) &&
    !existingConfig.arguments[0].properties.some(prop =>
      ['displayName', 'componentId'].includes(prop.key.name)
    )
  ) {
    existingConfig.arguments[0].properties.push(...withConfigProps)
    return
  }

  if (
    path.node.callee &&
    t.isMemberExpression(path.node.callee.callee) &&
    path.node.callee.callee.property &&
    path.node.callee.callee.property.name &&
    path.node.callee.callee.property.name == 'withConfig' &&
    path.node.callee.arguments.length &&
    Array.isArray(path.node.callee.arguments[0].properties) &&
    !path.node.callee.arguments[0].properties.some(prop =>
      ['displayName', 'componentId'].includes(prop.key.name)
    )
  ) {
    path.node.callee.arguments[0].properties.push(...withConfigProps)
    return
  }

  if (path.node.tag) {
    // Replace x`...` with x.withConfig({ })`...`
    path.node.tag = t.callExpression(
      t.memberExpression(path.node.tag, t.identifier('withConfig')),
      [t.objectExpression(withConfigProps)]
    )
  } else {
    path.replaceWith(
      t.callExpression(
        t.callExpression(
          t.memberExpression(path.node.callee, t.identifier('withConfig')),
          [t.objectExpression(withConfigProps)]
        ),
        path.node.arguments
      )
    )
  }
}

const getExistingConfig = t => path => {
  if (
    path.node.callee &&
    t.isMemberExpression(path.node.callee.callee) &&
    path.node.callee.callee.property &&
    path.node.callee.callee.property.name &&
    path.node.callee.callee.property.name == 'withConfig'
  ) {
    return path.node.callee
  }

  if (
    path.node.callee &&
    t.isMemberExpression(path.node.callee.callee) &&
    path.node.callee.callee.object &&
    path.node.callee.callee.object.callee &&
    path.node.callee.callee.object.callee.property &&
    path.node.callee.callee.object.callee.property.name === 'withConfig'
  ) {
    return path.node.callee.callee.object
  }
}

const getBlockName = file => {
  const name = path.basename(
    file.opts.filename,
    path.extname(file.opts.filename)
  )
  return name !== 'index'
    ? name
    : path.basename(path.dirname(file.opts.filename))
}

const getDisplayName = t => (path, state) => {
  const { file } = state
  const componentName = getName(t)(path)
  if (file) {
    const blockName = getBlockName(file)
    if (blockName === componentName) {
      return componentName
    }
    return componentName
      ? `${prefixLeadingDigit(blockName)}__${componentName}`
      : prefixLeadingDigit(blockName)
  } else {
    return componentName
  }
}

const findModuleRoot = filename => {
  if (!filename) {
    return null
  }
  let dir = path.dirname(filename)
  if (fs.existsSync(path.join(dir, 'package.json'))) {
    return dir
  } else if (dir !== filename) {
    return findModuleRoot(dir)
  } else {
    return null
  }
}

const FILE_HASH = 'styled-components-file-hash'
const COMPONENT_POSITION = 'styled-components-component-position'
const separatorRegExp = new RegExp(`\\${path.sep}`, 'g')

const getFileHash = state => {
  const { file } = state
  // hash calculation is costly due to fs operations, so we'll cache it per file.
  if (file.get(FILE_HASH)) {
    return file.get(FILE_HASH)
  }
  const filename = file.opts.filename
  // find module root directory
  const moduleRoot = findModuleRoot(filename)
  const filePath =
    moduleRoot &&
    path.relative(moduleRoot, filename).replace(separatorRegExp, '/')
  const moduleName =
    moduleRoot &&
    JSON.parse(fs.readFileSync(path.join(moduleRoot, 'package.json'))).name
  const code = file.code

  const stuffToHash = [moduleName]

  if (filePath) {
    stuffToHash.push(filePath)
  } else {
    stuffToHash.push(code)
  }

  const fileHash = hash(stuffToHash.join(''))
  file.set(FILE_HASH, fileHash)
  return fileHash
}

const getNextId = state => {
  const id = state.file.get(COMPONENT_POSITION) || 0
  state.file.set(COMPONENT_POSITION, id + 1)
  return id
}

const getComponentId = state => {
  // Prefix the identifier with a character because CSS classes cannot start with a number
  return `${useNamespace(state)}sc-${getFileHash(state)}-${getNextId(state)}`
}

export default t => (path, state) => {
  if (
    path.node.tag
      ? isStyled(t)(path.node.tag, state)
      : /* styled()`` */ (isStyled(t)(path.node.callee, state) &&
          path.node.callee.property &&
          path.node.callee.property.name !== 'withConfig') ||
        // styled(x)({})
        (isStyled(t)(path.node.callee, state) &&
          !t.isMemberExpression(path.node.callee.callee)) ||
        // styled(x).attrs()({})
        (isStyled(t)(path.node.callee, state) &&
          t.isMemberExpression(path.node.callee.callee) &&
          path.node.callee.callee.property &&
          path.node.callee.callee.property.name &&
          path.node.callee.callee.property.name !== 'withConfig') ||
        // styled(x).withConfig({})
        (isStyled(t)(path.node.callee, state) &&
          t.isMemberExpression(path.node.callee.callee) &&
          path.node.callee.callee.property &&
          path.node.callee.callee.property.name &&
          path.node.callee.callee.property.name === 'withConfig' &&
          path.node.callee.arguments.length &&
          Array.isArray(path.node.callee.arguments[0].properties) &&
          !path.node.callee.arguments[0].properties.some(prop =>
            ['displayName', 'componentId'].includes(prop.key.name)
          ))
  ) {
    const displayName =
      useDisplayName(state) &&
      getDisplayName(t)(path, useFileName(state) && state)

    addConfig(t)(
      path,
      displayName && displayName.replace(/[^_a-zA-Z0-9-]/g, ''),
      useSSR(state) && getComponentId(state)
    )
  }
}
<|endoftext|>


<commit_before>import React, {Component} from 'react';
import {findDOMNode} from 'react-dom';
import debounce from 'lodash/debounce';

import LandingNav from './LandingNav';
import LandingIntro from './sections/LandingIntro';
import LandingComponentCount from './sections/LandingComponentCount';
import LandingGetStarted from './sections/LandingGetStarted';
import LandingUsage from './sections/LandingUsage';
import LandingExamples from './sections/LandingExamples';
import LandingFoot from './LandingFoot';

import Event from 'vendors/Event';

import 'sass/containers/landing/Landing.scss';

class Landing extends Component {

    constructor(props) {

        super(props);

        this.menu = [{
            name: 'Intro',
            hash: '#landing-intro'
        }, {
            name: 'Get Started',
            hash: '#landing-get-started'
        }, {
            name: 'Usage',
            hash: '#landing-usage'
        }, {
            name: 'Examples',
            hash: '#landing-examples'
        }];

        this.state = {
            bodyScrollTop: 0,
            activatedMenu: this.menu[0],
            isNavFixed: false
        };

        this.isNavFixed = ::this.isNavFixed;
        this.scrollHandler = ::this.scrollHandler;

    }

    isNavFixed(bodyScrollTop) {
        const introEl = document.querySelector(this.menu[0].hash);
        return introEl && (bodyScrollTop > introEl.clientHeight - this.navHeight);
    }

    getActivatedMenu(bodyScrollTop) {

        let activatedMenu = this.menu[0];

        for (let i = 0, len = this.menu.length; i < len; i++) {
            const el = document.querySelector(this.menu[i].hash);
            if (el && bodyScrollTop >= el.offsetTop - this.navHeight) {
                activatedMenu = this.menu[i];
            }
        }

        return activatedMenu;

    }

    scrollHandler = debounce(() => {

        const bodyScrollTop = document.body.scrollTop || document.documentElement.scrollTop;

        this.setState({
            bodyScrollTop,
            activatedMenu: this.getActivatedMenu(bodyScrollTop),
            isNavFixed: this.isNavFixed(bodyScrollTop)
        });

    }, 250);

    componentDidMount() {

        Event.addEvent(document, 'scroll', this.scrollHandler);

        this.navEl = findDOMNode(this.refs.nav);
        this.navHeight = (this.navEl && this.navEl.offsetHeight) || 80;

    }

    componentWillUnmount() {
        Event.removeEvent(document, 'scroll', this.scrollHandler);
    }

    render() {

        const {bodyScrollTop, activatedMenu, isNavFixed} = this.state;

        return (

                <LandingNav ref="nav"
                            menu={this.menu}
                            activatedMenu={activatedMenu}
                            isFixed={isNavFixed}/>

                <LandingIntro/>

                <LandingComponentCount bodyScrollTop={bodyScrollTop}/>

                <LandingGetStarted/>

                <LandingUsage/>

                <LandingExamples/>

                <LandingFoot/>

        );

    }
}

export default Landing;<commit_msg>update Landing<commit_after>import React, {Component} from 'react';
import {findDOMNode} from 'react-dom';

import LandingNav from './LandingNav';
import LandingIntro from './sections/LandingIntro';
import LandingComponentCount from './sections/LandingComponentCount';
import LandingGetStarted from './sections/LandingGetStarted';
import LandingUsage from './sections/LandingUsage';
import LandingExamples from './sections/LandingExamples';
import LandingFoot from './LandingFoot';

import Event from 'vendors/Event';

import 'sass/containers/landing/Landing.scss';

class Landing extends Component {

    constructor(props) {

        super(props);

        this.menu = [{
            name: 'Intro',
            hash: '#landing-intro'
        }, {
            name: 'Get Started',
            hash: '#landing-get-started'
        }, {
            name: 'Usage',
            hash: '#landing-usage'
        }, {
            name: 'Examples',
            hash: '#landing-examples'
        }];

        this.state = {
            bodyScrollTop: 0,
            activatedMenu: this.menu[0],
            isNavFixed: false
        };

    }

    isNavFixed = bodyScrollTop => {
        const introEl = document.querySelector(this.menu[0].hash);
        return introEl && (bodyScrollTop > introEl.clientHeight - this.navHeight);
    };

    getActivatedMenu = bodyScrollTop => {

        let activatedMenu = this.menu[0];

        for (let i = 0, len = this.menu.length; i < len; i++) {
            const el = document.querySelector(this.menu[i].hash);
            if (el && bodyScrollTop >= el.offsetTop - this.navHeight) {
                activatedMenu = this.menu[i];
            }
        }

        return activatedMenu;

    };

    scrollHandler = () => {

        const bodyScrollTop = document.body.scrollTop || document.documentElement.scrollTop;

        this.setState({
            bodyScrollTop,
            activatedMenu: this.getActivatedMenu(bodyScrollTop),
            isNavFixed: this.isNavFixed(bodyScrollTop)
        });

    };

    componentDidMount() {

        Event.addEvent(document, 'scroll', this.scrollHandler);

        this.navEl = findDOMNode(this.refs.nav);
        this.navHeight = (this.navEl && this.navEl.offsetHeight) || 80;

    }

    componentWillUnmount() {
        Event.removeEvent(document, 'scroll', this.scrollHandler);
    }

    render() {

        const {bodyScrollTop, activatedMenu, isNavFixed} = this.state;

        return (

                <LandingNav ref="nav"
                            menu={this.menu}
                            activatedMenu={activatedMenu}
                            isFixed={isNavFixed}/>

                <LandingIntro/>

                <LandingComponentCount bodyScrollTop={bodyScrollTop}/>

                <LandingGetStarted/>

                <LandingUsage/>

                <LandingExamples/>

                <LandingFoot/>

        );

    }
}

export default Landing;<|endoftext|>


<commit_before>var StateManager = function() {
  this.states = {};
  this.renderOrder = [];
  this.updateOrder = [];
};

StateManager.prototype.add = function(name, state) {
  this.states[name] = this._newStateHolder(name, state);
  this.refreshOrder();
  return state;
};

var renderOrderSort = function(a, b) {
  return a.renderOrder < b.renderOrder;
};

var updateOrderSort = function(a, b) {
  return a.updateOrder < b.updateOrder;
};

StateManager.prototype.refreshOrder = function() {
  this.renderOrder.length = 0;
  this.updateOrder.length = 0;

  for (var name in this.states) {
    var holder = this.states[name];
    if (holder) {
      this.renderOrder.push(holder);
      this.updateOrder.push(holder);
    }
  }

  this.renderOrder.sort(renderOrderSort);
  this.updateOrder.sort(updateOrderSort);
};

StateManager.prototype._newStateHolder = function(name, state) {
  var holder = {};
  holder.name = name;
  holder.state = state;

  holder.protect = false;

  holder.enabled = true;
  holder.paused = false;

  holder.render = true;

  holder.initialized = false;
  holder.updated = false;

  holder.updateOrder = 0;
  holder.renderOrder = 0;

  return holder;
};

StateManager.prototype.setUpdateOrder = function(name, order) {
  var holder = this.get(name);
  if (holder) {
    holder.updateOrder = order;
    this.refreshOrder();
  }
};

StateManager.prototype.setRenderOrder = function(name, order) {
  var holder = this.get(name);
  if (holder) {
    holder.renderOrder = order;
    this.refreshOrder();
  }
};

StateManager.prototype.get = function(name) {
  return this.states[name];
};

StateManager.prototype.destroy = function(name) {
  var state = this.get(name);
  if (state && !state.protect) {
    if (state.state.close) {
      state.state.close();
    }
    delete this.states[name];
    this.refreshOrder();
  }
};

StateManager.prototype.destroyAll = function() {
  for (var i=0, len=this.updateOrder.length; i<len; i++) {
    var state = this.updateOrder[i];
    if (!state.protect) {
      if (state.state.close) {
        state.state.close();
      }
      delete this.states[state.name];
    }
  }

  this.refreshOrder();
};

StateManager.prototype.update = function(time) {
  for (var i=0, len=this.updateOrder.length; i<len; i++) {
    var state = this.updateOrder[i];

    if (state && state.enabled && state.state.update && !state.paused) {
      if (!state.initialized && state.state.init) {
        state.initialized = true;
        state.state.init();
      }

      state.state.update(time);
      state.updated = true;
    }
  }
};

StateManager.prototype.exitUpdate = function(time) {
  for (var i=0, len=this.updateOrder.length; i<len; i++) {
    var state = this.updateOrder[i];

    if (state.enabled && state.state.exitUpdate && !state.paused) {
      state.state.exitUpdate(time);
      state.updated = true;
    }
  }
};

StateManager.prototype.enable = function(name) {
  var holder = this.get(name);
  if (holder) {
    if (!holder.enabled) {
      if (holder.state.enable) {
        holder.state.enable();
      }
      holder.enabled = true;

      if (holder.paused) {
        this.unpause(name);
      }
    }
  }
};

StateManager.prototype.disable = function(name) {
  var holder = this.get(name);
  if (holder) {
    if (holder.enabled) {
      if (holder.state.disable) {
        holder.state.disable();
      }
      holder.enabled = false;
    }
  }
};

StateManager.prototype.render = function() {
  for (var i=0, len=this.renderOrder.length; i<len; i++) {
    var state = this.renderOrder[i];
    if (state.enabled && state.updated && state.render && state.state.render) {
      state.state.render();
    }
  }
};

StateManager.prototype.pause = function(name) {
  var holder = this.get(name);
  if (holder) {
    if (holder.state.pause) {
      holder.state.pause();
    }

    holder.paused = true;
  }
};

StateManager.prototype.unpause = function(name) {
  var holder = this.get(name);
  if (holder) {
    if (holder.state.unpause) {
      holder.state.unpause();
    }

    holder.paused = false;
  }
};

StateManager.prototype.protect = function(name) {
  var holder = this.get(name);
  if (holder) {
    holder.protect = true;
  }
};

StateManager.prototype.unprotect = function(name) {
  var holder = this.get(name);
  if (holder) {
    holder.protect = false;
  }
};

StateManager.prototype.mousemove = function(x, y, e) {
  for (var i=0, len=this.updateOrder.length; i<len; i++) {
    var state = this.updateOrder[i];
    if (state.enabled && state.state.mousemove && !state.paused) {
      state.state.mousemove(x, y, e);
    }
  }
};

StateManager.prototype.mouseup = function(x, y) {
  for (var i=0, len=this.updateOrder.length; i<len; i++) {
    var state = this.updateOrder[i];
    if (state.enabled && state.state.mouseup && !state.paused) {
      state.state.mouseup(x, y);
    }
  }
};

StateManager.prototype.mousedown = function(x, y, button) {
  for (var i=0, len=this.updateOrder.length; i<len; i++) {
    var state = this.updateOrder[i];
    if (state.enabled && state.state.mousedown && !state.paused) {
      state.state.mousedown(x, y, button);
    }
  }
};

StateManager.prototype.click = function(x, y, button) {
  for (var i=0, len=this.updateOrder.length; i<len; i++) {
    var state = this.updateOrder[i];
    if (state.enabled && state.state.click && !state.paused) {
      state.state.click(x, y, button);
    }
  }
};

StateManager.prototype.keypress = function(key) {
  for (var i=0, len=this.updateOrder.length; i<len; i++) {
    var state = this.updateOrder[i];
    if (state.enabled && state.state.keypress && !state.paused) {
      state.state.keypress(key);
    }
  }
};

StateManager.prototype.keyup = function(key) {
  for (var i=0, len=this.updateOrder.length; i<len; i++) {
    var state = this.updateOrder[i];
    if (state.enabled && state.state.keyup && !state.paused) {
      state.state.keyup(key);
    }
  }
};

StateManager.prototype.keydown = function(key) {
  for (var i=0, len=this.updateOrder.length; i<len; i++) {
    var state = this.updateOrder[i];
    if (state.enabled && state.state.keydown && !state.paused) {
      state.state.keydown(key);
    }
  }
};

StateManager.prototype.resize = function() {
  for (var i=0, len=this.updateOrder.length; i<len; i++) {
    var state = this.updateOrder[i];
    if (state.enabled && state.render && state.state.resize) {
      state.state.resize();
    }
  }
};

module.exports = StateManager;
<commit_msg>dont set updated after exitUpdate<commit_after>var StateManager = function() {
  this.states = {};
  this.renderOrder = [];
  this.updateOrder = [];
};

StateManager.prototype.add = function(name, state) {
  this.states[name] = this._newStateHolder(name, state);
  this.refreshOrder();
  return state;
};

var renderOrderSort = function(a, b) {
  return a.renderOrder < b.renderOrder;
};

var updateOrderSort = function(a, b) {
  return a.updateOrder < b.updateOrder;
};

StateManager.prototype.refreshOrder = function() {
  this.renderOrder.length = 0;
  this.updateOrder.length = 0;

  for (var name in this.states) {
    var holder = this.states[name];
    if (holder) {
      this.renderOrder.push(holder);
      this.updateOrder.push(holder);
    }
  }

  this.renderOrder.sort(renderOrderSort);
  this.updateOrder.sort(updateOrderSort);
};

StateManager.prototype._newStateHolder = function(name, state) {
  var holder = {};
  holder.name = name;
  holder.state = state;

  holder.protect = false;

  holder.enabled = true;
  holder.paused = false;

  holder.render = true;

  holder.initialized = false;
  holder.updated = false;

  holder.updateOrder = 0;
  holder.renderOrder = 0;

  return holder;
};

StateManager.prototype.setUpdateOrder = function(name, order) {
  var holder = this.get(name);
  if (holder) {
    holder.updateOrder = order;
    this.refreshOrder();
  }
};

StateManager.prototype.setRenderOrder = function(name, order) {
  var holder = this.get(name);
  if (holder) {
    holder.renderOrder = order;
    this.refreshOrder();
  }
};

StateManager.prototype.get = function(name) {
  return this.states[name];
};

StateManager.prototype.destroy = function(name) {
  var state = this.get(name);
  if (state && !state.protect) {
    if (state.state.close) {
      state.state.close();
    }
    delete this.states[name];
    this.refreshOrder();
  }
};

StateManager.prototype.destroyAll = function() {
  for (var i=0, len=this.updateOrder.length; i<len; i++) {
    var state = this.updateOrder[i];
    if (!state.protect) {
      if (state.state.close) {
        state.state.close();
      }
      delete this.states[state.name];
    }
  }

  this.refreshOrder();
};

StateManager.prototype.update = function(time) {
  for (var i=0, len=this.updateOrder.length; i<len; i++) {
    var state = this.updateOrder[i];

    if (state && state.enabled && state.state.update && !state.paused) {
      if (!state.initialized && state.state.init) {
        state.initialized = true;
        state.state.init();
      }

      state.state.update(time);
      state.updated = true;
    }
  }
};

StateManager.prototype.exitUpdate = function(time) {
  for (var i=0, len=this.updateOrder.length; i<len; i++) {
    var state = this.updateOrder[i];

    if (state.enabled && state.state.exitUpdate && !state.paused) {
      state.state.exitUpdate(time);
    }
  }
};

StateManager.prototype.enable = function(name) {
  var holder = this.get(name);
  if (holder) {
    if (!holder.enabled) {
      if (holder.state.enable) {
        holder.state.enable();
      }
      holder.enabled = true;

      if (holder.paused) {
        this.unpause(name);
      }
    }
  }
};

StateManager.prototype.disable = function(name) {
  var holder = this.get(name);
  if (holder) {
    if (holder.enabled) {
      if (holder.state.disable) {
        holder.state.disable();
      }
      holder.enabled = false;
    }
  }
};

StateManager.prototype.render = function() {
  for (var i=0, len=this.renderOrder.length; i<len; i++) {
    var state = this.renderOrder[i];
    if (state.enabled && state.updated && state.render && state.state.render) {
      state.state.render();
    }
  }
};

StateManager.prototype.pause = function(name) {
  var holder = this.get(name);
  if (holder) {
    if (holder.state.pause) {
      holder.state.pause();
    }

    holder.paused = true;
  }
};

StateManager.prototype.unpause = function(name) {
  var holder = this.get(name);
  if (holder) {
    if (holder.state.unpause) {
      holder.state.unpause();
    }

    holder.paused = false;
  }
};

StateManager.prototype.protect = function(name) {
  var holder = this.get(name);
  if (holder) {
    holder.protect = true;
  }
};

StateManager.prototype.unprotect = function(name) {
  var holder = this.get(name);
  if (holder) {
    holder.protect = false;
  }
};

StateManager.prototype.mousemove = function(x, y, e) {
  for (var i=0, len=this.updateOrder.length; i<len; i++) {
    var state = this.updateOrder[i];
    if (state.enabled && state.state.mousemove && !state.paused) {
      state.state.mousemove(x, y, e);
    }
  }
};

StateManager.prototype.mouseup = function(x, y) {
  for (var i=0, len=this.updateOrder.length; i<len; i++) {
    var state = this.updateOrder[i];
    if (state.enabled && state.state.mouseup && !state.paused) {
      state.state.mouseup(x, y);
    }
  }
};

StateManager.prototype.mousedown = function(x, y, button) {
  for (var i=0, len=this.updateOrder.length; i<len; i++) {
    var state = this.updateOrder[i];
    if (state.enabled && state.state.mousedown && !state.paused) {
      state.state.mousedown(x, y, button);
    }
  }
};

StateManager.prototype.click = function(x, y, button) {
  for (var i=0, len=this.updateOrder.length; i<len; i++) {
    var state = this.updateOrder[i];
    if (state.enabled && state.state.click && !state.paused) {
      state.state.click(x, y, button);
    }
  }
};

StateManager.prototype.keypress = function(key) {
  for (var i=0, len=this.updateOrder.length; i<len; i++) {
    var state = this.updateOrder[i];
    if (state.enabled && state.state.keypress && !state.paused) {
      state.state.keypress(key);
    }
  }
};

StateManager.prototype.keyup = function(key) {
  for (var i=0, len=this.updateOrder.length; i<len; i++) {
    var state = this.updateOrder[i];
    if (state.enabled && state.state.keyup && !state.paused) {
      state.state.keyup(key);
    }
  }
};

StateManager.prototype.keydown = function(key) {
  for (var i=0, len=this.updateOrder.length; i<len; i++) {
    var state = this.updateOrder[i];
    if (state.enabled && state.state.keydown && !state.paused) {
      state.state.keydown(key);
    }
  }
};

StateManager.prototype.resize = function() {
  for (var i=0, len=this.updateOrder.length; i<len; i++) {
    var state = this.updateOrder[i];
    if (state.enabled && state.render && state.state.resize) {
      state.state.resize();
    }
  }
};

module.exports = StateManager;
<|endoftext|>


<commit_before>const Constants = require('./Constants');

/**
 * HyperBolts ϟ (https://hyperbolts.io)
 *
 * Copyright © 2015-present Pace IT Systems Ltd.
 * All rights reserved.
 *
 * @author  Pace IT Systems Ltd
 * @license MIT
 */

module.exports = (state = {
    sources: {},
    errors:  []
}, action) => {
    let loading = false;

    // Handle action type
    switch (action.type) {

        // Request state
        case Constants.Actions.REQUEST_STATE:
            loading = true;

            // Check for existing cache
            const cache = state.sources[action.source] || {};

            // If we already have state for this source we need
            // to keep this intact, otherwise components will
            // temporarily blank while data is being refreshed
            if (cache !== undefined) {
                if (Array.isArray(cache.state) === true) {
                    action.state = action.state.splice();
                } else {
                    action.state = Object.assign({}, cache.state);
                }
            }

        // Receive state
        case Constants.Actions.RECEIVE_STATE:

            // Nest state in a new object with source,
            // loading status and update timestamp
            action.state = {
                state:   action.state || [],
                source:  action.source,
                updated: Date.now(),
                loading: loading,
                error:   false
            }

            // Return updated state
            return Object.assign({}, state, {

                // Merge into existing sources. We need to use a new
                // copy of the source object otherwise anything
                // referencing it will be updated.
                sources: Object.assign({}, state.sources, {
                    [action.source]: action.state
                })
            });

        // Error state
        case Constants.Actions.ADD_ERROR: {
            const source  = state.sources[action.source];
            const errors  = state.errors.slice();
            const sources = {};

            // If source exists, set error flag to true
            if (source !== undefined) {
                sources[action.source] = Object.assign({}, source, {
                    updated: Date.now(),
                    error:   true
                });
            }

            // Add error to stack
            errors.push({
                source:   action.source,
                error:    action.error,
                status:   action.status,
                response: action.response
            });

            // Return updated state
            return Object.assign({}, state, {
                sources: Object.assign({}, state.sources, sources),
                errors
            });
        }

        // Remove error
        case Constants.Actions.REMOVE_ERROR: {
            const errors = state.errors.slice();

            // Return updated state
            errors.splice(action.key, 1);
            return Object.assign({}, state, {
                errors
            });
        }

        // Remove errors
        case Constants.Actions.REMOVE_ERRORS:
            return Object.assign({}, state, {
                errors: []
            });

        // Reset store
        case Constants.Actions.RESET_STORE:
            return {
                sources: {},
                errors:  []
            };

        // No matching action
        default:
            return state;
    }
};
<commit_msg>Fix lint errors<commit_after>const Constants = require('./Constants');

/**
 * HyperBolts ϟ (https://hyperbolts.io)
 *
 * Copyright © 2015-present Pace IT Systems Ltd.
 * All rights reserved.
 *
 * @author  Pace IT Systems Ltd
 * @license MIT
 */

module.exports = (state = {
    sources: {},
    errors:  []
}, action) => {
    let loading = false;

    // Handle action type
    switch (action.type) {

        // Request state
        case Constants.Actions.REQUEST_STATE: {
            loading = true;

            // Check for existing cache
            const cache = state.sources[action.source] || {};

            // If we already have state for this source we need
            // to keep this intact, otherwise components will
            // temporarily blank while data is being refreshed
            if (cache !== undefined) {

                // Process array
                if (Array.isArray(cache.state) === true) {
                    action.state = action.state.splice();
                }

                // Process object
                else {
                    action.state = Object.assign({}, cache.state);
                }
            }
        }

        // Receive state
        case Constants.Actions.RECEIVE_STATE:

            // Nest state in a new object with source,
            // loading status and update timestamp
            action.state = {
                state:   action.state || [],
                source:  action.source,
                updated: Date.now(),
                error:   false,
                loading
            };

            // Return updated state
            return Object.assign({}, state, {

                // Merge into existing sources. We need to use a new
                // copy of the source object otherwise anything
                // referencing it will be updated.
                sources: Object.assign({}, state.sources, {
                    [action.source]: action.state
                })
            });

        // Error state
        case Constants.Actions.ADD_ERROR: {
            const source  = state.sources[action.source];
            const errors  = state.errors.slice();
            const sources = {};

            // If source exists, set error flag to true
            if (source !== undefined) {
                sources[action.source] = Object.assign({}, source, {
                    updated: Date.now(),
                    error:   true
                });
            }

            // Add error to stack
            errors.push({
                source:   action.source,
                error:    action.error,
                status:   action.status,
                response: action.response
            });

            // Return updated state
            return Object.assign({}, state, {
                sources: Object.assign({}, state.sources, sources),
                errors
            });
        }

        // Remove error
        case Constants.Actions.REMOVE_ERROR: {
            const errors = state.errors.slice();

            // Return updated state
            errors.splice(action.key, 1);
            return Object.assign({}, state, {
                errors
            });
        }

        // Remove errors
        case Constants.Actions.REMOVE_ERRORS:
            return Object.assign({}, state, {
                errors: []
            });

        // Reset store
        case Constants.Actions.RESET_STORE:
            return {
                sources: {},
                errors:  []
            };

        // No matching action
        default:
            return state;
    }
};
<|endoftext|>


<commit_before>$StateProvider.$inject = ['$urlRouterProvider', '$urlMatcherFactoryProvider'];
function $StateProvider(   $urlRouterProvider,   $urlMatcherFactory) {

  var root, states = {}, $state;

  function findState(stateOrName) {
    var state;
    if (isString(stateOrName)) {
      state = states[stateOrName];
      if (!state) throw new Error("No such state '" + stateOrName + "'");
    } else {
      state = states[stateOrName.name];
      if (!state || state !== stateOrName && state.self !== stateOrName) throw new Error("Invalid or unregistered state");
    }
    return state;
  }

  function registerState(state) {
    // Wrap a new object around the state so we can store our private details easily.
    state = inherit(state, {
      self: state,
      toString: function () { return this.name; },
    });

    var name = state.name;
    if (!isString(name)) throw new Error("State must have a name");
    if (states[name]) throw new Error("State '" + name + "'' is already defined");

    // Derive parent state from a hierarchical name only if 'parent' is not explicitly defined.
    var parent = root;
    if (!isDefined(state.parent)) {
      var compositeName = /^(.+)\.[^.]+$/.exec(name);
      if (compositeName != null) {
        parent = findState(compositeName[1]);
      }
    } else if (state.parent != null) {
      parent = findState(state.parent);
    }
    state.parent = parent;

    // Build a URLMatcher if necessary, either via a relative or absolute URL
    if (!state.urlMatcher && state.url != null) { // empty url is valid!
      if (state.url.charAt(0) == '^') {
        state.urlMatcher = $urlMatcherFactory.compile(state.url.substring(1));
      } else {
        var relativeTo = parent; while (!relativeTo.urlMatcher) relativeTo = relativeTo.parent;
        state.urlMatcher = relativeTo.urlMatcher.concat(state.url);
      }
    }

    // Keep track of the closest ancestor state that has a URL (i.e. is navigable)
    state.navigable = state.urlMatcher ? state : parent ? parent.navigable : null;

    // Figure out the parameters for this state and ensure they're a super-set of parent's parameters
    var params = state.params = state.urlMatcher ? state.urlMatcher.parameters() : state.parent.params;
    var paramNames = {}; forEach(params, function (p) { paramNames[p] = true; });
    if (parent) {
      forEach(parent.params, function (p) {
        if (!paramNames[p]) throw new Error("State '" + name + "' does not define parameter '" + p + "'");
        paramNames[p] = false;
      });
      var ownParams = state.ownParams = [];
      forEach(paramNames, function (own, p) { if (own) ownParams.push(p); });
    } else {
      state.ownParams = params;
    }

    // If there is no explicit multi-view configuration, make one up so we don't have
    // to handle both cases in the view directive later. Note that having an explicit
    // 'views' property will mean the default unnamed view properties are ignored. This
    // is also a good time to resolve view names to absolute names, so everything is a
    // straight lookup at link time.
    var views = {};
    forEach(!isDefined(state.views) ? { '': state } : state.views, function (view, name) {
      if (name.indexOf('@') < 0) name = name + '@' + state.parent.name;
      views[name] = view;
    });
    state.views = views;

    // Keep a full path from the root down to this state as this is needed for state activation.
    state.path = parent ? parent.path.concat(state) : []; // exclude root from path

    // Speed up $state.contains() as it's used a lot
    var includes = state.includes = parent ? extend({}, parent.includes) : {}; includes[name] = true;

    if (!state.resolve) state.resolve = {}; // prevent null checks later

    // Register the state in the global state list and with $urlRouter if necessary.
    if (!state.abstract && state.urlMatcher) {
      $urlRouterProvider.when(state.urlMatcher, function (params) {
        $state.transitionTo(state, params, false);
      });
    }
    return states[name] = state;
  }

  // Implicit root state that is always active
  root = registerState({
    name: '',
    url: '^',
    views: null,
    abstract: true,
  });
  root.locals = {};

  // .state(state)
  // .state(name, state)
  this.state = function (name, state) {
    if (isObject(name)) state = name;
    else state.name = name;
    registerState(state);
    return this;
  };

  this.$get =
    // We don't need access to $urlRouter directly but we need to ensure it gets instantiated.
    [        '$stateParams', '$rootScope', '$q', '$templateFactory', '$injector', '$urlRouter', '$location',
    function ($stateParams,   $rootScope,   $q,   $templateFactory,   $injector,   $urlRouter,   $location) {
      $state = {
        params: {},
        current: root.self,
        $current: root,
        $transition: $q.when(root.self),

        transitionTo: transitionTo,

        is: function (stateOrName) {
          return $state.$current === findState(stateOrName);
        },
        includes: function (stateOrName) {
          return $state.$current.includes[findState(stateOrName).name];
        },
      };

      function transitionTo(to, toParams, updateLocation) {
        if (!isDefined(updateLocation)) updateLocation = true;

        to = findState(to); if (to.abstract) throw new Error("Cannot transition to abstract state '" + to + "'");
        var toPath = to.path, from = $state.$current, fromParams = $state.params, fromPath = from.path;

        // Starting from the root of the path, keep all levels that haven't changed
        var keep, state, locals = root.locals, toLocals = [];
        for (keep = 0, state = toPath[keep];
             state && state === fromPath[keep] && equalForKeys(toParams, fromParams, state.ownParams);
             keep++, state = toPath[keep]) {
          locals = toLocals[keep] = state.locals;
        }

        // If we're going to the same state and all locals are kept, we've got nothing to do. But
        // update 'transition' anyway, as we still want to cancel any other pending transitions.
        // TODO: We may not want to bump 'transition' if we're called from a location change that we've initiated ourselves,
        // because we might accidentally abort a legitimate transition initiated from code?
        if (to === from && locals === from.locals) {
          return $state.$transition = $q.when($state.current);
        }

        // TODO: should we be passing from and to $stateParams as well?
        $rootScope.$broadcast('$stateChangeStart', to.self, from.self);

        // Resolve locals for the remaining states, but don't update any global state just
        // yet -- if anything fails to resolve the current state needs to remain untouched.
        // We also set up an inheritance chain for the locals here. This allows the view directive
        // to quickly look up the correct definition for each view in the current state. Even
        // though we create the locals object itself outside resolveState(), it is initially
        // empty and gets filled asynchronously. We need to keep track of the promise for the
        // (fully resolved) current locals, and pass this down the chain.
        var resolved = $q.when(locals);
        for (var l=keep; l<toPath.length; l++, state=toPath[l]) {
          locals = toLocals[l] = (locals ? inherit(locals) : {});
          resolved = resolveState(state, toParams, resolved, locals);
        }

        // Once everything is resolved, we are ready to perform the actual transition
        // and return a promise for the new state. We also keep track of what the
        // current promise is, so that we can detect overlapping transitions and
        // keep only the outcome of the last transition.
        var transition = $state.transition = resolved.then(function () {
          var l, entering, exiting;

          if ($state.transition !== transition) return; // superseded by a new transition

          // Exit 'from' states not kept
          for (l=fromPath.length-1; l>=keep; l--) {
            exiting = fromPath[l];
            if (exiting.self.onExit) {
              $injector.invoke(exiting.self.onExit, exiting.self, exiting.locals.globals);
            }
            exiting.locals = null;
          }

          // Enter 'to' states not kept
          // TODO: Should we be invoking onEnter in a separate pass after we've updated $state and $location?
          for (l=keep; l<toPath.length; l++) {
            entering = toPath[l];
            entering.locals = toLocals[l];
            if (entering.self.onEnter) {
              $injector.invoke(entering.self.onEnter, entering.self, entering.locals.globals);
            }
          }

          // Update globals in $state
          $state.$current = to;
          $state.current = to.self;
          $state.params = locals.globals.$stateParams; // these are normalized, unlike toParams
          copy($state.params, $stateParams);

          // Update $location
          var toNav = to.navigable;
          if (updateLocation && toNav) {
            $location.url(toNav.urlMatcher.format(toNav.locals.globals.$stateParams));
          }

          $rootScope.$broadcast('$stateChangeSuccess', to.self, from.self);
          return $state.current;
        }, function (error) {
          if ($state.transition !== transition) return; // superseded by a new transition
          $rootScope.$broadcast('$stateChangeError', to.self, from.self, error);
          return $q.reject(error);
        });

        return transition;
      }

      function resolveState(state, params, inherited, dst) {
        // We need to track all the promises generated during the resolution process.
        // The first of these is for the fully resolved parent locals.
        var promises = [ inherited ];

        // Make a restricted $stateParams with only the parameters that apply to this state, and
        // force them all to strings while we're at it. In addition to being available to the
        // controller and onEnter/onExit callbacks, we also need $stateParams to be available
        // for any $injector calls we make during the dependency resolution process.
        var $stateParams = {};
        var locals = { $stateParams: $stateParams };
        forEach(state.params, function (name) {
          var value = params[name];
          $stateParams[name] = (params[name] != null) ? String(value) : null;
        });

        function resolve(deps, dst) {
          forEach(deps, function (value, key) {
            promises.push($q
              .when(isString(value) ? $injector.get(value) : $injector.invoke(value, locals))
              .then(function (result) {
                dst[key] = result;
              }));
          });
        }

        // Resolve 'global' dependencies for the state, i.e. those not specific to a view.
        // We're also including $stateParams in this; that we're the parameters are restricted
        // to the set that should be visible to the state, and are independent of when we update
        // the global $state and $stateParams values.
        var globals = dst.globals = { $stateParams: $stateParams };
        resolve(state.resolve, globals);
        globals.$$state = state; // Provide access to the state itself for internal use

        // Resolve template and dependencies for all views. Each view receives
        // its own dependencies, which are set up to inherit from the state's deps,
        // and are accessible from the state locals as '$$view$<name>'.
        forEach(state.views, function (view, name) {
          // References to the controller (only instantiated at link time)
          var $view = dst[name] = {
            $$controller: view.controller
          };

          // Template
          promises.push($q
            .when($templateFactory.fromConfig(view, $stateParams, locals) || '')
            .then(function (result) {
              $view.$template = result;
            }));

          // View-local dependencies
          resolve(view.resolve, $view);
        });

        // Once we've resolved all the dependencies for this state, merge
        // in any inherited dependencies, and merge common state dependencies
        // into the dependency set for each view. Finally return a promise
        // for the fully popuplated state dependencies.
        return $q.all(promises).then(function (values) {
          merge(dst.globals, values[0].globals); // promises[0] === inherited
          forEach(state.views, function (view, name) {
            merge(dst[name], dst.globals);
          });
          return dst;
        });
      }

      function equalForKeys(a, b, keys) {
        for (var i=0; i<keys.length; i++) {
          var k = keys[i];
          if (a[k] != b[k]) return false; // Not '===', values aren't necessarily normalized
        }
        return true;
      }

      return $state;
    }];
}

angular.module('ui.state')
  .value('$stateParams', {})
  .provider('$state', $StateProvider);
<commit_msg>style<commit_after>$StateProvider.$inject = ['$urlRouterProvider', '$urlMatcherFactoryProvider'];
function $StateProvider(   $urlRouterProvider,   $urlMatcherFactory) {

  var root, states = {}, $state;

  function findState(stateOrName) {
    var state;
    if (isString(stateOrName)) {
      state = states[stateOrName];
      if (!state) throw new Error("No such state '" + stateOrName + "'");
    } else {
      state = states[stateOrName.name];
      if (!state || state !== stateOrName && state.self !== stateOrName) throw new Error("Invalid or unregistered state");
    }
    return state;
  }

  function registerState(state) {
    // Wrap a new object around the state so we can store our private details easily.
    state = inherit(state, {
      self: state,
      toString: function () { return this.name; },
    });

    var name = state.name;
    if (!isString(name)) throw new Error("State must have a name");
    if (states[name]) throw new Error("State '" + name + "'' is already defined");

    // Derive parent state from a hierarchical name only if 'parent' is not explicitly defined.
    var parent = root;
    if (!isDefined(state.parent)) {
      var compositeName = /^(.+)\.[^.]+$/.exec(name);
      if (compositeName != null) {
        parent = findState(compositeName[1]);
      }
    } else if (state.parent != null) {
      parent = findState(state.parent);
    }
    state.parent = parent;

    // Build a URLMatcher if necessary, either via a relative or absolute URL
    if (!state.urlMatcher && state.url != null) { // empty url is valid!
      if (state.url.charAt(0) == '^') {
        state.urlMatcher = $urlMatcherFactory.compile(state.url.substring(1));
      } else {
        var relativeTo = parent; while (!relativeTo.urlMatcher) relativeTo = relativeTo.parent;
        state.urlMatcher = relativeTo.urlMatcher.concat(state.url);
      }
    }

    // Keep track of the closest ancestor state that has a URL (i.e. is navigable)
    state.navigable = state.urlMatcher ? state : parent ? parent.navigable : null;

    // Figure out the parameters for this state and ensure they're a super-set of parent's parameters
    var params = state.params = state.urlMatcher ? state.urlMatcher.parameters() : state.parent.params;
    var paramNames = {}; forEach(params, function (p) { paramNames[p] = true; });
    if (parent) {
      forEach(parent.params, function (p) {
        if (!paramNames[p]) throw new Error("State '" + name + "' does not define parameter '" + p + "'");
        paramNames[p] = false;
      });
      var ownParams = state.ownParams = [];
      forEach(paramNames, function (own, p) { if (own) ownParams.push(p); });
    } else {
      state.ownParams = params;
    }

    // If there is no explicit multi-view configuration, make one up so we don't have
    // to handle both cases in the view directive later. Note that having an explicit
    // 'views' property will mean the default unnamed view properties are ignored. This
    // is also a good time to resolve view names to absolute names, so everything is a
    // straight lookup at link time.
    var views = {};
    forEach(!isDefined(state.views) ? { '': state } : state.views, function (view, name) {
      if (name.indexOf('@') < 0) name = name + '@' + state.parent.name;
      views[name] = view;
    });
    state.views = views;

    // Keep a full path from the root down to this state as this is needed for state activation.
    state.path = parent ? parent.path.concat(state) : []; // exclude root from path

    // Speed up $state.contains() as it's used a lot
    var includes = state.includes = parent ? extend({}, parent.includes) : {}; includes[name] = true;

    if (!state.resolve) state.resolve = {}; // prevent null checks later

    // Register the state in the global state list and with $urlRouter if necessary.
    if (!state.abstract && state.urlMatcher) {
      $urlRouterProvider.when(state.urlMatcher, function (params) {
        $state.transitionTo(state, params, false);
      });
    }
    return states[name] = state;
  }

  // Implicit root state that is always active
  root = registerState({
    name: '',
    url: '^',
    views: null,
    abstract: true,
  });
  root.locals = {};

  // .state(state)
  // .state(name, state)
  this.state = state;
  function state(name, state) {
    if (isObject(name)) state = name;
    else state.name = name;
    registerState(state);
    return this;
  }

  // $urlRouter is injected just to ensure it gets instantiated
  this.$get = $get;
  $get.$inject = ['$rootScope', '$q', '$templateFactory', '$injector', '$stateParams', '$location', '$urlRouter'];
  function $get(   $rootScope,   $q,   $templateFactory,   $injector,   $stateParams,   $location,   $urlRouter) {

    $state = {
      params: {},
      current: root.self,
      $current: root,
      $transition: $q.when(root.self),

      transitionTo: transitionTo,

      is: function (stateOrName) {
        return $state.$current === findState(stateOrName);
      },
      includes: function (stateOrName) {
        return $state.$current.includes[findState(stateOrName).name];
      },
    };

    function transitionTo(to, toParams, updateLocation) {
      if (!isDefined(updateLocation)) updateLocation = true;

      to = findState(to); if (to.abstract) throw new Error("Cannot transition to abstract state '" + to + "'");
      var toPath = to.path, from = $state.$current, fromParams = $state.params, fromPath = from.path;

      // Starting from the root of the path, keep all levels that haven't changed
      var keep, state, locals = root.locals, toLocals = [];
      for (keep = 0, state = toPath[keep];
           state && state === fromPath[keep] && equalForKeys(toParams, fromParams, state.ownParams);
           keep++, state = toPath[keep]) {
        locals = toLocals[keep] = state.locals;
      }

      // If we're going to the same state and all locals are kept, we've got nothing to do. But
      // update 'transition' anyway, as we still want to cancel any other pending transitions.
      // TODO: We may not want to bump 'transition' if we're called from a location change that we've initiated ourselves,
      // because we might accidentally abort a legitimate transition initiated from code?
      if (to === from && locals === from.locals) {
        return $state.$transition = $q.when($state.current);
      }

      // TODO: should we be passing from and to $stateParams as well?
      $rootScope.$broadcast('$stateChangeStart', to.self, from.self);

      // Resolve locals for the remaining states, but don't update any global state just
      // yet -- if anything fails to resolve the current state needs to remain untouched.
      // We also set up an inheritance chain for the locals here. This allows the view directive
      // to quickly look up the correct definition for each view in the current state. Even
      // though we create the locals object itself outside resolveState(), it is initially
      // empty and gets filled asynchronously. We need to keep track of the promise for the
      // (fully resolved) current locals, and pass this down the chain.
      var resolved = $q.when(locals);
      for (var l=keep; l<toPath.length; l++, state=toPath[l]) {
        locals = toLocals[l] = (locals ? inherit(locals) : {});
        resolved = resolveState(state, toParams, resolved, locals);
      }

      // Once everything is resolved, we are ready to perform the actual transition
      // and return a promise for the new state. We also keep track of what the
      // current promise is, so that we can detect overlapping transitions and
      // keep only the outcome of the last transition.
      var transition = $state.transition = resolved.then(function () {
        var l, entering, exiting;

        if ($state.transition !== transition) return; // superseded by a new transition

        // Exit 'from' states not kept
        for (l=fromPath.length-1; l>=keep; l--) {
          exiting = fromPath[l];
          if (exiting.self.onExit) {
            $injector.invoke(exiting.self.onExit, exiting.self, exiting.locals.globals);
          }
          exiting.locals = null;
        }

        // Enter 'to' states not kept
        // TODO: Should we be invoking onEnter in a separate pass after we've updated $state and $location?
        for (l=keep; l<toPath.length; l++) {
          entering = toPath[l];
          entering.locals = toLocals[l];
          if (entering.self.onEnter) {
            $injector.invoke(entering.self.onEnter, entering.self, entering.locals.globals);
          }
        }

        // Update globals in $state
        $state.$current = to;
        $state.current = to.self;
        $state.params = locals.globals.$stateParams; // these are normalized, unlike toParams
        copy($state.params, $stateParams);

        // Update $location
        var toNav = to.navigable;
        if (updateLocation && toNav) {
          $location.url(toNav.urlMatcher.format(toNav.locals.globals.$stateParams));
        }

        $rootScope.$broadcast('$stateChangeSuccess', to.self, from.self);
        return $state.current;
      }, function (error) {
        if ($state.transition !== transition) return; // superseded by a new transition
        $rootScope.$broadcast('$stateChangeError', to.self, from.self, error);
        return $q.reject(error);
      });

      return transition;
    }

    function resolveState(state, params, inherited, dst) {
      // We need to track all the promises generated during the resolution process.
      // The first of these is for the fully resolved parent locals.
      var promises = [ inherited ];

      // Make a restricted $stateParams with only the parameters that apply to this state, and
      // force them all to strings while we're at it. In addition to being available to the
      // controller and onEnter/onExit callbacks, we also need $stateParams to be available
      // for any $injector calls we make during the dependency resolution process.
      var $stateParams = {};
      var locals = { $stateParams: $stateParams };
      forEach(state.params, function (name) {
        var value = params[name];
        $stateParams[name] = (params[name] != null) ? String(value) : null;
      });

      // Resolves the values from an individual 'resolve' dependency spec
      function resolve(deps, dst) {
        forEach(deps, function (value, key) {
          promises.push($q
            .when(isString(value) ? $injector.get(value) : $injector.invoke(value, locals))
            .then(function (result) {
              dst[key] = result;
            }));
        });
      }

      // Resolve 'global' dependencies for the state, i.e. those not specific to a view.
      // We're also including $stateParams in this; that we're the parameters are restricted
      // to the set that should be visible to the state, and are independent of when we update
      // the global $state and $stateParams values.
      var globals = dst.globals = { $stateParams: $stateParams };
      resolve(state.resolve, globals);
      globals.$$state = state; // Provide access to the state itself for internal use

      // Resolve template and dependencies for all views. Each view receives
      // its own dependencies, which are set up to inherit from the state's deps,
      // and are accessible from the state locals as '$$view$<name>'.
      forEach(state.views, function (view, name) {
        // References to the controller (only instantiated at link time)
        var $view = dst[name] = {
          $$controller: view.controller
        };

        // Template
        promises.push($q
          .when($templateFactory.fromConfig(view, $stateParams, locals) || '')
          .then(function (result) {
            $view.$template = result;
          }));

        // View-local dependencies
        resolve(view.resolve, $view);
      });

      // Once we've resolved all the dependencies for this state, merge
      // in any inherited dependencies, and merge common state dependencies
      // into the dependency set for each view. Finally return a promise
      // for the fully popuplated state dependencies.
      return $q.all(promises).then(function (values) {
        merge(dst.globals, values[0].globals); // promises[0] === inherited
        forEach(state.views, function (view, name) {
          merge(dst[name], dst.globals);
        });
        return dst;
      });
    }

    function equalForKeys(a, b, keys) {
      for (var i=0; i<keys.length; i++) {
        var k = keys[i];
        if (a[k] != b[k]) return false; // Not '===', values aren't necessarily normalized
      }
      return true;
    }

    return $state;
  }
}

angular.module('ui.state')
  .value('$stateParams', {})
  .provider('$state', $StateProvider);
<|endoftext|>


<commit_before>var App = angular.module('App', ['ngResource']);

App.config(['$interpolateProvider', '$httpProvider', function($interpolateProvider, $httpProvider) {
  // New symbols to prevent interference with Django templating language
  $interpolateProvider.startSymbol('{$');
  $interpolateProvider.endSymbol('$}');

  $httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
  $httpProvider.defaults.xsrfCookieName = 'csrftoken';
}]);

// Bootstrap active tab helper
App.directive('isActive', function() {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
      if (attrs.href === window.location.pathname) {
        element.parent().addClass('active');
      }
    }
  };
});

// Still uses the data-content attr for content
App.directive('popover', function() {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
      options = {
        trigger: 'hover'
      };
      $(element).popover(options);
    }
  };
});

// Form Validation helper
App.directive('hasError', function() {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
      var formGroup = $(element);
      var error = formGroup.find('.label.label-danger');
      if (error.length > 0 && !error.is(':empty')) {
        formGroup.addClass('has-error');
      }
    }
  };
});

// Add a Bootstrap tooltip
App.directive('tooltip', function() {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
      $(element).tooltip();
    }
  };
});

// Helper for notifications and list-item-icons
App.directive('hasRecords', function() {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
      // Compare it with the python bool
      if (attrs.records == 'False') {
        element.addClass('no-records');
      }
    }
  };
});

App.directive('loading', function($http) {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
      scope.isLoading = function() {
        return $http.pendingRequests.length > 0;
      };

      loader = $('#loader').clone();

      scope.$watch(scope.isLoading, function(v) {
        if (v) {
          element.append(loader.show());
        } else {
          $(element).find('#loader').remove();
        }
      });
    }
  };
});

App.factory('Choropleth', ['$resource', function($resource) {
  return $resource('/choropleths/api/:id/ ', { id: '@id' }, {
    update: {
      method: 'PUT'
    }
  });
}]);

// Resource for Dataset
App.factory('Dataset', ['$resource', function($resource) {
  return $resource('/datasets/api/:id/ ');
}]);

// Resource for Palettes
App.factory('Palettes', ['$resource', function($resource) {
  return $resource('/choropleths/api/palettes/:id/ ');
}]);

App.controller('DatasetTableController', ['$scope', '$http', 'Dataset', function($scope, $http, Dataset) {

  $scope.init = function(id) {
    Dataset.get({id: id}, function(data) {
      $scope.dataset = data;
    });

    $scope.reverse = false;
    $scope.sortOrder='name';
  };

}]);

App.directive('progressBar', function() {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
      console.log(attrs);
      $(element).width(attrs.progressBar);
    }
  };
});

<commit_msg>Add capability to display loader with a HTTP Request in addition to to an Ajax Request.<commit_after>var App = angular.module('App', ['ngResource']);

App.config(['$interpolateProvider', '$httpProvider', function($interpolateProvider, $httpProvider) {
  // New symbols to prevent interference with Django templating language
  $interpolateProvider.startSymbol('{$');
  $interpolateProvider.endSymbol('$}');

  $httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
  $httpProvider.defaults.xsrfCookieName = 'csrftoken';
}]);

// Bootstrap active tab helper
App.directive('isActive', function() {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
      if (attrs.href === window.location.pathname) {
        element.parent().addClass('active');
      }
    }
  };
});

// Still uses the data-content attr for content
App.directive('popover', function() {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
      options = {
        trigger: 'hover'
      };
      $(element).popover(options);
    }
  };
});

// Form Validation helper
App.directive('hasError', function() {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
      var formGroup = $(element);
      var error = formGroup.find('.label.label-danger');
      if (error.length > 0 && !error.is(':empty')) {
        formGroup.addClass('has-error');
      }
    }
  };
});

// Add a Bootstrap tooltip
App.directive('tooltip', function() {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
      $(element).tooltip();
    }
  };
});

// Helper for notifications and list-item-icons
App.directive('hasRecords', function() {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
      // Compare it with the python bool
      if (attrs.records == 'False') {
        element.addClass('no-records');
      }
    }
  };
});

// Ajax loader
App.directive('loading', function($http) {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
      var loader = $('#loader').clone();

      if (attrs.loading === 'http') {
          element.append(loader.show());
        return;
      }

      scope.isLoading = function() {
        return $http.pendingRequests.length > 0;
      };

      scope.$watch(scope.isLoading, function(v) {
        if (v) {
          element.append(loader.show());
        } else {
          $(element).find('#loader').remove();
        }
      });
    }
  };
});

App.factory('Choropleth', ['$resource', function($resource) {
  return $resource('/choropleths/api/:id/ ', { id: '@id' }, {
    update: {
      method: 'PUT'
    }
  });
}]);

// Resource for Dataset
App.factory('Dataset', ['$resource', function($resource) {
  return $resource('/datasets/api/:id/ ');
}]);

// Resource for Palettes
App.factory('Palettes', ['$resource', function($resource) {
  return $resource('/choropleths/api/palettes/:id/ ');
}]);

App.controller('DatasetTableController', ['$scope', '$http', 'Dataset', function($scope, $http, Dataset) {

  $scope.init = function(id) {
    Dataset.get({id: id}, function(data) {
      $scope.dataset = data;
    });

    $scope.reverse = false;
    $scope.sortOrder='name';
  };

}]);

App.directive('progressBar', function() {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
      console.log(attrs);
      $(element).width(attrs.progressBar);
    }
  };
});

<|endoftext|>