|
|
|
var module = angular.module('cryto.jsde', ["frapontillo.ex.filters", "ngRoute"]);
|
|
|
|
|
|
|
|
module.factory("jsdeRouteManager", function($routeProvider, $q) {
|
|
|
|
/* This is a partial reimplementation of the routeProvider, and uses part of that.
|
|
|
|
* Since they already have routing figured out, we might as well implement a
|
|
|
|
* modified version that works on a window level. */
|
|
|
|
var obj = {};
|
|
|
|
|
|
|
|
obj.routes = {};
|
|
|
|
|
|
|
|
obj.getParams = function(target) {
|
|
|
|
var parts = target.split("?");
|
|
|
|
keyValue = parts[1];
|
|
|
|
return angular.parseKeyValue(keyValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Modified from angular router */
|
|
|
|
obj.parseRoute = function(target, routes) {
|
|
|
|
// Match a route
|
|
|
|
var params, match;
|
|
|
|
angular.forEach(routes, function(route, path) {
|
|
|
|
if (!match && (params = $routeProvider.switchRouteMatcher(target, route))) {
|
|
|
|
match = $routeProvider.inherit(route, {
|
|
|
|
params: angular.extend({}, obj.getParams(target), params),
|
|
|
|
pathParams: params});
|
|
|
|
match.$$route = route;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
// No route matched; fallback to "otherwise" route
|
|
|
|
return match || routes[null] && $routeProvider.inherit(routes[null], {params: {}, pathParams:{}});
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Modified from angular router */
|
|
|
|
obj.updateRoute = function(scope, element) {
|
|
|
|
var next = obj.parseRoute(scope.path, obj.routes);
|
|
|
|
var last = obj.lastRoute;
|
|
|
|
|
|
|
|
if (next && last && next.$$route === last.$$route
|
|
|
|
&& angular.equals(next.pathParams, last.pathParams)) {
|
|
|
|
last.params = next.params;
|
|
|
|
angular.copy(last.params, scope.params); // this sets the current route parameters so that other stuff can access it
|
|
|
|
} else if (next || last) {
|
|
|
|
obj.lastRoute = next;
|
|
|
|
|
|
|
|
// actually change route
|
|
|
|
var controller = next.$$route.controller;
|
|
|
|
|
|
|
|
if (angular.isDefined(template = next.template)) {
|
|
|
|
if (angular.isFunction(template)) {
|
|
|
|
template = template(next.params);
|
|
|
|
}
|
|
|
|
} else if (angular.isDefined(templateUrl = next.templateUrl)) {
|
|
|
|
if (angular.isFunction(templateUrl)) {
|
|
|
|
templateUrl = templateUrl(next.params);
|
|
|
|
}
|
|
|
|
templateUrl = $sce.getTrustedResourceUrl(templateUrl);
|
|
|
|
if (angular.isDefined(templateUrl)) {
|
|
|
|
next.loadedTemplateUrl = templateUrl;
|
|
|
|
var template = $http.get(templateUrl, {cache: $templateCache}).
|
|
|
|
then(function(response) { return response.data; });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var container = element.find(".window-inner");
|
|
|
|
container.html(template);
|
|
|
|
container.data('$ngControllerController', controller);
|
|
|
|
container.children().data('$ngControllerController', controller);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
obj.when = function(path, route) {
|
|
|
|
routes[path] = angular.extend(
|
|
|
|
{reloadOnSearch: true},
|
|
|
|
route,
|
|
|
|
path && $routeProvider.pathRegExp(path, route)
|
|
|
|
);
|
|
|
|
|
|
|
|
// create redirection for trailing slashes
|
|
|
|
if (path) {
|
|
|
|
var redirectPath = (path[path.length-1] == '/')
|
|
|
|
? path.substr(0, path.length-1)
|
|
|
|
: path +'/';
|
|
|
|
|
|
|
|
routes[redirectPath] = angular.extend(
|
|
|
|
{redirectTo: path},
|
|
|
|
$routeProvider.pathRegExp(redirectPath, route)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
});
|
|
|
|
|
|
|
|
module.factory("manager", function($document, defaultFilter){
|
|
|
|
var obj = {};
|
|
|
|
|
|
|
|
obj.next_z_index = 0;
|
|
|
|
obj.next_id = 0;
|
|
|
|
obj.windows = {};
|
|
|
|
obj.drag_mode = "none";
|
|
|
|
obj.dragged_window = null;
|
|
|
|
obj.dragged_scope = null;
|
|
|
|
obj.drag_offset = null;
|
|
|
|
|
|
|
|
obj.disablePageSelection = function() {
|
|
|
|
angular.element("body")
|
|
|
|
.attr('unselectable', 'on')
|
|
|
|
.css('user-select', 'none')
|
|
|
|
.on('selectstart', false);
|
|
|
|
};
|
|
|
|
|
|
|
|
obj.enablePageSelection = function() {
|
|
|
|
angular.element("body")
|
|
|
|
.attr('unselectable', 'off')
|
|
|
|
.css('user-select', 'text')
|
|
|
|
.off('selectstart');
|
|
|
|
};
|
|
|
|
|
|
|
|
obj.getNextZIndex = function()
|
|
|
|
{
|
|
|
|
obj.next_z_index += 1;
|
|
|
|
return obj.next_z_index - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
obj.addWindow = function(scope, element)
|
|
|
|
{
|
|
|
|
var id = obj.next_id;
|
|
|
|
obj.windows[id] = {scope: scope, element: element};
|
|
|
|
obj.next_id += 1;
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
obj.removeWindow = function(scope, element)
|
|
|
|
{
|
|
|
|
delete obj.windows[id];
|
|
|
|
}
|
|
|
|
|
|
|
|
obj.setAllUnfocused = function()
|
|
|
|
{
|
|
|
|
for(i in obj.windows)
|
|
|
|
{
|
|
|
|
obj.windows[i].scope.focused = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$document.on("mousemove", function(event){
|
|
|
|
if(obj.drag_mode == "move")
|
|
|
|
{
|
|
|
|
var new_x = event.pageX - obj.drag_offset.x;
|
|
|
|
var new_y = event.pageY - obj.drag_offset.y;
|
|
|
|
|
|
|
|
obj.dragged_scope.x = new_x;
|
|
|
|
obj.dragged_scope.y = new_y;
|
|
|
|
|
|
|
|
obj.dragged_scope.$apply();
|
|
|
|
}
|
|
|
|
else if(obj.drag_mode == "resize")
|
|
|
|
{
|
|
|
|
var new_width = event.pageX - obj.drag_offset.x;
|
|
|
|
var new_height = event.pageY - obj.drag_offset.y;
|
|
|
|
|
|
|
|
if(typeof obj.dragged_scope.minWidth !== "undefined" && new_width < obj.dragged_scope.minWidth)
|
|
|
|
{
|
|
|
|
new_width = obj.dragged_scope.minWidth;
|
|
|
|
}
|
|
|
|
else if(typeof obj.dragged_scope.maxWidth !== "undefined" && new_width > obj.dragged_scope.maxWidth)
|
|
|
|
{
|
|
|
|
new_width = obj.dragged_scope.maxWidth;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(typeof obj.dragged_scope.minHeight !== "undefined" && new_height < obj.dragged_scope.minHeight)
|
|
|
|
{
|
|
|
|
new_height = obj.dragged_scope.minHeight;
|
|
|
|
}
|
|
|
|
else if(typeof obj.dragged_scope.maxHeight !== "undefined" && new_height > obj.dragged_scope.maxHeight)
|
|
|
|
{
|
|
|
|
new_height = obj.dragged_scope.maxHeight;
|
|
|
|
}
|
|
|
|
|
|
|
|
obj.dragged_scope.width = new_width;
|
|
|
|
obj.dragged_scope.height = new_height;
|
|
|
|
|
|
|
|
obj.dragged_scope.$apply();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
$document.on("mouseup", function(event){
|
|
|
|
if(obj.drag_mode == "move" || obj.drag_mode == "resize")
|
|
|
|
{
|
|
|
|
obj.drag_mode = "none";
|
|
|
|
obj.drag_offset = null;
|
|
|
|
obj.enablePageSelection();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
obj.resolvePath = function(path) {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return obj;
|
|
|
|
});
|
|
|
|
|
|
|
|
module.directive("jsdeWindow", function(manager, defaultFilter, jsdeRouteProvider){
|
|
|
|
return {
|
|
|
|
restrict: "E",
|
|
|
|
transclude: true,
|
|
|
|
templateUrl: "templates/angular/jsde-window.html",
|
|
|
|
scope: {
|
|
|
|
title: "@",
|
|
|
|
start_width: "@",
|
|
|
|
start_height: "@",
|
|
|
|
start_x: "@x",
|
|
|
|
start_y: "@y",
|
|
|
|
minWidth: "@",
|
|
|
|
minHeight: "@",
|
|
|
|
maxWidth: "@",
|
|
|
|
maxHeight: "@",
|
|
|
|
onScroll: "&",
|
|
|
|
onClose: "&",
|
|
|
|
visible: "@",
|
|
|
|
_path: "@path"
|
|
|
|
},
|
|
|
|
link: function(scope, element, attrs) {
|
|
|
|
manager.addWindow(scope, element);
|
|
|
|
|
|
|
|
scope.x = scope.start_x;
|
|
|
|
scope.y = scope.start_y;
|
|
|
|
|
|
|
|
scope.width = scope.start_width;
|
|
|
|
scope.height = scope.start_height;
|
|
|
|
|
|
|
|
scope.defaults = {
|
|
|
|
x: 48,
|
|
|
|
y: 48,
|
|
|
|
width: 400,
|
|
|
|
height: 300
|
|
|
|
}
|
|
|
|
|
|
|
|
scope.$watch("_path", function(){
|
|
|
|
scope.path = scope._path;
|
|
|
|
});
|
|
|
|
|
|
|
|
scope.$watch("path", function(){
|
|
|
|
/* Update the view/controller pair for this path */
|
|
|
|
jsdeRouteProvider.updateRoute(scope, element);
|
|
|
|
})
|
|
|
|
|
|
|
|
/* Set the initial z-index, this is to prevent glitches when clicking overlapping windows
|
|
|
|
* in the same starting position */
|
|
|
|
element.find(".window-wrapper").css({"z-index": manager.getNextZIndex()});
|
|
|
|
|
|
|
|
/* Set the initial focus. */
|
|
|
|
manager.setAllUnfocused();
|
|
|
|
scope.focused = true;
|
|
|
|
|
|
|
|
/* When any part of a window is clicked, it's raised to the top and set to 'focused'. */
|
|
|
|
element.on("mousedown", function(){
|
|
|
|
element.find(".window-wrapper").css({"z-index": manager.getNextZIndex()});
|
|
|
|
manager.setAllUnfocused();
|
|
|
|
scope.focused = true;
|
|
|
|
scope.$apply();
|
|
|
|
});
|
|
|
|
|
|
|
|
element.find(".window-title").on("mousedown", function(event){
|
|
|
|
/* Dragging is centrally managed by the JsdeManager, to prevent conflicts where
|
|
|
|
* two windows are in a 'dragging' state at the same time due to an event not
|
|
|
|
* firing. Developing for browsers isn't always roses and sunshine... */
|
|
|
|
manager.drag_mode = "move";
|
|
|
|
manager.dragged_window = element;
|
|
|
|
manager.dragged_scope = scope;
|
|
|
|
manager.drag_offset = {x: event.pageX - defaultFilter(scope.x, scope.defaults.x), y: event.pageY - defaultFilter(scope.y, scope.defaults.y)};
|
|
|
|
manager.disablePageSelection();
|
|
|
|
});
|
|
|
|
|
|
|
|
element.find(".window-resizer").on("mousedown", function(event){
|
|
|
|
/* Dragging is centrally managed by the JsdeManager, to prevent conflicts where
|
|
|
|
* two windows are in a 'dragging' state at the same time due to an event not
|
|
|
|
* firing. Developing for browsers isn't always roses and sunshine... */
|
|
|
|
manager.drag_mode = "resize";
|
|
|
|
manager.dragged_window = element;
|
|
|
|
manager.dragged_scope = scope;
|
|
|
|
manager.drag_offset = {x: event.pageX - defaultFilter(scope.width, scope.defaults.width), y: event.pageY - defaultFilter(scope.height, scope.defaults.height)};
|
|
|
|
manager.disablePageSelection();
|
|
|
|
});
|
|
|
|
|
|
|
|
element.find(".window-title .window-close a").on("click", function(event){
|
|
|
|
scope.$apply(function(){
|
|
|
|
scope.visible = false;
|
|
|
|
scope.onClose();
|
|
|
|
});
|
|
|
|
})
|
|
|
|
|
|
|
|
scope.$watch("visible", function(newValue, oldValue){
|
|
|
|
if(newValue !== oldValue)
|
|
|
|
{
|
|
|
|
if(newValue == true || newValue == "true") /* What the fuck? */
|
|
|
|
{
|
|
|
|
scope.$emit("jsdeWindowOpened");
|
|
|
|
console.log("jsdeWindowOpened");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
scope.$emit("jsdeWindowClosed");
|
|
|
|
console.log("jsdeWindowClosed");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
scope.path = "/";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
module.directive("jsdeNotification", function(){
|
|
|
|
return {
|
|
|
|
restrict: "E",
|
|
|
|
transclude: true,
|
|
|
|
templateUrl: "templates/angular/jsde-notification.html",
|
|
|
|
link: function(scope, element, attrs) {
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
module.directive("jsdeError", function(){
|
|
|
|
return {
|
|
|
|
restrict: "E",
|
|
|
|
transclude: true,
|
|
|
|
templateUrl: "templates/angular/jsde-error.html",
|
|
|
|
link: function(scope, element, attrs) {
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|