From 6a7dab52eb472b062cf96357ba648fc056a24d6b Mon Sep 17 00:00:00 2001 From: Tomas Bures Date: Wed, 16 Aug 2017 12:10:00 +0200 Subject: [PATCH] Snapshot of incomplete DnD extension to tree.js. It however is rather unintuitive how nodes can be put to the end. Dropping this direction in favor of https://github.com/fritz-c/react-sortable-tree --- .../fancytree/skin-bootstrap/icons-rtl.gif | Bin 0 -> 5524 bytes .../public/fancytree/skin-bootstrap/icons.gif | Bin 0 -> 5510 bytes .../fancytree/skin-bootstrap/ui.fancytree.css | 630 ++++++++++++++++++ client/src/lib/form.js | 163 +++-- client/src/lib/tree.css | 73 +- client/src/lib/tree.js | 147 ++-- client/src/lists/segments/CUD.js | 119 +++- client/src/lists/subscriptions/List.js | 2 +- 8 files changed, 999 insertions(+), 135 deletions(-) create mode 100644 client/public/fancytree/skin-bootstrap/icons.gif create mode 100644 client/public/fancytree/skin-bootstrap/ui.fancytree.css diff --git a/client/public/fancytree/skin-bootstrap/icons-rtl.gif b/client/public/fancytree/skin-bootstrap/icons-rtl.gif index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9d6d571c0302b637754b79ae7d1330d0511c5c3e 100644 GIT binary patch literal 5524 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 W9{%AV9^xWC;v`<;CJvPW0RTIOa^czl literal 0 HcmV?d00001 diff --git a/client/public/fancytree/skin-bootstrap/icons.gif b/client/public/fancytree/skin-bootstrap/icons.gif new file mode 100644 index 0000000000000000000000000000000000000000..0097b1f0406f47c6ba5006fe8ff0ce9a94a4076a GIT binary patch literal 5510 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 li:before { + content: none; +} +ul.fancytree-container li { + list-style-image: none; + list-style-position: outside; + list-style-type: none; + -moz-background-clip: border; + -moz-background-inline-policy: continuous; + -moz-background-origin: padding; + background-attachment: scroll; + background-color: transparent; + background-position: 0em 0em; + background-repeat: repeat-y; + background-image: none; + margin: 0; +} +ul.fancytree-container li.fancytree-lastsib { + background-image: none; +} +.ui-fancytree-disabled ul.fancytree-container { + opacity: 0.5; + background-color: silver; +} +ul.fancytree-connectors.fancytree-container li { + background-image: url("data:image/gif;base64,R0lGODlhEAAQAPcAAAAAAIAAAACAAICAAAAAgIAAgACAgMDAwMDcwKbK8P///6Wlpf/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////78KCgpICAgP8AAAD/AP//AAAA//8A/wD//////yH5BAEAAP4ALAAAAAAQABAAAAgpAP0JFHhvoMGDCBMiLKiwocOBDB9KXDixosGIFidizPhwI8eGHj8KDAgAOw=="); + background-position: 0 0; +} +ul.fancytree-container li.fancytree-lastsib, +ul.fancytree-no-connector > li { + background-image: none; +} +li.fancytree-animating { + position: relative; +} +/*------------------------------------------------------------------------------ + * Common icon definitions + *----------------------------------------------------------------------------*/ +span.fancytree-empty, +span.fancytree-vline, +span.fancytree-expander, +span.fancytree-icon, +span.fancytree-checkbox, +span.fancytree-drag-helper-img, +#fancytree-drop-marker { + width: 1em; + height: 1em; + display: inline-block; + vertical-align: top; + background-repeat: no-repeat; + background-position: left; + background-position: 0em 0em; +} +span.fancytree-icon, +span.fancytree-checkbox, +span.fancytree-expander, +span.fancytree-custom-icon { + margin-top: 2px; +} +/* Used by icon option: */ +span.fancytree-custom-icon { + width: 1em; + height: 1em; + display: inline-block; + margin-left: 0.5em; + background-position: 0em 0em; +} +/* Used by 'icon' node option: */ +img.fancytree-icon { + width: 1em; + height: 1em; + margin-left: 0.5em; + margin-top: 2px; + vertical-align: top; + border-style: none; +} +/*------------------------------------------------------------------------------ + * Expander icon + * + * Note: IE6 doesn't correctly evaluate multiples class names, + * so we create combined class names that can be used in the CSS. + * + * Prefix: fancytree-exp- + * 1st character: 'e': expanded, 'c': collapsed, 'n': no children + * 2nd character (optional): 'd': lazy (Delayed) + * 3rd character (optional): 'l': Last sibling + *----------------------------------------------------------------------------*/ +span.fancytree-expander { + cursor: pointer; +} +.fancytree-exp-n span.fancytree-expander, +.fancytree-exp-nl span.fancytree-expander { + background-image: none; + cursor: default; +} +.fancytree-connectors .fancytree-exp-n span.fancytree-expander, +.fancytree-connectors .fancytree-exp-nl span.fancytree-expander { + margin-top: 0; +} +/* Fade out expanders, when container is not hovered or active */ +.fancytree-fade-expander span.fancytree-expander { + transition: opacity 1.5s; + opacity: 0; +} +.fancytree-fade-expander:hover span.fancytree-expander, +.fancytree-fade-expander.fancytree-treefocus span.fancytree-expander, +.fancytree-fade-expander .fancytree-treefocus span.fancytree-expander, +.fancytree-fade-expander [class*='fancytree-statusnode-'] span.fancytree-expander { + transition: opacity 0.6s; + opacity: 1; +} +/*------------------------------------------------------------------------------ + * Checkbox icon + *----------------------------------------------------------------------------*/ +span.fancytree-checkbox { + margin-left: 0.5em; +} +.fancytree-unselectable span.fancytree-checkbox { + opacity: 0.4; + filter: alpha(opacity=40); +} +/*------------------------------------------------------------------------------ + * Node type icon + * Note: IE6 doesn't correctly evaluate multiples class names, + * so we create combined class names that can be used in the CSS. + * + * Prefix: fancytree-ico- + * 1st character: 'e': expanded, 'c': collapsed + * 2nd character (optional): 'f': folder + *----------------------------------------------------------------------------*/ +span.fancytree-icon { + margin-left: 0.5em; +} +/* Documents */ +/* Folders */ +.fancytree-loading span.fancytree-expander, +.fancytree-loading span.fancytree-expander:hover, +.fancytree-statusnode-loading span.fancytree-icon, +.fancytree-statusnode-loading span.fancytree-icon:hover { + background-image: none; +} +/* Status node icons */ +/*------------------------------------------------------------------------------ + * Node titles and highlighting + *----------------------------------------------------------------------------*/ +span.fancytree-node { + /* See #117 */ + display: inherit; + width: 100%; + margin-top: 0px; + min-height: 1em; +} +span.fancytree-title { + color: #333333; + cursor: pointer; + display: inline-block; + vertical-align: top; + min-height: 1em; + padding: 0 3px 0 3px; + margin: 0px 0 0 0.5em; + border: 1px solid transparent; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + -ms-border-radius: 3px; + -o-border-radius: 3px; + border-radius: 3px; +} +span.fancytree-node.fancytree-error span.fancytree-title { + color: #d9534f; +} +/*------------------------------------------------------------------------------ + * Drag'n'drop support + *----------------------------------------------------------------------------*/ +div.fancytree-drag-helper span.fancytree-childcounter, +div.fancytree-drag-helper span.fancytree-dnd-modifier { + display: inline-block; + color: #fff; + background: #337ab7; + border: 1px solid gray; + min-width: 10px; + height: 10px; + line-height: 1; + vertical-align: baseline; + border-radius: 10px; + padding: 2px; + text-align: center; + font-size: 9px; +} +div.fancytree-drag-helper span.fancytree-childcounter { + position: absolute; + top: -6px; + right: -6px; +} +div.fancytree-drag-helper span.fancytree-dnd-modifier { + background: #5cb85c; + border: none; + font-weight: bolder; +} +/*** Drop marker icon *********************************************************/ +#fancytree-drop-marker { + width: 2em; + position: absolute; + margin: 0; +} +#fancytree-drop-marker.fancytree-drop-after, +#fancytree-drop-marker.fancytree-drop-before { + width: 4em; +} +/*** Source node while dragging ***********************************************/ +span.fancytree-drag-source.fancytree-drag-remove { + opacity: 0.15; +} +/*** Target node while dragging cursor is over it *****************************/ +/*------------------------------------------------------------------------------ + * 'rtl' option + *----------------------------------------------------------------------------*/ +.fancytree-container.fancytree-rtl .fancytree-title { + /*unicode-bidi: bidi-override;*/ + /* optional: reverse title letters */ +} +.fancytree-container.fancytree-rtl span.fancytree-connector, +.fancytree-container.fancytree-rtl span.fancytree-expander, +.fancytree-container.fancytree-rtl span.fancytree-icon, +.fancytree-container.fancytree-rtl span.fancytree-drag-helper-img, +.fancytree-container.fancytree-rtl #fancytree-drop-marker { + background-image: url("icons-rtl.gif"); +} +.fancytree-container.fancytree-rtl .fancytree-exp-n span.fancytree-expander, +.fancytree-container.fancytree-rtl .fancytree-exp-nl span.fancytree-expander { + background-image: none; +} +.fancytree-container.fancytree-rtl.fancytree-connectors .fancytree-exp-n span.fancytree-expander, +.fancytree-container.fancytree-rtl.fancytree-connectors .fancytree-exp-nl span.fancytree-expander { + background-image: url("icons-rtl.gif"); +} +ul.fancytree-container.fancytree-rtl ul { + padding: 0 16px 0 0; +} +ul.fancytree-container.fancytree-rtl.fancytree-connectors li { + background-position: right 0; + background-image: url("vline-rtl.gif"); +} +ul.fancytree-container.fancytree-rtl li.fancytree-lastsib, +ul.fancytree-container.fancytree-rtl.fancytree-no-connector > li { + background-image: none; +} +/*------------------------------------------------------------------------------ + * 'table' extension + *----------------------------------------------------------------------------*/ +table.fancytree-ext-table { + border-collapse: collapse; +} +table.fancytree-ext-table span.fancytree-node { + display: inline-block; + box-sizing: border-box; +} +/*------------------------------------------------------------------------------ + * 'columnview' extension + *----------------------------------------------------------------------------*/ +table.fancytree-ext-columnview tbody tr td { + position: relative; + border: 1px solid gray; + vertical-align: top; + overflow: auto; +} +table.fancytree-ext-columnview tbody tr td > ul { + padding: 0; +} +table.fancytree-ext-columnview tbody tr td > ul li { + list-style-image: none; + list-style-position: outside; + list-style-type: none; + -moz-background-clip: border; + -moz-background-inline-policy: continuous; + -moz-background-origin: padding; + background-attachment: scroll; + background-color: transparent; + background-position: 0em 0em; + background-repeat: repeat-y; + background-image: none; + /* no v-lines */ + margin: 0; +} +table.fancytree-ext-columnview span.fancytree-node { + position: relative; + /* allow positioning of embedded spans */ + display: inline-block; +} +table.fancytree-ext-columnview span.fancytree-node.fancytree-expanded { + background-color: #CBE8F6; +} +table.fancytree-ext-columnview .fancytree-has-children span.fancytree-cv-right { + position: absolute; + right: 3px; +} +/*------------------------------------------------------------------------------ + * 'filter' extension + *----------------------------------------------------------------------------*/ +.fancytree-ext-filter-dimm span.fancytree-node span.fancytree-title { + color: #333333; + font-weight: lighter; +} +.fancytree-ext-filter-dimm tr.fancytree-submatch span.fancytree-title, +.fancytree-ext-filter-dimm span.fancytree-node.fancytree-submatch span.fancytree-title { + color: black; + font-weight: normal; +} +.fancytree-ext-filter-dimm tr.fancytree-match span.fancytree-title, +.fancytree-ext-filter-dimm span.fancytree-node.fancytree-match span.fancytree-title { + color: black; + font-weight: bold; +} +.fancytree-ext-filter-hide tr.fancytree-hide, +.fancytree-ext-filter-hide span.fancytree-node.fancytree-hide { + display: none; +} +.fancytree-ext-filter-hide tr.fancytree-submatch span.fancytree-title, +.fancytree-ext-filter-hide span.fancytree-node.fancytree-submatch span.fancytree-title { + color: #333333; + font-weight: lighter; +} +.fancytree-ext-filter-hide tr.fancytree-match span.fancytree-title, +.fancytree-ext-filter-hide span.fancytree-node.fancytree-match span.fancytree-title { + color: black; + font-weight: normal; +} +/* Hide expanders if all child nodes are hidden by filter */ +.fancytree-ext-filter-hide-expanders tr.fancytree-match span.fancytree-expander, +.fancytree-ext-filter-hide-expanders span.fancytree-node.fancytree-match span.fancytree-expander { + visibility: hidden; +} +.fancytree-ext-filter-hide-expanders tr.fancytree-submatch span.fancytree-expander, +.fancytree-ext-filter-hide-expanders span.fancytree-node.fancytree-submatch span.fancytree-expander { + visibility: visible; +} +.fancytree-ext-childcounter span.fancytree-icon, +.fancytree-ext-filter span.fancytree-icon { + position: relative; +} +.fancytree-ext-childcounter span.fancytree-childcounter, +.fancytree-ext-filter span.fancytree-childcounter { + color: #fff; + background: #777; + border: 1px solid gray; + position: absolute; + top: -6px; + right: -6px; + min-width: 10px; + height: 10px; + line-height: 1; + vertical-align: baseline; + border-radius: 10px; + padding: 2px; + text-align: center; + font-size: 9px; +} +/*------------------------------------------------------------------------------ + * 'wide' extension + *----------------------------------------------------------------------------*/ +ul.fancytree-ext-wide { + position: relative; + min-width: 100%; + z-index: 2; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +ul.fancytree-ext-wide span.fancytree-node > span { + position: relative; + z-index: 2; +} +ul.fancytree-ext-wide span.fancytree-node span.fancytree-title { + position: absolute; + z-index: 1; + left: 0px; + min-width: 100%; + margin-left: 0; + margin-right: 0; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +/*------------------------------------------------------------------------------ + * 'fixed' extension + *----------------------------------------------------------------------------*/ +.fancytree-ext-fixed-wrapper .fancytree-fixed-hidden { + display: none; +} +.fancytree-ext-fixed-wrapper div.scrollBorderBottom { + border-bottom: 3px solid rgba(0, 0, 0, 0.75); +} +.fancytree-ext-fixed-wrapper div.scrollBorderRight { + border-right: 3px solid rgba(0, 0, 0, 0.75); +} +.fancytree-ext-fixed-wrapper div.fancytree-fixed-wrapper-tl { + position: absolute; + overflow: hidden; + z-index: 3; + top: 0px; + left: 0px; +} +.fancytree-ext-fixed-wrapper div.fancytree-fixed-wrapper-tr { + position: absolute; + overflow: hidden; + z-index: 2; + top: 0px; +} +.fancytree-ext-fixed-wrapper div.fancytree-fixed-wrapper-bl { + position: absolute; + overflow: hidden; + z-index: 2; + left: 0px; +} +.fancytree-ext-fixed-wrapper div.fancytree-fixed-wrapper-br { + position: absolute; + overflow: scroll; + z-index: 1; +} +/******************************************************************************* + * Styles specific to this skin. + * + * This section is automatically generated from the `ui-fancytree.less` template. + ******************************************************************************/ +/******************************************************************************* + * Plain tree + * Modifier classes on
    container: + * table-hover : Enable a light mouse hover effect + * fancytree-colorize-selected: Give selected (checked) rows a color + */ +ul.fancytree-container ul { + padding: 0 0 0 1.5em; + margin: 0; +} +/* Prevent focus frame */ +.fancytree-container:focus { + outline: none; +} +.fancytree-container .fancytree-active span.fancytree-title input, +.fancytree-container.fancytree-colorize-selected .fancytree-selected span.fancytree-title input { + color: black; +} +.fancytree-container span.fancytree-statusnode-error span.fancytree-expander { + color: #d9534f; +} +/* Helper to allow spinning loader icon with bootstrap */ +.glyphicon-spin { + -webkit-animation: spin 1000ms infinite linear; + animation: spin 1000ms infinite linear; +} +@-webkit-keyframes spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} +@keyframes spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} +div.fancytree-drag-helper.fancytree-drop-reject, +div.fancytree-drag-helper.fancytree-drop-reject span.fancytree-title { + color: #d9534f; +} +span.fancytree-node.fancytree-drag-source { + background-color: #5bc0de !important; +} +span.fancytree-node.fancytree-drop-target.fancytree-drop-reject span.fancytree.title { + background-color: #d9534f !important; +} +span.fancytree-expander { + color: #999; +} +.fancytree-expanded span.fancytree-expander { + color: #333333; +} +span.fancytree-node span.fancytree-expander:hover { + color: cyan; +} +.fancytree-plain.fancytree-colorize-selected span.fancytree-node.fancytree-selected, +.fancytree-plain.fancytree-colorize-selected span.fancytree-node.fancytree-selected span.fancytree-title { + background-color: #80c780; + border-color: #80c780; + color: #fff; +} +.fancytree-plain.fancytree-colorize-selected span.fancytree-node.fancytree-selected:hover span.fancytree-title { + background-color: #6ec06e; +} +.fancytree-plain.fancytree-colorize-selected span.fancytree-node.fancytree-active.fancytree-selected span.fancytree-title { + color: #80c780; +} +.fancytree-plain.fancytree-colorize-selected.fancytree-treefocus span.fancytree-title:hover { + background-color: #f5f5f5; +} +.fancytree-plain.fancytree-colorize-selected.fancytree-treefocus span.fancytree-node.fancytree-selected span.fancytree-title { + background-color: #5cb85c; +} +.fancytree-plain.fancytree-colorize-selected.fancytree-treefocus span.fancytree-node.fancytree-selected:hover span.fancytree-title { + background-color: #4cae4c; +} +.fancytree-plain.fancytree-colorize-selected.fancytree-treefocus span.fancytree-node.fancytree-active.fancytree-selected span.fancytree-title { + color: #5cb85c; +} +.fancytree-plain.fancytree-container span.fancytree-node { + margin-top: 2px; + margin-bottom: 2px; +} +.fancytree-plain.fancytree-container span.fancytree-title { + border: 1px solid transparent; + border-radius: 3px; + outline-radius: 3px; +} +.fancytree-plain.fancytree-container span.fancytree-title:hover { + background-color: #f5f5f5; +} +.fancytree-plain.fancytree-container span.fancytree-node.fancytree-active span.fancytree-title { + background-color: #5094ce; + color: #fff; +} +.fancytree-plain.fancytree-container span.fancytree-node.fancytree-active:hover span.fancytree-title { + background-color: #3c87c8; +} +.fancytree-plain.fancytree-container.fancytree-ext-wide span.fancytree-node.fancytree-active { + color: #fff; +} +.fancytree-plain.fancytree-container.fancytree-treefocus span.fancytree-node.fancytree-focused span.fancytree-title { + border-color: #337ab7; +} +.fancytree-plain.fancytree-container.fancytree-treefocus span.fancytree-node.fancytree-active span.fancytree-title { + background-color: #337ab7; + border-color: #337ab7; +} +.fancytree-plain.fancytree-container.fancytree-treefocus span.fancytree-node.fancytree-active:hover span.fancytree-title { + background-color: #2e6da4; +} +/******************************************************************************* + * 'table' extension + * Modifier classes on : + * table-hover : Enable a light mouse hover effect + * fancytree-colorize-selected: Give selected (checked) rows a color + */ +table.fancytree-ext-table > tbody > tr > td span.fancytree-title { + border: none; +} +table.fancytree-ext-table.fancytree-colorize-selected > tbody > tr.fancytree-selected > td { + background-color: #80c780; +} +table.fancytree-ext-table.fancytree-colorize-selected > tbody > tr.fancytree-selected > td, +table.fancytree-ext-table.fancytree-colorize-selected > tbody > tr.fancytree-selected > td span.fancytree-title { + color: #fff; +} +table.fancytree-ext-table.fancytree-colorize-selected.fancytree-treefocus > tbody > tr.fancytree-selected > td { + background-color: #5cb85c; +} +table.fancytree-ext-table.fancytree-colorize-selected.table-hover > tbody > tr.fancytree-selected:hover > td { + background-color: #6ec06e; +} +table.fancytree-ext-table.fancytree-colorize-selected.fancytree-treefocus.table-hover > tbody > tr.fancytree-selected:hover > td { + background-color: #4cae4c; +} +table.fancytree-ext-table.fancytree-colorize-selected.fancytree-treefocus.table-hover > tbody > tr.fancytree-selected.fancytree-active:hover > td, +table.fancytree-ext-table.fancytree-colorize-selected.table-hover > tbody > tr.fancytree-selected.fancytree-active:hover > td { + background-color: #2e6da4; +} +table.fancytree-ext-table.fancytree-colorize-selected > tbody > tr.fancytree-active.fancytree-selected { + outline-width: 2px; + outline-offset: -2px; + outline-style: solid; + outline-color: #80c780; +} +table.fancytree-ext-table.fancytree-container > tbody > tr.fancytree-active > td { + background-color: #5094ce; +} +table.fancytree-ext-table.fancytree-container > tbody > tr.fancytree-active > td, +table.fancytree-ext-table.fancytree-container > tbody > tr.fancytree-active > td span.fancytree-title { + color: #fff; +} +table.fancytree-ext-table.fancytree-treefocus.fancytree-container > tbody > tr.fancytree-focused span.fancytree-title { + outline: 1px dotted #000; +} +table.fancytree-ext-table.fancytree-treefocus.fancytree-container > tbody > tr.fancytree-active > td { + background-color: #337ab7; +} +table.fancytree-ext-table.fancytree-treefocus.fancytree-container.table-hover > tbody > tr.fancytree-active:hover > td { + background-color: #2e6da4; +} diff --git a/client/src/lib/form.js b/client/src/lib/form.js index b2d9fc7d..674949ac 100644 --- a/client/src/lib/form.js +++ b/client/src/lib/form.js @@ -37,7 +37,7 @@ class Form extends Component { static propTypes = { stateOwner: PropTypes.object.isRequired, onSubmitAsync: PropTypes.func, - inline: PropTypes.bool + format: PropTypes.string } static childContextTypes = { @@ -70,6 +70,13 @@ class Form extends Component { const statusMessageText = owner.getFormStatusMessageText(); const statusMessageSeverity = owner.getFormStatusMessageSeverity(); + let formClass = 'form-horizontal'; + if (props.format === 'wide') { + formClass = ''; + } else if (props.format === 'inline') { + formClass = 'form-inline'; + } + if (!owner.isFormReady()) { if (owner.isFormWithLoadingNotice()) { return

    {t('Loading ...')}

    @@ -78,11 +85,15 @@ class Form extends Component { } } else { return ( - +
    {props.children}
    - {statusMessageText &&

    {statusMessageText}

    } + {statusMessageText && + +

    {statusMessageText}

    +
    + } ); } @@ -106,27 +117,48 @@ class Fieldset extends Component { } } -function wrapInput(id, htmlId, owner, label, help, input, inline) { +function wrapInput(id, htmlId, owner, format, rightContainerClass, label, help, input) { const className = id ? owner.addFormValidationClass('form-group', id) : 'form-group'; + let colLeft = ''; + let colRight = ''; + let offsetRight = ''; + + switch (format) { + case 'wide': + colLeft = ''; + colRight = ''; + offsetRight = ''; + break; + default: + colLeft = 'col-sm-2'; + colRight = 'col-sm-10'; + offsetRight = 'col-sm-offset-2'; + break; + } + + if (format === 'inline') { + } + let helpBlock = null; if (help) { - helpBlock =
    {help}
    ; + helpBlock =
    {help}
    ; } let validationBlock = null; if (id) { const validationMsg = id && owner.getFormValidationMessage(id); if (validationMsg) { - validationBlock =
    {validationMsg}
    ; + validationBlock =
    {validationMsg}
    ; } } - const labelBlock = ; + let labelBlock = null; + if (label) { + labelBlock = ; + } - if (inline) { + if (format === 'inline') { return (
    {labelBlock}   {input} @@ -137,10 +169,10 @@ function wrapInput(id, htmlId, owner, label, help, input, inline) { } else { return (
    -
    +
    {labelBlock}
    -
    +
    {input}
    {helpBlock} @@ -150,30 +182,13 @@ function wrapInput(id, htmlId, owner, label, help, input, inline) { } } -function wrapInputWithText(id, htmlId, owner, containerClass, label, text, help, input) { - const helpBlock = help ?
    {help}
    : ''; - const validationMsg = id && owner.getFormValidationMessage(id); - - return ( -
    -
    - -
    -
    - -
    - {helpBlock} - {id && validationMsg &&
    {validationMsg}
    } -
    - ); -} - class StaticField extends Component { static propTypes = { id: PropTypes.string.isRequired, label: PropTypes.string.isRequired, help: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), - className: PropTypes.string + className: PropTypes.string, + format: PropTypes.string } render() { @@ -187,7 +202,7 @@ class StaticField extends Component { className += ' ' + props.className; } - return wrapInput(null, htmlId, owner, props.label, props.help, + return wrapInput(null, htmlId, owner, props.format, '', props.label, props.help,
    {props.children}
    ); } @@ -199,7 +214,8 @@ class InputField extends Component { label: PropTypes.string.isRequired, placeholder: PropTypes.string, type: PropTypes.string, - help: PropTypes.oneOfType([PropTypes.string, PropTypes.object]) + help: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), + format: PropTypes.string } static defaultProps = { @@ -221,7 +237,7 @@ class InputField extends Component { type = 'password'; } - return wrapInput(id, htmlId, owner, props.label, props.help, + return wrapInput(id, htmlId, owner, props.format, '', props.label, props.help, owner.updateFormValue(id, evt.target.value)}/> ); } @@ -232,7 +248,8 @@ class CheckBox extends Component { id: PropTypes.string.isRequired, text: PropTypes.string.isRequired, label: PropTypes.string, - help: PropTypes.oneOfType([PropTypes.string, PropTypes.object]) + help: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), + format: PropTypes.string } static contextTypes = { @@ -245,8 +262,11 @@ class CheckBox extends Component { const id = this.props.id; const htmlId = 'form_' + id; - return wrapInputWithText(id, htmlId, owner, 'checkbox', props.label, props.text, props.help, - owner.updateFormValue(id, !owner.getFormValue(id))}/> + return wrapInput(id, htmlId, owner, props.format, 'checkbox', props.label, props.help, + ); } } @@ -255,7 +275,8 @@ class TextArea extends Component { static propTypes = { id: PropTypes.string.isRequired, label: PropTypes.string.isRequired, - help: PropTypes.oneOfType([PropTypes.string, PropTypes.object]) + help: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), + format: PropTypes.string } static contextTypes = { @@ -268,7 +289,7 @@ class TextArea extends Component { const id = this.props.id; const htmlId = 'form_' + id; - return wrapInput(id, htmlId, owner, props.label, props.help, + return wrapInput(id, htmlId, owner, props.format, '', props.label, props.help, ); } @@ -282,7 +303,7 @@ class Dropdown extends Component { options: PropTypes.array, optGroups: PropTypes.array, className: PropTypes.string, - inline: PropTypes.bool + format: PropTypes.string } static contextTypes = { @@ -312,11 +333,10 @@ class Dropdown extends Component { className += ' ' + props.className; } - return wrapInput(id, htmlId, owner, props.label, props.help, + return wrapInput(id, htmlId, owner, props.format, '', props.label, props.help, , - props.inline + ); } } @@ -326,7 +346,12 @@ class AlignedRow extends Component { static propTypes = { className: PropTypes.string, label: PropTypes.string, - htmlId: PropTypes.string + htmlId: PropTypes.string, + format: PropTypes.string + } + + static contextTypes = { + formStateOwner: PropTypes.object.isRequired } static defaultProps = { @@ -334,33 +359,28 @@ class AlignedRow extends Component { } render() { - if (this.props.label) { - return ( -
    - -
    - {this.props.children} -
    -
    - ); + const props = this.props; + const owner = this.context.formStateOwner; - } else { - return ( -
    -
    - {this.props.children} -
    -
    - ); - } + return wrapInput(null, props.htmlId, owner, props.format, props.className, props.label, null, this.props.children); } } class ButtonRow extends Component { + static propTypes = { + className: PropTypes.string, + format: PropTypes.string + } + render() { + let className = 'mt-button-row'; + if (this.props.className) { + className += ' ' + this.props.className; + } + return ( - {this.props.children} + {this.props.children} ); } } @@ -423,7 +443,8 @@ class TreeTableSelect extends Component { label: PropTypes.string.isRequired, dataUrl: PropTypes.string, data: PropTypes.array, - help: PropTypes.oneOfType([PropTypes.string, PropTypes.object]) + help: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), + format: PropTypes.string } static contextTypes = { @@ -441,7 +462,7 @@ class TreeTableSelect extends Component { const id = this.props.id; const htmlId = 'form_' + id; - return wrapInput(id, htmlId, owner, props.label, props.help, + return wrapInput(id, htmlId, owner, props.format, '', props.label, props.help, ); } @@ -471,7 +492,8 @@ class TableSelect extends Component { id: PropTypes.string.isRequired, label: PropTypes.string.isRequired, - help: PropTypes.oneOfType([PropTypes.string, PropTypes.object]) + help: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), + format: PropTypes.string } static defaultProps = { @@ -530,7 +552,7 @@ class TableSelect extends Component { const t = props.t; if (props.dropdown) { - return wrapInput(id, htmlId, owner, props.label, props.help, + return wrapInput(id, htmlId, owner, props.format, '', props.label, props.help,
    @@ -544,7 +566,7 @@ class TableSelect extends Component {
    ); } else { - return wrapInput(id, htmlId, owner, props.label, props.help, + return wrapInput(id, htmlId, owner, props.format, '', props.label, props.help,
    this.table = node} data={props.data} dataUrl={props.dataUrl} columns={props.columns} selectMode={props.selectMode} selectionAsArray={this.props.selectionAsArray} withHeader={props.withHeader} selection={owner.getFormValue(id)} onSelectionChangedAsync={::this.onSelectionChangedAsync}/> @@ -570,7 +592,8 @@ class ACEEditor extends Component { label: PropTypes.string, help: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), height: PropTypes.string, - mode: PropTypes.string + mode: PropTypes.string, + format: PropTypes.string } static contextTypes = { @@ -583,7 +606,7 @@ class ACEEditor extends Component { const id = this.props.id; const htmlId = 'form_' + id; - return wrapInput(id, htmlId, owner, props.label, props.help, + return wrapInput(id, htmlId, owner, props.format, '', props.label, props.help, table.fancytree-ext-table.fancytree-container>tbody>tr.fancytree-active>td, -.mt-treetable-container.mt-treetable-inactivable>table.fancytree-ext-table.fancytree-container>tbody>tr.fancytree-active:hover>td { +.mt-treetable-container.mt-treetable-inactivable>table.fancytree-ext-table.fancytree-container>tbody>tr.fancytree-active:hover>td, +.mt-treetable-container.mt-treetable-inactivable .fancytree-container span.fancytree-node.fancytree-active span.fancytree-title, +.mt-treetable-container.mt-treetable-inactivable .fancytree-container span.fancytree-node.fancytree-active span.fancytree-title:hover, +.mt-treetable-container.mt-treetable-inactivable .fancytree-container span.fancytree-node.fancytree-active:hover span.fancytree-title, +.mt-treetable-container.mt-treetable-inactivable .fancytree-container span.fancytree-node span.fancytree-title:hover { background-color: transparent; } -.mt-treetable-container.mt-treetable-inactivable>table.fancytree-ext-table.fancytree-container>tbody>tr.fancytree-active>td span.fancytree-title { +.mt-treetable-container.mt-treetable-inactivable .fancytree-container span.fancytree-node span.fancytree-title { + cursor: default; +} + +.mt-treetable-container.mt-treetable-inactivable .fancytree-container span.fancytree-node.fancytree-active span.fancytree-title, +.mt-treetable-container.mt-treetable-inactivable .fancytree-container span.fancytree-node.fancytree-active span.fancytree-title:hover { + border-color: transparent; +} + +.mt-treetable-container.mt-treetable-inactivable>table.fancytree-ext-table.fancytree-container>tbody>tr.fancytree-active>td span.fancytree-title, +.mt-treetable-container.mt-treetable-inactivable>table.fancytree-ext-table.fancytree-container>tbody>tr.fancytree-active>td span.fancytree-expander, +.mt-treetable-container.mt-treetable-inactivable .fancytree-container span.fancytree-node.fancytree-active span.fancytree-title { + outline: 0px none; color: #333333; } @@ -28,6 +69,33 @@ min-width: 150px; } + + +.mt-treetable-container span.fancytree-node.fancytree-drag-source { + background-color: transparent !important; +} + +.mt-treetable-container #fancytree-drop-marker { + background-image: url("../../public/fancytree/skin-bootstrap/icons.gif"); + height: 12px; +} + +.mt-treetable-container #fancytree-drop-marker.fancytree-drop-over { + background-position: 0px -130px; + width: 22px; +} + +.mt-treetable-container #fancytree-drop-marker.fancytree-drop-after, .mt-treetable-container #fancytree-drop-marker.fancytree-drop-before { + background-position: 0px -145px; + width: 64px; +} + +.mt-treetable-container span.fancytree-node.fancytree-drop-accept fancytree-expander { + visibility: hidden; +} + + + .form-group .mt-treetable-container { border: 1px solid #cccccc; border-radius: 4px; @@ -49,3 +117,4 @@ -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,0.075); box-shadow: inset 0 1px 1px rgba(0,0,0,0.075); } + diff --git a/client/src/lib/tree.js b/client/src/lib/tree.js index a26a18c4..07ae4c87 100644 --- a/client/src/lib/tree.js +++ b/client/src/lib/tree.js @@ -69,7 +69,10 @@ class TreeTable extends Component { onSelectionChangedAsync: PropTypes.func, actions: PropTypes.func, withHeader: PropTypes.bool, - withDescription: PropTypes.bool + withDescription: PropTypes.bool, + noTable: PropTypes.bool, + withDnd: PropTypes.bool, + withIcons: PropTypes.bool } componentWillReceiveProps(nextProps) { @@ -106,17 +109,6 @@ class TreeTable extends Component { this.loadData(this.props.dataUrl); } - const glyphOpts = { - map: { - expanderClosed: 'glyphicon glyphicon-menu-right', - expanderLazy: 'glyphicon glyphicon-menu-right', // glyphicon-plus-sign - expanderOpen: 'glyphicon glyphicon-menu-down', // glyphicon-collapse-down - checkbox: 'glyphicon glyphicon-unchecked', - checkboxSelected: 'glyphicon glyphicon-check', - checkboxUnknown: 'glyphicon glyphicon-share', - } - }; - let createNodeFn; createNodeFn = (event, data) => { const node = data.node; @@ -148,22 +140,70 @@ class TreeTable extends Component { } }; - this.tree = jQuery(this.domTable).fancytree({ - extensions: ['glyph', 'table'], - glyph: glyphOpts, + const treeOpts = { + extensions: ['glyph'], + glyph: { + map: { + expanderClosed: 'glyphicon glyphicon-menu-right', + expanderLazy: 'glyphicon glyphicon-menu-right', // glyphicon-plus-sign + expanderOpen: 'glyphicon glyphicon-menu-down', // glyphicon-collapse-down + checkbox: 'glyphicon glyphicon-unchecked', + checkboxSelected: 'glyphicon glyphicon-check', + checkboxUnknown: 'glyphicon glyphicon-share', + + folder: 'glyphicon glyphicon-folder-close', + folderOpen: 'glyphicon glyphicon-folder-open', + doc: 'glyphicon glyphicon-file', + docOpen: 'glyphicon glyphicon-file' + } + }, selectMode: (this.selectMode === TreeSelectMode.MULTI ? 2 : 1), - icon: false, + icon: !!this.props.withIcons, autoScroll: true, scrollParent: jQuery(this.domTableContainer), source: this.sanitizeTreeData(this.state.treeData), - table: { - nodeColumnIdx: 0 - }, + toggleEffect: false, createNode: createNodeFn, checkbox: this.selectMode === TreeSelectMode.MULTI, activate: (this.selectMode === TreeSelectMode.SINGLE ? ::this.onActivate : null), - select: (this.selectMode === TreeSelectMode.MULTI ? ::this.onSelect : null) - }).fancytree("getTree"); + select: (this.selectMode === TreeSelectMode.MULTI ? ::this.onSelect : null), + }; + + if (!this.props.noTable) { + treeOpts.extensions.push('table'); + treeOpts.table = { + nodeColumnIdx: 0 + }; + } + + if (this.props.withDnd) { + treeOpts.extensions.push('dnd'); + treeOpts.dnd = { + autoExpandMS: 400, + focusOnClick: true, + preventVoidMoves: true, + preventRecursiveMoves: true, + dropMarkerOffsetX: -46, // -22 + dropMarkerInsertOffsetX: 0, + dragStart: (node, data) => { + return node.key !== '__mt-tree-end-drop__'; + }, + dragEnter: (node, data) => { + if (node.folder) { + return ['before', 'over']; + } else { + return ['before']; + } + }, + dragDrop: (node, data) => { + console.log(node); + console.log(data); + data.otherNode.moveTo(node, data.hitMode); + } + }; + } + + this.tree = jQuery(this.domTable).fancytree(treeOpts).fancytree("getTree"); this.updateSelection(); } @@ -252,6 +292,10 @@ class TreeTable extends Component { let containerClass = 'mt-treetable-container'; if (this.selectMode === TreeSelectMode.NONE) { containerClass += ' mt-treetable-inactivable'; + } else { + if (!props.noTable) { + containerClass += ' table-hover'; + } } if (!this.withHeader) { @@ -260,31 +304,44 @@ class TreeTable extends Component { // FIXME: style={{ height: '100px', overflow: 'auto'}} - const container = -
    { this.domTableContainer = domElem; }} > -
    { this.domTable = domElem; }} className="table table-hover table-striped table-condensed"> - {props.withHeader && - - - - {withDescription && } - {actions && } - - - } - - - - {withDescription && } - {actions && } - - -
    {t('Name')}{t('Description')}
    - ; + if (props.noTable) { + return ( +
    { this.domTableContainer = domElem; }} > +
    { this.domTable = domElem; }}> +
    +
    + ); + + } else { + let tableClass = 'table table-striped table-condensed'; + if (this.selectMode !== TreeSelectMode.NONE) { + tableClass += ' table-hover'; + } + + return ( +
    { this.domTableContainer = domElem; }} > + { this.domTable = domElem; }} className={tableClass}> + {props.withHeader && + + + + {withDescription && } + {actions && } + + + } + + + + {withDescription && } + {actions && } + + +
    {t('Name')}{t('Description')}
    +
    + ); + } - return ( - container - ); } } diff --git a/client/src/lists/segments/CUD.js b/client/src/lists/segments/CUD.js index 0d0cc035..fe6c5218 100644 --- a/client/src/lists/segments/CUD.js +++ b/client/src/lists/segments/CUD.js @@ -3,14 +3,14 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { translate, Trans } from 'react-i18next'; -import {requiresAuthenticatedUser, withPageHelpers, Title, NavButton} from '../../lib/page'; +import {requiresAuthenticatedUser, withPageHelpers, Title, NavButton, Toolbar} from '../../lib/page'; import { - withForm, Form, FormSendMethod, InputField, ButtonRow, Button + withForm, Form, FormSendMethod, InputField, ButtonRow, Button, Fieldset } from '../../lib/form'; import { withErrorHandling, withAsyncErrorHandler } from '../../lib/error-handling'; import {DeleteModalDialog} from "../../lib/delete"; import interoperableErrors from '../../../../shared/interoperable-errors'; -import {TreeTable} from "../../lib/tree"; +import {TreeSelectMode, TreeTable} from "../../lib/tree"; @translate() @withForm @@ -100,57 +100,131 @@ export default class CUD extends Component { } } + async onRuleSelectionChangedAsync(sel) { + this.setState({ + selectedRule: sel + }); + } + render() { const t = this.props.t; const isEdit = !!this.props.entity; + const treeEnd = { + key: '__mt-tree-end-drop__', + icon: false, + unselectable: true, + extraClasses: 'mt-tree-end-drop', + beforeActivate: () => false + }; + + const treeEndWide = { // This one is used after a non-folder sibling that has no children + key: '__mt-tree-end-drop__', + icon: false, + unselectable: true, + extraClasses: 'mt-tree-end-drop mt-tree-end-drop-wide', + beforeActivate: () => false + } + const sampleTreeData = [ { key: 'a', title: 'A', expanded: true, + folder: true, children: [ { key: 'aa', title: 'AA', expanded: true, + folder: true, children: [ { key: 'aaa', title: 'AAA', - expanded: true }, { key: 'aab', title: 'AAB', - expanded: true - } + }, + { + key: 'aab', + title: 'AAB', + folder: true + }, + treeEnd ] }, { key: 'ab', title: 'AB', expanded: true, + folder: true, children: [ { key: 'aba', - title: 'ABA', - expanded: true + title: 'ABA' }, { key: 'abb', - title: 'ABB', - expanded: true - } + title: 'ABB' + }, + treeEndWide ] }, + treeEnd ] - } + }, + { + key: 'b', + title: 'B', + expanded: true, + folder: true, + children: [ + { + key: 'ba', + title: 'BA', + expanded: true, + folder: true, + children: [ + { + key: 'baa', + title: 'BAA' + }, + { + key: 'bab', + title: 'BAB' + }, + treeEndWide + ] + }, + { + key: 'bb', + title: 'BB', + expanded: true, + folder: true, + children: [ + { + key: 'bba', + title: 'BBA' + }, + { + key: 'bbb', + title: 'BBB' + }, + treeEndWide + ] + }, + treeEnd + ] + }, + treeEnd ]; return ( +
    {isEdit && {isEdit ? t('Edit Segment') : t('Create Segment')} -
    - - - + +
    ); diff --git a/client/src/lists/subscriptions/List.js b/client/src/lists/subscriptions/List.js index 488974fb..85439cc2 100644 --- a/client/src/lists/subscriptions/List.js +++ b/client/src/lists/subscriptions/List.js @@ -110,7 +110,7 @@ export default class List extends Component {
    - +