diff --git a/app/static/js/cm-resize.js b/app/static/js/cm-resize.js new file mode 100644 index 0000000000000000000000000000000000000000..78116e0373f74aa05d06f4b3ab51b0bcc5bc4033 --- /dev/null +++ b/app/static/js/cm-resize.js @@ -0,0 +1,262 @@ +/*! + * cm-resize v1.0.0 + * https://github.com/Sphinxxxx/cm-resize + * + * Copyright 2017-2018 Andreas Borgen (https://github.com/Sphinxxxx) + * Released under the MIT license. + */ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global.cmResize = factory()); +}(this, (function () { 'use strict'; + +function dragTracker(options) { + + + var ep = Element.prototype; + if (!ep.matches) ep.matches = ep.msMatchesSelector || ep.webkitMatchesSelector; + if (!ep.closest) ep.closest = function (s) { + var node = this; + do { + if (node.matches(s)) return node; + node = node.tagName === 'svg' ? node.parentNode : node.parentElement; + } while (node); + + return null; + }; + + options = options || {}; + var container = options.container || document.documentElement, + selector = options.selector, + callback = options.callback || console.log, + callbackStart = options.callbackDragStart, + callbackEnd = options.callbackDragEnd, + + callbackClick = options.callbackClick, + propagate = options.propagateEvents, + roundCoords = options.roundCoords !== false, + dragOutside = options.dragOutside !== false, + + handleOffset = options.handleOffset || options.handleOffset !== false; + var offsetToCenter = null; + switch (handleOffset) { + case 'center': + offsetToCenter = true;break; + case 'topleft': + case 'top-left': + offsetToCenter = false;break; + } + + var dragged = void 0, + mouseOffset = void 0, + dragStart = void 0; + + function getMousePos(e, elm, offset, stayWithin) { + var x = e.clientX, + y = e.clientY; + + function respectBounds(value, min, max) { + return Math.max(min, Math.min(value, max)); + } + + if (elm) { + var bounds = elm.getBoundingClientRect(); + x -= bounds.left; + y -= bounds.top; + + if (offset) { + x -= offset[0]; + y -= offset[1]; + } + if (stayWithin) { + x = respectBounds(x, 0, bounds.width); + y = respectBounds(y, 0, bounds.height); + } + + if (elm !== container) { + var center = offsetToCenter !== null ? offsetToCenter + : elm.nodeName === 'circle' || elm.nodeName === 'ellipse'; + + if (center) { + x -= bounds.width / 2; + y -= bounds.height / 2; + } + } + } + return roundCoords ? [Math.round(x), Math.round(y)] : [x, y]; + } + + function stopEvent(e) { + e.preventDefault(); + if (!propagate) { + e.stopPropagation(); + } + } + + function onDown(e) { + if (selector) { + dragged = selector instanceof Element ? selector.contains(e.target) ? selector : null : e.target.closest(selector); + } else { + dragged = {}; + } + + if (dragged) { + stopEvent(e); + + mouseOffset = selector && handleOffset ? getMousePos(e, dragged) : [0, 0]; + dragStart = getMousePos(e, container, mouseOffset); + if (roundCoords) { + dragStart = dragStart.map(Math.round); + } + + if (callbackStart) { + callbackStart(dragged, dragStart); + } + } + } + + function onMove(e) { + if (!dragged) { + return; + } + stopEvent(e); + + var pos = getMousePos(e, container, mouseOffset, !dragOutside); + callback(dragged, pos, dragStart); + } + + function onEnd(e) { + if (!dragged) { + return; + } + + if (callbackEnd || callbackClick) { + var pos = getMousePos(e, container, mouseOffset, !dragOutside); + + if (callbackClick && dragStart[0] === pos[0] && dragStart[1] === pos[1]) { + callbackClick(dragged, dragStart); + } + if (callbackEnd) { + callbackEnd(dragged, pos, dragStart); + } + } + dragged = null; + } + + + container.addEventListener('mousedown', function (e) { + if (isLeftButton(e)) { + onDown(e); + } + }); + container.addEventListener('touchstart', function (e) { + relayTouch(e, onDown); + }); + + window.addEventListener('mousemove', function (e) { + if (!dragged) { + return; + } + + if (isLeftButton(e)) { + onMove(e); + } + else { + onEnd(e); + } + }); + window.addEventListener('touchmove', function (e) { + relayTouch(e, onMove); + }); + + window.addEventListener('mouseup', function (e) { + if (dragged && !isLeftButton(e)) { + onEnd(e); + } + }); + function onTouchEnd(e) { + onEnd(tweakTouch(e)); + } + container.addEventListener('touchend', onTouchEnd); + container.addEventListener('touchcancel', onTouchEnd); + + function isLeftButton(e) { + return e.buttons !== undefined ? e.buttons === 1 : + e.which === 1; + } + function relayTouch(e, handler) { + if (e.touches.length !== 1) { + onEnd(e);return; + } + + handler(tweakTouch(e)); + } + function tweakTouch(e) { + var touch = e.targetTouches[0]; + if (!touch) { + touch = e.changedTouches[0]; + } + + touch.preventDefault = e.preventDefault.bind(e); + touch.stopPropagation = e.stopPropagation.bind(e); + return touch; + } +} + +document.documentElement.firstElementChild +.appendChild(document.createElement('style')).textContent = '.cm-resize-handle{display:block;position:absolute;bottom:0;right:0;z-index:99;width:18px;height:18px;background:url("data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'30\' height=\'30\' viewBox=\'0,0 16,16\'%3E%3Cpath stroke=\'gray\' stroke-width=\'2\' d=\'M-1,12 l18,-18 M-1,18 l18,-18 M-1,24 l18,-18 M-1,30 l18,-18\'/%3E%3C/svg%3E") center/cover;box-shadow:inset -1px -1px 0 0 silver;cursor:nwse-resize}'; + +function cmResize(cm, config) { + config = config || {}; + + var minW = config.minWidth || 200, + minH = config.minHeight || 100, + resizeW = config.resizableWidth !== false, + resizeH = config.resizableHeight !== false, + css = config.cssClass || 'cm-resize-handle'; + + var cmElement = cm.display.wrapper, + cmHandle = config.handle || function () { + var h = cmElement.appendChild(document.createElement('div')); + h.className = css; + return h; + }(); + + var vScroll = cmElement.querySelector('.CodeMirror-vscrollbar'), + hScroll = cmElement.querySelector('.CodeMirror-hscrollbar'); + function constrainScrollbars() { + if (!config.handle) { + vScroll.style.bottom = '18px'; + hScroll.style.right = '18px'; + } + } + cm.on('update', constrainScrollbars); + constrainScrollbars(); + + var startPos = void 0, + startSize = void 0; + dragTracker({ + container: cmHandle.offsetParent, + selector: cmHandle, + + callbackDragStart: function callbackDragStart(handle, pos) { + startPos = pos; + startSize = [cmElement.clientWidth, cmElement.clientHeight]; + }, + callback: function callback(handle, pos) { + var diffX = pos[0] - startPos[0], + diffY = pos[1] - startPos[1], + cw = resizeW ? Math.max(minW, startSize[0] + diffX) : null, + ch = resizeH ? Math.max(minH, startSize[1] + diffY) : null; + + cm.setSize(cw, ch); + } + }); + + return cmHandle; +} + +return cmResize; + +}))); diff --git a/app/static/js/groups.js b/app/static/js/groups.js index e660d72b301951e1004e4e596d8d658df6b90549..14635267baea07258ef5886e076fe9db6e62274a 100644 --- a/app/static/js/groups.js +++ b/app/static/js/groups.js @@ -27,6 +27,11 @@ $(document).ready(function() { mode: "yaml" }); groupVarsEditor.setSize(null, 120); + var handle = cmResize(groupVarsEditor, { + minHeight: 120, + resizableWidth: false, + resizableHeight: true, + }); } var groups_table = $("#groups_table").DataTable({ diff --git a/app/static/js/hosts.js b/app/static/js/hosts.js index 463fff207cf6b6297481022886609108ee7e400a..d79f195194eaea8f4445d7742fabcb0e197db235 100644 --- a/app/static/js/hosts.js +++ b/app/static/js/hosts.js @@ -6,6 +6,11 @@ $(document).ready(function() { mode: "yaml" }); hostVarsEditor.setSize(null, 120); + var handle = cmResize(hostVarsEditor, { + minHeight: 120, + resizableWidth: false, + resizableHeight: true, + }); } function set_default_ip() { diff --git a/app/templates/base.html b/app/templates/base.html index 79d304ad0a8c82c60ebe1786691dde5306b74db6..05b686cb632f6b94b0b0ee1b9464ea00c85acea7 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -69,6 +69,7 @@ <script src="{{ url_for('static', filename='js/showdown.min.js') }}"></script> <script src="{{ url_for('static', filename='js/codemirror.js') }}"></script> <script src="{{ url_for('static', filename='js/yaml.js') }}"></script> + <script src="{{ url_for('static', filename='js/cm-resize.js') }}"></script> <script type=text/javascript> $SCRIPT_ROOT = {{ request.script_root|tojson|safe }}; </script>