Skip to content

Commit

Permalink
refactor row.js to use register_id/callback pattern, move drag/drop out
Browse files Browse the repository at this point in the history
of view.js and into separate file, change dragdrop handlers to
underscore_naming
  • Loading branch information
sc1f authored and texodus committed Nov 7, 2018
1 parent 4a7186c commit 42612d8
Show file tree
Hide file tree
Showing 12 changed files with 316 additions and 280 deletions.
3 changes: 1 addition & 2 deletions packages/perspective-viewer-highcharts/src/js/draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ import {COLORS_10, COLORS_20} from "./externals.js";
import {color_axis} from "./color_axis.js";
import {make_tree_data, make_y_data, make_xy_data, make_xyz_data, make_xy_column_data} from "./series.js";
import {set_boost, set_category_axis, set_both_axis, default_config, set_tick_size} from "./config.js";
import {bindTemplate} from "../../../perspective-viewer/src/js/utils";
import {detectIE} from "../../../perspective/src/js/utils";
import {bindTemplate, detectIE} from "../../../perspective-viewer/src/js/utils";

export const PRIVATE = Symbol("Highcharts private");

Expand Down
4 changes: 2 additions & 2 deletions packages/perspective-viewer/src/html/computed_column.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<div class="psp-cc__container" style="margin-top:-7px;">
<div class="psp-cc__content">
<div id="psp-cc-computation__type"></div>
<span contentEditable=true type="text" required maxlength="25" size="10" autocomplete="off" id="psp-cc-name" ondragover="disallowDrop(event)"></span>
<span contentEditable=true type="text" required maxlength="25" size="10" autocomplete="off" id="psp-cc-name"></span>
</div>
<div class="psp-cc__content psp-cc__content--nomargin">
<span class="psp-cc__label psp-cc__error" id="psp-cc__error--name"></span>
Expand All @@ -30,7 +30,7 @@
</div>
<div class="psp-cc__container" style="margin-top:-12px;">
<div id="psp-cc-computation-inputs">
<!--<div class="psp-cc-computation__input-column" drop-target ondragenter="dragEnter(event)"></div>-->
<!--<div class="psp-cc-computation__input-column" drop-target></div>-->
</div>
</div>
</div>
Expand Down
12 changes: 6 additions & 6 deletions packages/perspective-viewer/src/html/view.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
</select>
</div>
<div id="columns_container" style="visibility: hidden">
<ul id='active_columns' ondragenter="dragEnter(event)"></ul>
<ul id='active_columns'></ul>
<div id='divider'></div>
<div id="sub_columns">
<ul id='inactive_columns'></ul>
Expand All @@ -30,7 +30,7 @@
<div class="column noselect">
<div id='top_panel'>
<div class="rrow">
<div id="row_pivots" ondragover="allowDrop(event)" ondragleave="disallowDrop(event)" ondragenter="dragEnter(event)">
<div id="row_pivots">
<div class="psp-text-field">
<ul class="psp-text-field__input" for="row-pivots"></ul>
<label for="row_pivots"></label>
Expand All @@ -39,23 +39,23 @@
</div>
<span id="transpose_button" class="rrow centered">&#x2715;</span>
<div class="rrow">
<div id="column_pivots" ondragover="allowDrop(event)" ondragleave="disallowDrop(event)" ondragenter="dragEnter(event)">
<div id="column_pivots">
<div class="psp-text-field">
<ul class="psp-text-field__input" for="column-pivots"></ul>
<label for="column_pivots"></label>
</div>
</div>
</div>
<div class="rrow">
<div id="sort" ondragover="allowDrop(event)" ondragleave="disallowDrop(event)" ondragenter="dragEnter(event)">
<div id="sort">
<div class="psp-text-field">
<ul class="psp-text-field__input" for="sort"></ul>
<label for="sort"></label>
</div>
</div>
</div>
<div class="rrow" style='flex-grow:3;height:auto;flex:1 1 400px;max-width:none'>
<div id="filters" ondragover="allowDrop(event)" ondragleave="disallowDrop(event)" ondragenter="dragEnter(event)">
<div id="filters">
<div class="psp-text-field">
<ul class="psp-text-field__input" for='filters'></ul>
<label for="filters"></label>
Expand All @@ -70,7 +70,7 @@

<div id="config_button" class="noselect"></div>

<div id='drop_target' ondragover="allowDrop(event)">
<div id='drop_target'>
<div id='drop_target_inner'>

</div>
Expand Down
3 changes: 3 additions & 0 deletions packages/perspective-viewer/src/js/computed_column.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import template from "../html/computed_column.html";

import style from "../less/computed_column.less";

import {disallow_drop} from "./dragdrop.js";

polyfill({});

// Computations
Expand Down Expand Up @@ -486,6 +488,7 @@ class ComputedColumn extends HTMLElement {
_register_callbacks() {
this._close_button.addEventListener("click", this._close_computed_column.bind(this));
this._computation_selector.addEventListener("change", this._update_computation.bind(this));
this._column_name_input.addEventListener("dragover", disallow_drop.bind(this));
this._column_name_input.addEventListener("keyup", event => {
this.state["name_edited"] = this._column_name_input.innerText && this._column_name_input.innerText.length > 0;
this._set_column_name(event);
Expand Down
171 changes: 171 additions & 0 deletions packages/perspective-viewer/src/js/dragdrop.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
/******************************************************************************
*
* Copyright (c) 2018, the Perspective Authors.
*
* This file is part of the Perspective library, distributed under the terms of
* the Apache License 2.0. The full license can be found in the LICENSE file.
*
*/

import {detectIE} from "./utils.js";

function calc_index(event) {
if (this._active_columns.children.length == 0) {
return 0;
} else {
for (let cidx in this._active_columns.children) {
let child = this._active_columns.children[cidx];
if (child.offsetTop + child.offsetHeight > event.offsetY + this._active_columns.scrollTop) {
return parseInt(cidx);
}
}
return this._active_columns.children.length;
}
}

export function undrag(event) {
let div = event.target.getRootNode().host;
let parent = div;
if (parent.tagName === "PERSPECTIVE-VIEWER") {
parent = event.target.parentElement;
} else {
parent = div.parentElement;
}
let idx = Array.prototype.slice.call(parent.children).indexOf(div.tagName === "PERSPECTIVE-ROW" ? div : event.target);
let attr_name = parent.getAttribute("for");
let pivots = JSON.parse(this.getAttribute(attr_name));
pivots.splice(idx, 1);
this.setAttribute(attr_name, JSON.stringify(pivots));

if (detectIE()) {
window.ShadyCSS.styleDocument();
}
}

export function drop(ev) {
ev.preventDefault();
ev.currentTarget.classList.remove("dropping");
if (this._drop_target_hover) {
this._drop_target_hover.removeAttribute("drop-target");
}
let data = ev.dataTransfer.getData("text");
if (!data) return;
data = JSON.parse(data);

// Update the columns attribute
let name = ev.currentTarget.querySelector("ul").getAttribute("for") || ev.currentTarget.getAttribute("id").replace("_", "-");
let columns = JSON.parse(this.getAttribute(name) || "[]");
let data_index = columns.indexOf(data[0]);
if (data_index !== -1) {
columns.splice(data_index, 1);
}
if (name.indexOf("filter") > -1) {
this.setAttribute(name, JSON.stringify(columns.concat([data])));
} else if (name.indexOf("sort") > -1) {
this.setAttribute(name, JSON.stringify(columns.concat([[data[0], "asc"]])));
} else {
this.setAttribute(name, JSON.stringify(columns.concat([data[0]])));
}

// Deselect the dropped column
if (this._plugin.deselectMode === "pivots" && this._visible_column_count() > 1 && name !== "sort" && name !== "filter") {
for (let x of this.shadowRoot.querySelectorAll("#active_columns perspective-row")) {
if (x.getAttribute("name") === data[0]) {
this._active_columns.removeChild(x);
break;
}
}
this._update_column_view();
}

this._debounce_update();
}

// Handle column actions
export function column_undrag(event) {
let data = event.target.parentElement.parentElement;
Array.prototype.slice.call(this._active_columns.children).map(x => {
x.className = "";
});
if (this._visible_column_count() > 1 && event.dataTransfer.dropEffect !== "move") {
this._active_columns.removeChild(data);
this._update_column_view();
}
this._active_columns.classList.remove("dropping");
}

export function column_dragleave(event) {
let src = event.relatedTarget;
while (src && src !== this._active_columns) {
src = src.parentElement;
}
if (src === null) {
this._active_columns.classList.remove("dropping");
if (this._drop_target_hover.parentElement === this._active_columns) {
this._active_columns.removeChild(this._drop_target_hover);
}
if (this._original_index !== -1) {
this._active_columns.insertBefore(this._drop_target_hover, this._active_columns.children[this._original_index]);
}
this._drop_target_hover.removeAttribute("drop-target");
}
}

export function column_dragover(event) {
event.preventDefault();
event.dataTransfer.dropEffect = "move";
if (event.currentTarget.className !== "dropping") {
event.currentTarget.classList.add("dropping");
}
if (!this._drop_target_hover.hasAttribute("drop-target")) {
this._drop_target_hover.setAttribute("drop-target", true);
}
let new_index = calc_index.call(this, event);
let current_index = Array.prototype.slice.call(this._active_columns.children).indexOf(this._drop_target_hover);
if (current_index < new_index) new_index += 1;
if (new_index < this._active_columns.children.length) {
if (!this._active_columns.children[new_index].hasAttribute("drop-target")) {
this._active_columns.insertBefore(this._drop_target_hover, this._active_columns.children[new_index]);
}
} else {
if (!this._active_columns.children[this._active_columns.children.length - 1].hasAttribute("drop-target")) {
this._active_columns.appendChild(this._drop_target_hover);
}
}
}

export function column_drop(ev) {
ev.preventDefault();
ev.currentTarget.classList.remove("dropping");
if (this._drop_target_hover.parentElement === this._active_columns) {
this._drop_target_hover.removeAttribute("drop-target");
}
Array.prototype.slice.call(this._active_columns.children).map(x => {
x.className = "";
});
let data = ev.dataTransfer.getData("text");
if (!data) return;

this._update_column_view();
}

export function drag_enter(ev) {
ev.stopPropagation();
ev.preventDefault();
ev.currentTarget.classList.add("dropping");
}

export function allow_drop(ev) {
ev.stopPropagation();
ev.preventDefault();
ev.currentTarget.classList.add("dropping");
ev.dataTransfer.dropEffect = "move";
}

export function disallow_drop(ev) {
if (ev.currentTarget == ev.target) {
ev.stopPropagation();
ev.preventDefault();
ev.currentTarget.classList.remove("dropping");
}
}
94 changes: 51 additions & 43 deletions packages/perspective-viewer/src/js/row.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,17 @@ class Row extends HTMLElement {
// computed_input_column.textContent = data.input_column;
}

_get_computed_data() {
const data = JSON.parse(this.getAttribute("computed_column"));
return {
column_name: data.column_name,
input_columns: data.input_columns,
input_type: data.input_type,
computation: data.computation,
type: data.type
};
}

_update_filter(event) {
let filter_operand = this.shadowRoot.querySelector("#filter_operand");
let filter_operator = this.shadowRoot.querySelector("#filter_operator");
Expand All @@ -178,64 +189,56 @@ class Row extends HTMLElement {
this.dispatchEvent(new CustomEvent("filter-selected", {detail: event}));
}

_get_computed_data() {
const data = JSON.parse(this.getAttribute("computed_column"));
return {
column_name: data.column_name,
input_columns: data.input_columns,
input_type: data.input_type,
computation: data.computation,
type: data.type
};
_set_data_transfer(event) {
if (this.hasAttribute("filter")) {
let {operator, operand} = JSON.parse(this.getAttribute("filter"));
event.dataTransfer.setData("text", JSON.stringify([this.getAttribute("name"), operator, operand, this.getAttribute("type"), this.getAttribute("aggregate")]));
} else {
event.dataTransfer.setData(
"text",
JSON.stringify([this.getAttribute("name"), perspective.FILTER_DEFAULTS[this.getAttribute("type")], undefined, this.getAttribute("type"), this.getAttribute("aggregate")])
);
}
this.dispatchEvent(new CustomEvent("row-drag"));
}

connectedCallback() {
let li = this.shadowRoot.querySelector(".row_draggable");
li.addEventListener("dragstart", ev => {
if (this.hasAttribute("filter")) {
let {operator, operand} = JSON.parse(this.getAttribute("filter"));
ev.dataTransfer.setData("text", JSON.stringify([this.getAttribute("name"), operator, operand, this.getAttribute("type"), this.getAttribute("aggregate")]));
} else {
ev.dataTransfer.setData(
"text",
JSON.stringify([this.getAttribute("name"), perspective.FILTER_DEFAULTS[this.getAttribute("type")], undefined, this.getAttribute("type"), this.getAttribute("aggregate")])
);
}
this.dispatchEvent(new CustomEvent("row-drag"));
});
li.addEventListener("dragend", () => {
_register_ids() {
this._li = this.shadowRoot.querySelector(".row_draggable");
this._visible = this.shadowRoot.querySelector(".is_visible");
this._row_close = this.shadowRoot.querySelector("#row_close");
this._agg_dropdown = this.shadowRoot.querySelector("#column_aggregate");
this._sort_order = this.shadowRoot.querySelector("#sort_order");
this._filter_operand = this.shadowRoot.querySelector("#filter_operand");
this._filter_operator = this.shadowRoot.querySelector("#filter_operator");
this._edit_computed_column_button = this.shadowRoot.querySelector("#row_edit");
}

_register_callbacks() {
this._li.addEventListener("dragstart", this._set_data_transfer.bind(this));
this._li.addEventListener("dragend", () => {
this.dispatchEvent(new CustomEvent("row-dragend"));
});
let visible = this.shadowRoot.querySelector(".is_visible");
visible.addEventListener("mousedown", event => this.dispatchEvent(new CustomEvent("visibility-clicked", {detail: event})));
this.shadowRoot.querySelector("#row_close").addEventListener("mousedown", event => this.dispatchEvent(new CustomEvent("close-clicked", {detail: event})));

let agg_dropdown = this.shadowRoot.querySelector("#column_aggregate");
agg_dropdown.addEventListener("change", event => {
this.setAttribute("aggregate", agg_dropdown.value);
this._visible.addEventListener("mousedown", event => this.dispatchEvent(new CustomEvent("visibility-clicked", {detail: event})));
this._row_close.addEventListener("mousedown", event => this.dispatchEvent(new CustomEvent("close-clicked", {detail: event})));
this._agg_dropdown.addEventListener("change", event => {
this.setAttribute("aggregate", this._agg_dropdown.value);
this.dispatchEvent(new CustomEvent("aggregate-selected", {detail: event}));
});

let sort_order = this.shadowRoot.querySelector("#sort_order");
sort_order.addEventListener("click", event => {
this._sort_order.addEventListener("click", event => {
const current = this.getAttribute("sort-order");
const order = (perspective.SORT_ORDERS.indexOf(current) + 1) % 5;
this.setAttribute("sort-order", perspective.SORT_ORDERS[order]);
this.dispatchEvent(new CustomEvent("sort-order", {detail: event}));
});

let filter_operand = this.shadowRoot.querySelector("#filter_operand");
let filter_operator = this.shadowRoot.querySelector("#filter_operator");
let debounced_filter = _.debounce(event => this._update_filter(event), 50);
filter_operator.addEventListener("change", () => {
filter_operator.style.width = get_text_width(filter_operator.value);
const debounced_filter = _.debounce(event => this._update_filter(event), 50);
this._filter_operator.addEventListener("change", () => {
this._filter_operator.style.width = get_text_width(this._filter_operator.value);
const filter_input = this.shadowRoot.querySelector("#filter_operand");
filter_input.style.width = get_text_width("" + filter_operand.value, 30);
filter_input.style.width = get_text_width("" + this._filter_operand.value, 30);
debounced_filter();
});

const edit_computed_column_button = this.shadowRoot.querySelector("#row_edit");
edit_computed_column_button.addEventListener("click", () => {
this._edit_computed_column_button.addEventListener("click", () => {
this.dispatchEvent(
new CustomEvent("perspective-computed-column-edit", {
bubbles: true,
Expand All @@ -244,4 +247,9 @@ class Row extends HTMLElement {
);
});
}

connectedCallback() {
this._register_ids();
this._register_callbacks();
}
}
Loading

0 comments on commit 42612d8

Please sign in to comment.