diff --git a/client/cat3/main.html b/client/cat3/main.html index f55d9bff2..b3619babc 100644 --- a/client/cat3/main.html +++ b/client/cat3/main.html @@ -36,9 +36,6 @@ - - - diff --git a/client/cat3/src/main.js b/client/cat3/src/main.js index 5b0fde688..b1dc91af7 100644 --- a/client/cat3/src/main.js +++ b/client/cat3/src/main.js @@ -12,7 +12,7 @@ * All modules/feature will be through * */ -var angularApp = angular.module('catapp', ['ui.router','ngTouch','toastr','firebase', +var angularApp = angular.module('catapp', ['ui.router','ngTouch','toastr', 'global.login', 'global.breadcrumb', 'authentication', diff --git a/client/cat3/src/partials/globals/drag-and-drop/angular-drag-and-drop-lists.min.js b/client/cat3/src/partials/globals/drag-and-drop/angular-drag-and-drop-lists.min.js deleted file mode 100644 index 46c5a2d4a..000000000 --- a/client/cat3/src/partials/globals/drag-and-drop/angular-drag-and-drop-lists.min.js +++ /dev/null @@ -1,590 +0,0 @@ -/** - * angular-drag-and-drop-lists v1.4.0 - * - * Copyright (c) 2014 Marcel Juenemann marcel@juenemann.cc - * Copyright (c) 2014-2016 Google Inc. - * https://github.com/marceljuenemann/angular-drag-and-drop-lists - * - * License: MIT - */ -angular.module('dndLists', []) - - /** - * Use the dnd-draggable attribute to make your element draggable - * - * Attributes: - * - dnd-draggable Required attribute. The value has to be an object that represents the data - * of the element. In case of a drag and drop operation the object will be - * serialized and unserialized on the receiving end. - * - dnd-selected Callback that is invoked when the element was clicked but not dragged. - * The original click event will be provided in the local event variable. - * - dnd-effect-allowed Use this attribute to limit the operations that can be performed. Options: - * - "move": The drag operation will move the element. This is the default. - * - "copy": The drag operation will copy the element. Shows a copy cursor. - * - "copyMove": The user can choose between copy and move by pressing the - * ctrl or shift key. *Not supported in IE:* In Internet Explorer this - * option will be the same as "copy". *Not fully supported in Chrome on - * Windows:* In the Windows version of Chrome the cursor will always be the - * move cursor. However, when the user drops an element and has the ctrl - * key pressed, we will perform a copy anyways. - * - HTML5 also specifies the "link" option, but this library does not - * actively support it yet, so use it at your own risk. - * - dnd-moved Callback that is invoked when the element was moved. Usually you will - * remove your element from the original list in this callback, since the - * directive is not doing that for you automatically. The original dragend - * event will be provided in the local event variable. - * - dnd-canceled Callback that is invoked if the element was dragged, but the operation was - * canceled and the element was not dropped. The original dragend event will - * be provided in the local event variable. - * - dnd-copied Same as dnd-moved, just that it is called when the element was copied - * instead of moved. The original dragend event will be provided in the local - * event variable. - * - dnd-dragstart Callback that is invoked when the element was dragged. The original - * dragstart event will be provided in the local event variable. - * - dnd-dragend Callback that is invoked when the drag operation ended. Available local - * variables are event and dropEffect. - * - dnd-type Use this attribute if you have different kinds of items in your - * application and you want to limit which items can be dropped into which - * lists. Combine with dnd-allowed-types on the dnd-list(s). This attribute - * should evaluate to a string, although this restriction is not enforced. - * - dnd-disable-if You can use this attribute to dynamically disable the draggability of the - * element. This is useful if you have certain list items that you don't want - * to be draggable, or if you want to disable drag & drop completely without - * having two different code branches (e.g. only allow for admins). - * **Note**: If your element is not draggable, the user is probably able to - * select text or images inside of it. Since a selection is always draggable, - * this breaks your UI. You most likely want to disable user selection via - * CSS (see user-select). - * - * CSS classes: - * - dndDragging This class will be added to the element while the element is being - * dragged. It will affect both the element you see while dragging and the - * source element that stays at it's position. Do not try to hide the source - * element with this class, because that will abort the drag operation. - * - dndDraggingSource This class will be added to the element after the drag operation was - * started, meaning it only affects the original element that is still at - * it's source position, and not the "element" that the user is dragging with - * his mouse pointer. - */ - .directive('dndDraggable', ['$parse', '$timeout', 'dndDropEffectWorkaround', 'dndDragTypeWorkaround', - function($parse, $timeout, dndDropEffectWorkaround, dndDragTypeWorkaround) { - return function(scope, element, attr) { - // Set the HTML5 draggable attribute on the element - element.attr("draggable", "true"); - - // If the dnd-disable-if attribute is set, we have to watch that - if (attr.dndDisableIf) { - scope.$watch(attr.dndDisableIf, function(disabled) { - element.attr("draggable", !disabled); - }); - } - - /** - * When the drag operation is started we have to prepare the dataTransfer object, - * which is the primary way we communicate with the target element - */ - element.on('dragstart', function(event) { - event = event.originalEvent || event; - - // Check whether the element is draggable, since dragstart might be triggered on a child. - if (element.attr('draggable') == 'false') return true; - - // Serialize the data associated with this element. IE only supports the Text drag type - event.dataTransfer.setData("Text", angular.toJson(scope.$eval(attr.dndDraggable))); - - // Only allow actions specified in dnd-effect-allowed attribute - event.dataTransfer.effectAllowed = attr.dndEffectAllowed || "move"; - - // Add CSS classes. See documentation above - element.addClass("dndDragging"); - $timeout(function() { element.addClass("dndDraggingSource"); }, 0); - - // Workarounds for stupid browsers, see description below - dndDropEffectWorkaround.dropEffect = "none"; - dndDragTypeWorkaround.isDragging = true; - - // Save type of item in global state. Usually, this would go into the dataTransfer - // typename, but we have to use "Text" there to support IE - dndDragTypeWorkaround.dragType = attr.dndType ? scope.$eval(attr.dndType) : undefined; - - // Try setting a proper drag image if triggered on a dnd-handle (won't work in IE). - if (event._dndHandle && event.dataTransfer.setDragImage) { - event.dataTransfer.setDragImage(element[0], 0, 0); - } - - // Invoke callback - $parse(attr.dndDragstart)(scope, {event: event}); - - event.stopPropagation(); - }); - - /** - * The dragend event is triggered when the element was dropped or when the drag - * operation was aborted (e.g. hit escape button). Depending on the executed action - * we will invoke the callbacks specified with the dnd-moved or dnd-copied attribute. - */ - element.on('dragend', function(event) { - event = event.originalEvent || event; - - // Invoke callbacks. Usually we would use event.dataTransfer.dropEffect to determine - // the used effect, but Chrome has not implemented that field correctly. On Windows - // it always sets it to 'none', while Chrome on Linux sometimes sets it to something - // else when it's supposed to send 'none' (drag operation aborted). - var dropEffect = dndDropEffectWorkaround.dropEffect; - scope.$apply(function() { - switch (dropEffect) { - case "move": - $parse(attr.dndMoved)(scope, {event: event}); - break; - case "copy": - $parse(attr.dndCopied)(scope, {event: event}); - break; - case "none": - $parse(attr.dndCanceled)(scope, {event: event}); - break; - } - $parse(attr.dndDragend)(scope, {event: event, dropEffect: dropEffect}); - }); - - // Clean up - element.removeClass("dndDragging"); - $timeout(function() { element.removeClass("dndDraggingSource"); }, 0); - dndDragTypeWorkaround.isDragging = false; - event.stopPropagation(); - }); - - /** - * When the element is clicked we invoke the callback function - * specified with the dnd-selected attribute. - */ - element.on('click', function(event) { - if (!attr.dndSelected) return; - - event = event.originalEvent || event; - scope.$apply(function() { - $parse(attr.dndSelected)(scope, {event: event}); - }); - - // Prevent triggering dndSelected in parent elements. - event.stopPropagation(); - }); - - /** - * Workaround to make element draggable in IE9 - */ - element.on('selectstart', function() { - if (this.dragDrop) this.dragDrop(); - }); - }; - }]) - - /** - * Use the dnd-list attribute to make your list element a dropzone. Usually you will add a single - * li element as child with the ng-repeat directive. If you don't do that, we will not be able to - * position the dropped element correctly. If you want your list to be sortable, also add the - * dnd-draggable directive to your li element(s). Both the dnd-list and it's direct children must - * have position: relative CSS style, otherwise the positioning algorithm will not be able to - * determine the correct placeholder position in all browsers. - * - * Attributes: - * - dnd-list Required attribute. The value has to be the array in which the data of - * the dropped element should be inserted. - * - dnd-allowed-types Optional array of allowed item types. When used, only items that had a - * matching dnd-type attribute will be dropable. - * - dnd-disable-if Optional boolean expresssion. When it evaluates to true, no dropping - * into the list is possible. Note that this also disables rearranging - * items inside the list. - * - dnd-horizontal-list Optional boolean expresssion. When it evaluates to true, the positioning - * algorithm will use the left and right halfs of the list items instead of - * the upper and lower halfs. - * - dnd-dragover Optional expression that is invoked when an element is dragged over the - * list. If the expression is set, but does not return true, the element is - * not allowed to be dropped. The following variables will be available: - * - event: The original dragover event sent by the browser. - * - index: The position in the list at which the element would be dropped. - * - type: The dnd-type set on the dnd-draggable, or undefined if unset. - * - external: Whether the element was dragged from an external source. - * - dnd-drop Optional expression that is invoked when an element is dropped on the - * list. The following variables will be available: - * - event: The original drop event sent by the browser. - * - index: The position in the list at which the element would be dropped. - * - item: The transferred object. - * - type: The dnd-type set on the dnd-draggable, or undefined if unset. - * - external: Whether the element was dragged from an external source. - * The return value determines the further handling of the drop: - * - false: The drop will be canceled and the element won't be inserted. - * - true: Signalises that the drop is allowed, but the dnd-drop - * callback already took care of inserting the element. - * - otherwise: All other return values will be treated as the object to - * insert into the array. In most cases you want to simply return the - * item parameter, but there are no restrictions on what you can return. - * - dnd-inserted Optional expression that is invoked after a drop if the element was - * actually inserted into the list. The same local variables as for - * dnd-drop will be available. Note that for reorderings inside the same - * list the old element will still be in the list due to the fact that - * dnd-moved was not called yet. - * - dnd-external-sources Optional boolean expression. When it evaluates to true, the list accepts - * drops from sources outside of the current browser tab. This allows to - * drag and drop accross different browser tabs. Note that this will allow - * to drop arbitrary text into the list, thus it is highly recommended to - * implement the dnd-drop callback to check the incoming element for - * sanity. Furthermore, the dnd-type of external sources can not be - * determined, therefore do not rely on restrictions of dnd-allowed-type. - * - * CSS classes: - * - dndPlaceholder When an element is dragged over the list, a new placeholder child - * element will be added. This element is of type li and has the class - * dndPlaceholder set. Alternatively, you can define your own placeholder - * by creating a child element with dndPlaceholder class. - * - dndDragover Will be added to the list while an element is dragged over the list. - */ - .directive('dndList', ['$parse', '$timeout', 'dndDropEffectWorkaround', 'dndDragTypeWorkaround', - function($parse, $timeout, dndDropEffectWorkaround, dndDragTypeWorkaround) { - return function(scope, element, attr) { - // While an element is dragged over the list, this placeholder element is inserted - // at the location where the element would be inserted after dropping - var placeholder = getPlaceholderElement(); - var placeholderNode = placeholder[0]; - var listNode = element[0]; - placeholder.remove(); - - var horizontal = attr.dndHorizontalList && scope.$eval(attr.dndHorizontalList); - var externalSources = attr.dndExternalSources && scope.$eval(attr.dndExternalSources); - - /** - * The dragenter event is fired when a dragged element or text selection enters a valid drop - * target. According to the spec, we either need to have a dropzone attribute or listen on - * dragenter events and call preventDefault(). It should be noted though that no browser seems - * to enforce this behaviour. - */ - element.on('dragenter', function (event) { - event = event.originalEvent || event; - if (!isDropAllowed(event)) return true; - event.preventDefault(); - }); - - /** - * The dragover event is triggered "every few hundred milliseconds" while an element - * is being dragged over our list, or over an child element. - */ - element.on('dragover', function(event) { - event = event.originalEvent || event; - - if (!isDropAllowed(event)) return true; - - // First of all, make sure that the placeholder is shown - // This is especially important if the list is empty - if (placeholderNode.parentNode != listNode) { - element.append(placeholder); - } - - if (event.target !== listNode) { - // Try to find the node direct directly below the list node. - var listItemNode = event.target; - while (listItemNode.parentNode !== listNode && listItemNode.parentNode) { - listItemNode = listItemNode.parentNode; - } - - if (listItemNode.parentNode === listNode && listItemNode !== placeholderNode) { - // If the mouse pointer is in the upper half of the child element, - // we place it before the child element, otherwise below it. - if (isMouseInFirstHalf(event, listItemNode)) { - listNode.insertBefore(placeholderNode, listItemNode); - } else { - listNode.insertBefore(placeholderNode, listItemNode.nextSibling); - } - } - } else { - // This branch is reached when we are dragging directly over the list element. - // Usually we wouldn't need to do anything here, but the IE does not fire it's - // events for the child element, only for the list directly. Therefore, we repeat - // the positioning algorithm for IE here. - if (isMouseInFirstHalf(event, placeholderNode, true)) { - // Check if we should move the placeholder element one spot towards the top. - // Note that display none elements will have offsetTop and offsetHeight set to - // zero, therefore we need a special check for them. - while (placeholderNode.previousElementSibling - && (isMouseInFirstHalf(event, placeholderNode.previousElementSibling, true) - || placeholderNode.previousElementSibling.offsetHeight === 0)) { - listNode.insertBefore(placeholderNode, placeholderNode.previousElementSibling); - } - } else { - // Check if we should move the placeholder element one spot towards the bottom - while (placeholderNode.nextElementSibling && - !isMouseInFirstHalf(event, placeholderNode.nextElementSibling, true)) { - listNode.insertBefore(placeholderNode, - placeholderNode.nextElementSibling.nextElementSibling); - } - } - } - - // At this point we invoke the callback, which still can disallow the drop. - // We can't do this earlier because we want to pass the index of the placeholder. - if (attr.dndDragover && !invokeCallback(attr.dndDragover, event, getPlaceholderIndex())) { - return stopDragover(); - } - - element.addClass("dndDragover"); - event.preventDefault(); - event.stopPropagation(); - return false; - }); - - /** - * When the element is dropped, we use the position of the placeholder element as the - * position where we insert the transferred data. This assumes that the list has exactly - * one child element per array element. - */ - element.on('drop', function(event) { - event = event.originalEvent || event; - - if (!isDropAllowed(event)) return true; - - // The default behavior in Firefox is to interpret the dropped element as URL and - // forward to it. We want to prevent that even if our drop is aborted. - event.preventDefault(); - - // Unserialize the data that was serialized in dragstart. According to the HTML5 specs, - // the "Text" drag type will be converted to text/plain, but IE does not do that. - var data = event.dataTransfer.getData("Text") || event.dataTransfer.getData("text/plain"); - var transferredObject; - try { - transferredObject = JSON.parse(data); - } catch(e) { - return stopDragover(); - } - - // Invoke the callback, which can transform the transferredObject and even abort the drop. - var index = getPlaceholderIndex(); - if (attr.dndDrop) { - transferredObject = invokeCallback(attr.dndDrop, event, index, transferredObject); - if (!transferredObject) { - return stopDragover(); - } - } - - // Insert the object into the array, unless dnd-drop took care of that (returned true). - if (transferredObject !== true) { - scope.$apply(function() { - scope.$eval(attr.dndList).splice(index, 0, transferredObject); - }); - } - invokeCallback(attr.dndInserted, event, index, transferredObject); - - // In Chrome on Windows the dropEffect will always be none... - // We have to determine the actual effect manually from the allowed effects - if (event.dataTransfer.dropEffect === "none") { - if (event.dataTransfer.effectAllowed === "copy" || - event.dataTransfer.effectAllowed === "move") { - dndDropEffectWorkaround.dropEffect = event.dataTransfer.effectAllowed; - } else { - dndDropEffectWorkaround.dropEffect = event.ctrlKey ? "copy" : "move"; - } - } else { - dndDropEffectWorkaround.dropEffect = event.dataTransfer.dropEffect; - } - - // Clean up - stopDragover(); - event.stopPropagation(); - return false; - }); - - /** - * We have to remove the placeholder when the element is no longer dragged over our list. The - * problem is that the dragleave event is not only fired when the element leaves our list, - * but also when it leaves a child element -- so practically it's fired all the time. As a - * workaround we wait a few milliseconds and then check if the dndDragover class was added - * again. If it is there, dragover must have been called in the meantime, i.e. the element - * is still dragging over the list. If you know a better way of doing this, please tell me! - */ - element.on('dragleave', function(event) { - event = event.originalEvent || event; - - element.removeClass("dndDragover"); - $timeout(function() { - if (!element.hasClass("dndDragover")) { - placeholder.remove(); - } - }, 100); - }); - - /** - * Checks whether the mouse pointer is in the first half of the given target element. - * - * In Chrome we can just use offsetY, but in Firefox we have to use layerY, which only - * works if the child element has position relative. In IE the events are only triggered - * on the listNode instead of the listNodeItem, therefore the mouse positions are - * relative to the parent element of targetNode. - */ - function isMouseInFirstHalf(event, targetNode, relativeToParent) { - var mousePointer = horizontal ? (event.offsetX || event.layerX) - : (event.offsetY || event.layerY); - var targetSize = horizontal ? targetNode.offsetWidth : targetNode.offsetHeight; - var targetPosition = horizontal ? targetNode.offsetLeft : targetNode.offsetTop; - targetPosition = relativeToParent ? targetPosition : 0; - return mousePointer < targetPosition + targetSize / 2; - } - - /** - * Tries to find a child element that has the dndPlaceholder class set. If none was found, a - * new li element is created. - */ - function getPlaceholderElement() { - var placeholder; - angular.forEach(element.children(), function(childNode) { - var child = angular.element(childNode); - if (child.hasClass('dndPlaceholder')) { - placeholder = child; - } - }); - return placeholder || angular.element("
"); - } - - /** - * We use the position of the placeholder node to determine at which position of the array the - * object needs to be inserted - */ - function getPlaceholderIndex() { - return Array.prototype.indexOf.call(listNode.children, placeholderNode); - } - - /** - * Checks various conditions that must be fulfilled for a drop to be allowed - */ - function isDropAllowed(event) { - // Disallow drop from external source unless it's allowed explicitly. - if (!dndDragTypeWorkaround.isDragging && !externalSources) return false; - - // Check mimetype. Usually we would use a custom drag type instead of Text, but IE doesn't - // support that. - if (!hasTextMimetype(event.dataTransfer.types)) return false; - - // Now check the dnd-allowed-types against the type of the incoming element. For drops from - // external sources we don't know the type, so it will need to be checked via dnd-drop. - if (attr.dndAllowedTypes && dndDragTypeWorkaround.isDragging) { - var allowed = scope.$eval(attr.dndAllowedTypes); - if (angular.isArray(allowed) && allowed.indexOf(dndDragTypeWorkaround.dragType) === -1) { - return false; - } - } - - // Check whether droping is disabled completely - if (attr.dndDisableIf && scope.$eval(attr.dndDisableIf)) return false; - - return true; - } - - /** - * Small helper function that cleans up if we aborted a drop. - */ - function stopDragover() { - placeholder.remove(); - element.removeClass("dndDragover"); - return true; - } - - /** - * Invokes a callback with some interesting parameters and returns the callbacks return value. - */ - function invokeCallback(expression, event, index, item) { - return $parse(expression)(scope, { - event: event, - index: index, - item: item || undefined, - external: !dndDragTypeWorkaround.isDragging, - type: dndDragTypeWorkaround.isDragging ? dndDragTypeWorkaround.dragType : undefined - }); - } - - /** - * Check if the dataTransfer object contains a drag type that we can handle. In old versions - * of IE the types collection will not even be there, so we just assume a drop is possible. - */ - function hasTextMimetype(types) { - if (!types) return true; - for (var i = 0; i < types.length; i++) { - if (types[i] === "Text" || types[i] === "text/plain") return true; - } - - return false; - } - }; - }]) - - /** - * Use the dnd-nodrag attribute inside of dnd-draggable elements to prevent them from starting - * drag operations. This is especially useful if you want to use input elements inside of - * dnd-draggable elements or create specific handle elements. Note: This directive does not work - * in Internet Explorer 9. - */ - .directive('dndNodrag', function() { - return function(scope, element, attr) { - // Set as draggable so that we can cancel the events explicitly - element.attr("draggable", "true"); - - /** - * Since the element is draggable, the browser's default operation is to drag it on dragstart. - * We will prevent that and also stop the event from bubbling up. - */ - element.on('dragstart', function(event) { - event = event.originalEvent || event; - - if (!event._dndHandle) { - // If a child element already reacted to dragstart and set a dataTransfer object, we will - // allow that. For example, this is the case for user selections inside of input elements. - if (!(event.dataTransfer.types && event.dataTransfer.types.length)) { - event.preventDefault(); - } - event.stopPropagation(); - } - }); - - /** - * Stop propagation of dragend events, otherwise dnd-moved might be triggered and the element - * would be removed. - */ - element.on('dragend', function(event) { - event = event.originalEvent || event; - if (!event._dndHandle) { - event.stopPropagation(); - } - }); - }; - }) - - /** - * Use the dnd-handle directive within a dnd-nodrag element in order to allow dragging with that - * element after all. Therefore, by combining dnd-nodrag and dnd-handle you can allow - * dnd-draggable elements to only be dragged via specific "handle" elements. Note that Internet - * Explorer will show the handle element as drag image instead of the dnd-draggable element. You - * can work around this by styling the handle element differently when it is being dragged. Use - * the CSS selector .dndDragging:not(.dndDraggingSource) [dnd-handle] for that. - */ - .directive('dndHandle', function() { - return function(scope, element, attr) { - element.attr("draggable", "true"); - - element.on('dragstart dragend', function(event) { - event = event.originalEvent || event; - event._dndHandle = true; - }); - }; - }) - - /** - * This workaround handles the fact that Internet Explorer does not support drag types other than - * "Text" and "URL". That means we can not know whether the data comes from one of our elements or - * is just some other data like a text selection. As a workaround we save the isDragging flag in - * here. When a dropover event occurs, we only allow the drop if we are already dragging, because - * that means the element is ours. - */ - .factory('dndDragTypeWorkaround', function(){ return {} }) - - /** - * Chrome on Windows does not set the dropEffect field, which we need in dragend to determine - * whether a drag operation was successful. Therefore we have to maintain it in this global - * variable. The bug report for that has been open for years: - * https://code.google.com/p/chromium/issues/detail?id=39399 - */ - .factory('dndDropEffectWorkaround', function(){ return {} }); \ No newline at end of file