fc3a92316440d1e15a6a04b47ab07ff2ca7585224706fd7e44f1e27c2101ce2f4a6acc36ba1b47189617a9c9ea379fcf0c3670501cab5e4c943bb94320106f 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
  2. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  3. import { getComputedStyle, getTrimmingContainer, innerWidth, innerHeight, offset, outerHeight, outerWidth } from './../../../helpers/dom/element';
  4. import { stopImmediatePropagation } from './../../../helpers/dom/event';
  5. import { hasOwnProperty } from './../../../helpers/object';
  6. import { isMobileBrowser } from './../../../helpers/browser';
  7. import EventManager from './../../../eventManager';
  8. import CellCoords from './cell/coords';
  9. import Overlay from './overlay/_base.js';
  10. /**
  11. *
  12. */
  13. var Border = function () {
  14. /**
  15. * @param {Walkontable} wotInstance
  16. * @param {Object} settings
  17. */
  18. function Border(wotInstance, settings) {
  19. _classCallCheck(this, Border);
  20. if (!settings) {
  21. return;
  22. }
  23. this.eventManager = new EventManager(wotInstance);
  24. this.instance = wotInstance;
  25. this.wot = wotInstance;
  26. this.settings = settings;
  27. this.mouseDown = false;
  28. this.main = null;
  29. this.top = null;
  30. this.left = null;
  31. this.bottom = null;
  32. this.right = null;
  33. this.topStyle = null;
  34. this.leftStyle = null;
  35. this.bottomStyle = null;
  36. this.rightStyle = null;
  37. this.cornerDefaultStyle = {
  38. width: '5px',
  39. height: '5px',
  40. borderWidth: '2px',
  41. borderStyle: 'solid',
  42. borderColor: '#FFF'
  43. };
  44. this.corner = null;
  45. this.cornerStyle = null;
  46. this.createBorders(settings);
  47. this.registerListeners();
  48. }
  49. /**
  50. * Register all necessary events
  51. */
  52. _createClass(Border, [{
  53. key: 'registerListeners',
  54. value: function registerListeners() {
  55. var _this2 = this;
  56. this.eventManager.addEventListener(document.body, 'mousedown', function () {
  57. return _this2.onMouseDown();
  58. });
  59. this.eventManager.addEventListener(document.body, 'mouseup', function () {
  60. return _this2.onMouseUp();
  61. });
  62. var _loop = function _loop(c, len) {
  63. _this2.eventManager.addEventListener(_this2.main.childNodes[c], 'mouseenter', function (event) {
  64. return _this2.onMouseEnter(event, _this2.main.childNodes[c]);
  65. });
  66. };
  67. for (var c = 0, len = this.main.childNodes.length; c < len; c++) {
  68. _loop(c, len);
  69. }
  70. }
  71. /**
  72. * Mouse down listener
  73. *
  74. * @private
  75. */
  76. }, {
  77. key: 'onMouseDown',
  78. value: function onMouseDown() {
  79. this.mouseDown = true;
  80. }
  81. /**
  82. * Mouse up listener
  83. *
  84. * @private
  85. */
  86. }, {
  87. key: 'onMouseUp',
  88. value: function onMouseUp() {
  89. this.mouseDown = false;
  90. }
  91. /**
  92. * Mouse enter listener for fragment selection functionality.
  93. *
  94. * @private
  95. * @param {Event} event Dom event
  96. * @param {HTMLElement} parentElement Part of border element.
  97. */
  98. }, {
  99. key: 'onMouseEnter',
  100. value: function onMouseEnter(event, parentElement) {
  101. if (!this.mouseDown || !this.wot.getSetting('hideBorderOnMouseDownOver')) {
  102. return;
  103. }
  104. event.preventDefault();
  105. stopImmediatePropagation(event);
  106. var _this = this;
  107. var bounds = parentElement.getBoundingClientRect();
  108. // Hide border to prevents selection jumping when fragmentSelection is enabled.
  109. parentElement.style.display = 'none';
  110. function isOutside(event) {
  111. if (event.clientY < Math.floor(bounds.top)) {
  112. return true;
  113. }
  114. if (event.clientY > Math.ceil(bounds.top + bounds.height)) {
  115. return true;
  116. }
  117. if (event.clientX < Math.floor(bounds.left)) {
  118. return true;
  119. }
  120. if (event.clientX > Math.ceil(bounds.left + bounds.width)) {
  121. return true;
  122. }
  123. }
  124. function handler(event) {
  125. if (isOutside(event)) {
  126. _this.eventManager.removeEventListener(document.body, 'mousemove', handler);
  127. parentElement.style.display = 'block';
  128. }
  129. }
  130. this.eventManager.addEventListener(document.body, 'mousemove', handler);
  131. }
  132. /**
  133. * Create border elements
  134. *
  135. * @param {Object} settings
  136. */
  137. }, {
  138. key: 'createBorders',
  139. value: function createBorders(settings) {
  140. this.main = document.createElement('div');
  141. var borderDivs = ['top', 'left', 'bottom', 'right', 'corner'];
  142. var style = this.main.style;
  143. style.position = 'absolute';
  144. style.top = 0;
  145. style.left = 0;
  146. for (var i = 0; i < 5; i++) {
  147. var position = borderDivs[i];
  148. var div = document.createElement('div');
  149. div.className = 'wtBorder ' + (this.settings.className || ''); // + borderDivs[i];
  150. if (this.settings[position] && this.settings[position].hide) {
  151. div.className += ' hidden';
  152. }
  153. style = div.style;
  154. style.backgroundColor = this.settings[position] && this.settings[position].color ? this.settings[position].color : settings.border.color;
  155. style.height = this.settings[position] && this.settings[position].width ? this.settings[position].width + 'px' : settings.border.width + 'px';
  156. style.width = this.settings[position] && this.settings[position].width ? this.settings[position].width + 'px' : settings.border.width + 'px';
  157. this.main.appendChild(div);
  158. }
  159. this.top = this.main.childNodes[0];
  160. this.left = this.main.childNodes[1];
  161. this.bottom = this.main.childNodes[2];
  162. this.right = this.main.childNodes[3];
  163. this.topStyle = this.top.style;
  164. this.leftStyle = this.left.style;
  165. this.bottomStyle = this.bottom.style;
  166. this.rightStyle = this.right.style;
  167. this.corner = this.main.childNodes[4];
  168. this.corner.className += ' corner';
  169. this.cornerStyle = this.corner.style;
  170. this.cornerStyle.width = this.cornerDefaultStyle.width;
  171. this.cornerStyle.height = this.cornerDefaultStyle.height;
  172. this.cornerStyle.border = [this.cornerDefaultStyle.borderWidth, this.cornerDefaultStyle.borderStyle, this.cornerDefaultStyle.borderColor].join(' ');
  173. if (isMobileBrowser()) {
  174. this.createMultipleSelectorHandles();
  175. }
  176. this.disappear();
  177. if (!this.wot.wtTable.bordersHolder) {
  178. this.wot.wtTable.bordersHolder = document.createElement('div');
  179. this.wot.wtTable.bordersHolder.className = 'htBorders';
  180. this.wot.wtTable.spreader.appendChild(this.wot.wtTable.bordersHolder);
  181. }
  182. this.wot.wtTable.bordersHolder.insertBefore(this.main, this.wot.wtTable.bordersHolder.firstChild);
  183. }
  184. /**
  185. * Create multiple selector handler for mobile devices
  186. */
  187. }, {
  188. key: 'createMultipleSelectorHandles',
  189. value: function createMultipleSelectorHandles() {
  190. this.selectionHandles = {
  191. topLeft: document.createElement('DIV'),
  192. topLeftHitArea: document.createElement('DIV'),
  193. bottomRight: document.createElement('DIV'),
  194. bottomRightHitArea: document.createElement('DIV')
  195. };
  196. var width = 10;
  197. var hitAreaWidth = 40;
  198. this.selectionHandles.topLeft.className = 'topLeftSelectionHandle';
  199. this.selectionHandles.topLeftHitArea.className = 'topLeftSelectionHandle-HitArea';
  200. this.selectionHandles.bottomRight.className = 'bottomRightSelectionHandle';
  201. this.selectionHandles.bottomRightHitArea.className = 'bottomRightSelectionHandle-HitArea';
  202. this.selectionHandles.styles = {
  203. topLeft: this.selectionHandles.topLeft.style,
  204. topLeftHitArea: this.selectionHandles.topLeftHitArea.style,
  205. bottomRight: this.selectionHandles.bottomRight.style,
  206. bottomRightHitArea: this.selectionHandles.bottomRightHitArea.style
  207. };
  208. var hitAreaStyle = {
  209. position: 'absolute',
  210. height: hitAreaWidth + 'px',
  211. width: hitAreaWidth + 'px',
  212. 'border-radius': parseInt(hitAreaWidth / 1.5, 10) + 'px'
  213. };
  214. for (var prop in hitAreaStyle) {
  215. if (hasOwnProperty(hitAreaStyle, prop)) {
  216. this.selectionHandles.styles.bottomRightHitArea[prop] = hitAreaStyle[prop];
  217. this.selectionHandles.styles.topLeftHitArea[prop] = hitAreaStyle[prop];
  218. }
  219. }
  220. var handleStyle = {
  221. position: 'absolute',
  222. height: width + 'px',
  223. width: width + 'px',
  224. 'border-radius': parseInt(width / 1.5, 10) + 'px',
  225. background: '#F5F5FF',
  226. border: '1px solid #4285c8'
  227. };
  228. for (var _prop in handleStyle) {
  229. if (hasOwnProperty(handleStyle, _prop)) {
  230. this.selectionHandles.styles.bottomRight[_prop] = handleStyle[_prop];
  231. this.selectionHandles.styles.topLeft[_prop] = handleStyle[_prop];
  232. }
  233. }
  234. this.main.appendChild(this.selectionHandles.topLeft);
  235. this.main.appendChild(this.selectionHandles.bottomRight);
  236. this.main.appendChild(this.selectionHandles.topLeftHitArea);
  237. this.main.appendChild(this.selectionHandles.bottomRightHitArea);
  238. }
  239. }, {
  240. key: 'isPartRange',
  241. value: function isPartRange(row, col) {
  242. if (this.wot.selections.area.cellRange) {
  243. if (row != this.wot.selections.area.cellRange.to.row || col != this.wot.selections.area.cellRange.to.col) {
  244. return true;
  245. }
  246. }
  247. return false;
  248. }
  249. }, {
  250. key: 'updateMultipleSelectionHandlesPosition',
  251. value: function updateMultipleSelectionHandlesPosition(row, col, top, left, width, height) {
  252. var handleWidth = parseInt(this.selectionHandles.styles.topLeft.width, 10);
  253. var hitAreaWidth = parseInt(this.selectionHandles.styles.topLeftHitArea.width, 10);
  254. this.selectionHandles.styles.topLeft.top = parseInt(top - handleWidth, 10) + 'px';
  255. this.selectionHandles.styles.topLeft.left = parseInt(left - handleWidth, 10) + 'px';
  256. this.selectionHandles.styles.topLeftHitArea.top = parseInt(top - hitAreaWidth / 4 * 3, 10) + 'px';
  257. this.selectionHandles.styles.topLeftHitArea.left = parseInt(left - hitAreaWidth / 4 * 3, 10) + 'px';
  258. this.selectionHandles.styles.bottomRight.top = parseInt(top + height, 10) + 'px';
  259. this.selectionHandles.styles.bottomRight.left = parseInt(left + width, 10) + 'px';
  260. this.selectionHandles.styles.bottomRightHitArea.top = parseInt(top + height - hitAreaWidth / 4, 10) + 'px';
  261. this.selectionHandles.styles.bottomRightHitArea.left = parseInt(left + width - hitAreaWidth / 4, 10) + 'px';
  262. if (this.settings.border.multipleSelectionHandlesVisible && this.settings.border.multipleSelectionHandlesVisible()) {
  263. this.selectionHandles.styles.topLeft.display = 'block';
  264. this.selectionHandles.styles.topLeftHitArea.display = 'block';
  265. if (this.isPartRange(row, col)) {
  266. this.selectionHandles.styles.bottomRight.display = 'none';
  267. this.selectionHandles.styles.bottomRightHitArea.display = 'none';
  268. } else {
  269. this.selectionHandles.styles.bottomRight.display = 'block';
  270. this.selectionHandles.styles.bottomRightHitArea.display = 'block';
  271. }
  272. } else {
  273. this.selectionHandles.styles.topLeft.display = 'none';
  274. this.selectionHandles.styles.bottomRight.display = 'none';
  275. this.selectionHandles.styles.topLeftHitArea.display = 'none';
  276. this.selectionHandles.styles.bottomRightHitArea.display = 'none';
  277. }
  278. if (row == this.wot.wtSettings.getSetting('fixedRowsTop') || col == this.wot.wtSettings.getSetting('fixedColumnsLeft')) {
  279. this.selectionHandles.styles.topLeft.zIndex = '9999';
  280. this.selectionHandles.styles.topLeftHitArea.zIndex = '9999';
  281. } else {
  282. this.selectionHandles.styles.topLeft.zIndex = '';
  283. this.selectionHandles.styles.topLeftHitArea.zIndex = '';
  284. }
  285. }
  286. /**
  287. * Show border around one or many cells
  288. *
  289. * @param {Array} corners
  290. */
  291. }, {
  292. key: 'appear',
  293. value: function appear(corners) {
  294. if (this.disabled) {
  295. return;
  296. }
  297. var isMultiple, fromTD, toTD, fromOffset, toOffset, containerOffset, top, minTop, left, minLeft, height, width, fromRow, fromColumn, toRow, toColumn, trimmingContainer, cornerOverlappingContainer, ilen;
  298. ilen = this.wot.wtTable.getRenderedRowsCount();
  299. for (var i = 0; i < ilen; i++) {
  300. var s = this.wot.wtTable.rowFilter.renderedToSource(i);
  301. if (s >= corners[0] && s <= corners[2]) {
  302. fromRow = s;
  303. break;
  304. }
  305. }
  306. for (var _i = ilen - 1; _i >= 0; _i--) {
  307. var _s = this.wot.wtTable.rowFilter.renderedToSource(_i);
  308. if (_s >= corners[0] && _s <= corners[2]) {
  309. toRow = _s;
  310. break;
  311. }
  312. }
  313. ilen = this.wot.wtTable.getRenderedColumnsCount();
  314. for (var _i2 = 0; _i2 < ilen; _i2++) {
  315. var _s2 = this.wot.wtTable.columnFilter.renderedToSource(_i2);
  316. if (_s2 >= corners[1] && _s2 <= corners[3]) {
  317. fromColumn = _s2;
  318. break;
  319. }
  320. }
  321. for (var _i3 = ilen - 1; _i3 >= 0; _i3--) {
  322. var _s3 = this.wot.wtTable.columnFilter.renderedToSource(_i3);
  323. if (_s3 >= corners[1] && _s3 <= corners[3]) {
  324. toColumn = _s3;
  325. break;
  326. }
  327. }
  328. if (fromRow === void 0 || fromColumn === void 0) {
  329. this.disappear();
  330. return;
  331. }
  332. isMultiple = fromRow !== toRow || fromColumn !== toColumn;
  333. fromTD = this.wot.wtTable.getCell(new CellCoords(fromRow, fromColumn));
  334. toTD = isMultiple ? this.wot.wtTable.getCell(new CellCoords(toRow, toColumn)) : fromTD;
  335. fromOffset = offset(fromTD);
  336. toOffset = isMultiple ? offset(toTD) : fromOffset;
  337. containerOffset = offset(this.wot.wtTable.TABLE);
  338. minTop = fromOffset.top;
  339. height = toOffset.top + outerHeight(toTD) - minTop;
  340. minLeft = fromOffset.left;
  341. width = toOffset.left + outerWidth(toTD) - minLeft;
  342. top = minTop - containerOffset.top - 1;
  343. left = minLeft - containerOffset.left - 1;
  344. var style = getComputedStyle(fromTD);
  345. if (parseInt(style.borderTopWidth, 10) > 0) {
  346. top += 1;
  347. height = height > 0 ? height - 1 : 0;
  348. }
  349. if (parseInt(style.borderLeftWidth, 10) > 0) {
  350. left += 1;
  351. width = width > 0 ? width - 1 : 0;
  352. }
  353. this.topStyle.top = top + 'px';
  354. this.topStyle.left = left + 'px';
  355. this.topStyle.width = width + 'px';
  356. this.topStyle.display = 'block';
  357. this.leftStyle.top = top + 'px';
  358. this.leftStyle.left = left + 'px';
  359. this.leftStyle.height = height + 'px';
  360. this.leftStyle.display = 'block';
  361. var delta = Math.floor(this.settings.border.width / 2);
  362. this.bottomStyle.top = top + height - delta + 'px';
  363. this.bottomStyle.left = left + 'px';
  364. this.bottomStyle.width = width + 'px';
  365. this.bottomStyle.display = 'block';
  366. this.rightStyle.top = top + 'px';
  367. this.rightStyle.left = left + width - delta + 'px';
  368. this.rightStyle.height = height + 1 + 'px';
  369. this.rightStyle.display = 'block';
  370. if (isMobileBrowser() || !this.hasSetting(this.settings.border.cornerVisible) || this.isPartRange(toRow, toColumn)) {
  371. this.cornerStyle.display = 'none';
  372. } else {
  373. this.cornerStyle.top = top + height - 4 + 'px';
  374. this.cornerStyle.left = left + width - 4 + 'px';
  375. this.cornerStyle.borderRightWidth = this.cornerDefaultStyle.borderWidth;
  376. this.cornerStyle.width = this.cornerDefaultStyle.width;
  377. // Hide the fill handle, so the possible further adjustments won't force unneeded scrollbars.
  378. this.cornerStyle.display = 'none';
  379. trimmingContainer = getTrimmingContainer(this.wot.wtTable.TABLE);
  380. if (toColumn === this.wot.getSetting('totalColumns') - 1) {
  381. cornerOverlappingContainer = toTD.offsetLeft + outerWidth(toTD) + parseInt(this.cornerDefaultStyle.width, 10) / 2 >= innerWidth(trimmingContainer);
  382. if (cornerOverlappingContainer) {
  383. this.cornerStyle.left = Math.floor(left + width - 3 - parseInt(this.cornerDefaultStyle.width, 10) / 2) + 'px';
  384. this.cornerStyle.borderRightWidth = 0;
  385. }
  386. }
  387. if (toRow === this.wot.getSetting('totalRows') - 1) {
  388. cornerOverlappingContainer = toTD.offsetTop + outerHeight(toTD) + parseInt(this.cornerDefaultStyle.height, 10) / 2 >= innerHeight(trimmingContainer);
  389. if (cornerOverlappingContainer) {
  390. this.cornerStyle.top = Math.floor(top + height - 3 - parseInt(this.cornerDefaultStyle.height, 10) / 2) + 'px';
  391. this.cornerStyle.borderBottomWidth = 0;
  392. }
  393. }
  394. this.cornerStyle.display = 'block';
  395. }
  396. if (isMobileBrowser()) {
  397. this.updateMultipleSelectionHandlesPosition(fromRow, fromColumn, top, left, width, height);
  398. }
  399. }
  400. /**
  401. * Hide border
  402. */
  403. }, {
  404. key: 'disappear',
  405. value: function disappear() {
  406. this.topStyle.display = 'none';
  407. this.leftStyle.display = 'none';
  408. this.bottomStyle.display = 'none';
  409. this.rightStyle.display = 'none';
  410. this.cornerStyle.display = 'none';
  411. if (isMobileBrowser()) {
  412. this.selectionHandles.styles.topLeft.display = 'none';
  413. this.selectionHandles.styles.bottomRight.display = 'none';
  414. }
  415. }
  416. /**
  417. * @param {Function} setting
  418. * @returns {*}
  419. */
  420. }, {
  421. key: 'hasSetting',
  422. value: function hasSetting(setting) {
  423. if (typeof setting === 'function') {
  424. return setting();
  425. }
  426. return !!setting;
  427. }
  428. }]);
  429. return Border;
  430. }();
  431. export default Border;