123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535 |
- var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
- import Hooks from './../../pluginHooks';
- import { registerPlugin } from './../../plugins';
- import { hasOwnProperty } from './../../helpers/object';
- import { CellRange, Selection } from './../../3rdparty/walkontable/src';
- function CustomBorders() {}
- /** *
- * Current instance (table where borders should be placed)
- */
- var instance;
- /**
- * This plugin enables an option to apply custom borders through the context menu (configurable with context menu key `borders`).
- *
- * To initialize Handsontable with predefined custom borders, provide cell coordinates and border styles in a form of an array.
- *
- * See [Custom Borders](http://docs.handsontable.com/demo-custom-borders.html) demo for more examples.
- *
- * @example
- * ```js
- * ...
- * customBorders: [
- * {range: {
- * from: {row: 1, col: 1},
- * to: {row: 3, col: 4}},
- * left: {},
- * right: {},
- * top: {},
- * bottom: {}
- * }
- * ],
- * ...
- *
- * // or
- * ...
- * customBorders: [
- * {row: 2, col: 2, left: {width: 2, color: 'red'},
- * right: {width: 1, color: 'green'}, top: '', bottom: ''}
- * ],
- * ...
- * ```
- * @private
- * @class CustomBorders
- * @plugin CustomBorders
- */
- /** *
- * Check if plugin should be enabled.
- */
- var checkEnable = function checkEnable(customBorders) {
- if (typeof customBorders === 'boolean') {
- if (customBorders === true) {
- return true;
- }
- }
- if ((typeof customBorders === 'undefined' ? 'undefined' : _typeof(customBorders)) === 'object') {
- if (customBorders.length > 0) {
- return true;
- }
- }
- return false;
- };
- /** *
- * Initialize plugin.
- */
- var init = function init() {
- if (checkEnable(this.getSettings().customBorders)) {
- if (!this.customBorders) {
- instance = this;
- this.customBorders = new CustomBorders();
- }
- }
- };
- /** *
- * Get index of border from the settings.
- *
- * @param {String} className
- * @returns {Number}
- */
- var getSettingIndex = function getSettingIndex(className) {
- for (var i = 0; i < instance.view.wt.selections.length; i++) {
- if (instance.view.wt.selections[i].settings.className == className) {
- return i;
- }
- }
- return -1;
- };
- /** *
- * Insert WalkontableSelection instance into Walkontable settings.
- *
- * @param border
- */
- var insertBorderIntoSettings = function insertBorderIntoSettings(border) {
- var coordinates = {
- row: border.row,
- col: border.col
- };
- var selection = new Selection(border, new CellRange(coordinates, coordinates, coordinates));
- var index = getSettingIndex(border.className);
- if (index >= 0) {
- instance.view.wt.selections[index] = selection;
- } else {
- instance.view.wt.selections.push(selection);
- }
- };
- /** *
- * Prepare borders from setting (single cell).
- *
- * @param {Number} row Row index.
- * @param {Number} col Column index.
- * @param borderObj
- */
- var prepareBorderFromCustomAdded = function prepareBorderFromCustomAdded(row, col, borderObj) {
- var border = createEmptyBorders(row, col);
- border = extendDefaultBorder(border, borderObj);
- this.setCellMeta(row, col, 'borders', border);
- insertBorderIntoSettings(border);
- };
- /** *
- * Prepare borders from setting (object).
- *
- * @param {Object} rowObj
- */
- var prepareBorderFromCustomAddedRange = function prepareBorderFromCustomAddedRange(rowObj) {
- var range = rowObj.range;
- for (var row = range.from.row; row <= range.to.row; row++) {
- for (var col = range.from.col; col <= range.to.col; col++) {
- var border = createEmptyBorders(row, col);
- var add = 0;
- if (row == range.from.row) {
- add++;
- if (hasOwnProperty(rowObj, 'top')) {
- border.top = rowObj.top;
- }
- }
- if (row == range.to.row) {
- add++;
- if (hasOwnProperty(rowObj, 'bottom')) {
- border.bottom = rowObj.bottom;
- }
- }
- if (col == range.from.col) {
- add++;
- if (hasOwnProperty(rowObj, 'left')) {
- border.left = rowObj.left;
- }
- }
- if (col == range.to.col) {
- add++;
- if (hasOwnProperty(rowObj, 'right')) {
- border.right = rowObj.right;
- }
- }
- if (add > 0) {
- this.setCellMeta(row, col, 'borders', border);
- insertBorderIntoSettings(border);
- }
- }
- }
- };
- /** *
- * Create separated class name for borders for each cell.
- *
- * @param {Number} row Row index.
- * @param {Number} col Column index.
- * @returns {String}
- */
- var createClassName = function createClassName(row, col) {
- return 'border_row' + row + 'col' + col;
- };
- /** *
- * Create default single border for each position (top/right/bottom/left).
- *
- * @returns {Object} `{{width: number, color: string}}`
- */
- var createDefaultCustomBorder = function createDefaultCustomBorder() {
- return {
- width: 1,
- color: '#000'
- };
- };
- /** *
- * Create default object for empty border.
- *
- * @returns {Object} `{{hide: boolean}}`
- */
- var createSingleEmptyBorder = function createSingleEmptyBorder() {
- return {
- hide: true
- };
- };
- /** *
- * Create default Handsontable border object.
- *
- * @returns {Object} `{{width: number, color: string, cornerVisible: boolean}}`
- */
- var createDefaultHtBorder = function createDefaultHtBorder() {
- return {
- width: 1,
- color: '#000',
- cornerVisible: false
- };
- };
- /** *
- * Prepare empty border for each cell with all custom borders hidden.
- *
- * @param {Number} row Row index.
- * @param {Number} col Column index.
- * @returns {Object} `{{className: *, border: *, row: *, col: *, top: {hide: boolean}, right: {hide: boolean}, bottom: {hide: boolean}, left: {hide: boolean}}}`
- */
- var createEmptyBorders = function createEmptyBorders(row, col) {
- return {
- className: createClassName(row, col),
- border: createDefaultHtBorder(),
- row: row,
- col: col,
- top: createSingleEmptyBorder(),
- right: createSingleEmptyBorder(),
- bottom: createSingleEmptyBorder(),
- left: createSingleEmptyBorder()
- };
- };
- var extendDefaultBorder = function extendDefaultBorder(defaultBorder, customBorder) {
- if (hasOwnProperty(customBorder, 'border')) {
- defaultBorder.border = customBorder.border;
- }
- if (hasOwnProperty(customBorder, 'top')) {
- defaultBorder.top = customBorder.top;
- }
- if (hasOwnProperty(customBorder, 'right')) {
- defaultBorder.right = customBorder.right;
- }
- if (hasOwnProperty(customBorder, 'bottom')) {
- defaultBorder.bottom = customBorder.bottom;
- }
- if (hasOwnProperty(customBorder, 'left')) {
- defaultBorder.left = customBorder.left;
- }
- return defaultBorder;
- };
- /**
- * Remove borders divs from DOM.
- *
- * @param borderClassName
- */
- var removeBordersFromDom = function removeBordersFromDom(borderClassName) {
- var borders = document.querySelectorAll('.' + borderClassName);
- for (var i = 0; i < borders.length; i++) {
- if (borders[i]) {
- if (borders[i].nodeName != 'TD') {
- var parent = borders[i].parentNode;
- if (parent.parentNode) {
- parent.parentNode.removeChild(parent);
- }
- }
- }
- }
- };
- /** *
- * Remove border (triggered from context menu).
- *
- * @param {Number} row Row index.
- * @param {Number} col Column index.
- */
- var removeAllBorders = function removeAllBorders(row, col) {
- var borderClassName = createClassName(row, col);
- removeBordersFromDom(borderClassName);
- this.removeCellMeta(row, col, 'borders');
- };
- /** *
- * Set borders for each cell re. to border position
- *
- * @param row
- * @param col
- * @param place
- * @param remove
- */
- var setBorder = function setBorder(row, col, place, remove) {
- var bordersMeta = this.getCellMeta(row, col).borders;
- if (!bordersMeta || bordersMeta.border == undefined) {
- bordersMeta = createEmptyBorders(row, col);
- }
- if (remove) {
- bordersMeta[place] = createSingleEmptyBorder();
- } else {
- bordersMeta[place] = createDefaultCustomBorder();
- }
- this.setCellMeta(row, col, 'borders', bordersMeta);
- var borderClassName = createClassName(row, col);
- removeBordersFromDom(borderClassName);
- insertBorderIntoSettings(bordersMeta);
- this.render();
- };
- /** *
- * Prepare borders based on cell and border position
- *
- * @param range
- * @param place
- * @param remove
- */
- var prepareBorder = function prepareBorder(range, place, remove) {
- if (range.from.row == range.to.row && range.from.col == range.to.col) {
- if (place == 'noBorders') {
- removeAllBorders.call(this, range.from.row, range.from.col);
- } else {
- setBorder.call(this, range.from.row, range.from.col, place, remove);
- }
- } else {
- switch (place) {
- case 'noBorders':
- for (var column = range.from.col; column <= range.to.col; column++) {
- for (var row = range.from.row; row <= range.to.row; row++) {
- removeAllBorders.call(this, row, column);
- }
- }
- break;
- case 'top':
- for (var topCol = range.from.col; topCol <= range.to.col; topCol++) {
- setBorder.call(this, range.from.row, topCol, place, remove);
- }
- break;
- case 'right':
- for (var rowRight = range.from.row; rowRight <= range.to.row; rowRight++) {
- setBorder.call(this, rowRight, range.to.col, place);
- }
- break;
- case 'bottom':
- for (var bottomCol = range.from.col; bottomCol <= range.to.col; bottomCol++) {
- setBorder.call(this, range.to.row, bottomCol, place);
- }
- break;
- case 'left':
- for (var rowLeft = range.from.row; rowLeft <= range.to.row; rowLeft++) {
- setBorder.call(this, rowLeft, range.from.col, place);
- }
- break;
- default:
- break;
- }
- }
- };
- /** *
- * Check if selection has border by className
- *
- * @param hot
- * @param direction
- */
- var checkSelectionBorders = function checkSelectionBorders(hot, direction) {
- var atLeastOneHasBorder = false;
- hot.getSelectedRange().forAll(function (r, c) {
- var metaBorders = hot.getCellMeta(r, c).borders;
- if (metaBorders) {
- if (direction) {
- if (!hasOwnProperty(metaBorders[direction], 'hide')) {
- atLeastOneHasBorder = true;
- return false; // breaks forAll
- }
- } else {
- atLeastOneHasBorder = true;
- return false; // breaks forAll
- }
- }
- });
- return atLeastOneHasBorder;
- };
- /** *
- * Mark label in contextMenu as selected
- *
- * @param label
- * @returns {string}
- */
- var markSelected = function markSelected(label) {
- return '<span class="selected">' + String.fromCharCode(10003) + '</span>' + label; // workaround for https://github.com/handsontable/handsontable/issues/1946
- };
- /** *
- * Add border options to context menu
- *
- * @param defaultOptions
- */
- var addBordersOptionsToContextMenu = function addBordersOptionsToContextMenu(defaultOptions) {
- if (!this.getSettings().customBorders) {
- return;
- }
- defaultOptions.items.push({
- name: '---------'
- });
- defaultOptions.items.push({
- key: 'borders',
- name: 'Borders',
- disabled: function disabled() {
- return this.selection.selectedHeader.corner;
- },
- submenu: {
- items: [{
- key: 'borders:top',
- name: function name() {
- var label = 'Top';
- var hasBorder = checkSelectionBorders(this, 'top');
- if (hasBorder) {
- label = markSelected(label);
- }
- return label;
- },
- callback: function callback() {
- var hasBorder = checkSelectionBorders(this, 'top');
- prepareBorder.call(this, this.getSelectedRange(), 'top', hasBorder);
- }
- }, {
- key: 'borders:right',
- name: function name() {
- var label = 'Right';
- var hasBorder = checkSelectionBorders(this, 'right');
- if (hasBorder) {
- label = markSelected(label);
- }
- return label;
- },
- callback: function callback() {
- var hasBorder = checkSelectionBorders(this, 'right');
- prepareBorder.call(this, this.getSelectedRange(), 'right', hasBorder);
- }
- }, {
- key: 'borders:bottom',
- name: function name() {
- var label = 'Bottom';
- var hasBorder = checkSelectionBorders(this, 'bottom');
- if (hasBorder) {
- label = markSelected(label);
- }
- return label;
- },
- callback: function callback() {
- var hasBorder = checkSelectionBorders(this, 'bottom');
- prepareBorder.call(this, this.getSelectedRange(), 'bottom', hasBorder);
- }
- }, {
- key: 'borders:left',
- name: function name() {
- var label = 'Left';
- var hasBorder = checkSelectionBorders(this, 'left');
- if (hasBorder) {
- label = markSelected(label);
- }
- return label;
- },
- callback: function callback() {
- var hasBorder = checkSelectionBorders(this, 'left');
- prepareBorder.call(this, this.getSelectedRange(), 'left', hasBorder);
- }
- }, {
- key: 'borders:no_borders',
- name: 'Remove border(s)',
- callback: function callback() {
- prepareBorder.call(this, this.getSelectedRange(), 'noBorders');
- },
- disabled: function disabled() {
- return !checkSelectionBorders(this);
- }
- }]
- }
- });
- };
- Hooks.getSingleton().add('beforeInit', init);
- Hooks.getSingleton().add('afterContextMenuDefaultOptions', addBordersOptionsToContextMenu);
- Hooks.getSingleton().add('afterInit', function () {
- var customBorders = this.getSettings().customBorders;
- if (customBorders) {
- for (var i = 0; i < customBorders.length; i++) {
- if (customBorders[i].range) {
- prepareBorderFromCustomAddedRange.call(this, customBorders[i]);
- } else {
- prepareBorderFromCustomAdded.call(this, customBorders[i].row, customBorders[i].col, customBorders[i]);
- }
- }
- this.render();
- this.view.wt.draw(true);
- }
- });
|