1 /** 2 * @fileOverview Contains the jMatrixBrowse plug-in code. 3 * 4 * The core file for jMatrixBrowse that manages the initialization of the 5 * component and manages interaction with different parts of the components. 6 * 7 * @version 0.1 8 * @author Pulkit Goyal <pulkit110@gmail.com> 9 */ 10 11 /** 12 * See (http://jquery.com/). 13 * @name jQuery 14 * @class 15 * See the jQuery Library (http://jquery.com/) for full details. This just 16 * documents the function and classes that are added to jQuery by this plug-in. 17 */ 18 19 /** 20 * See (http://jquery.com/) 21 * @name fn 22 * @class 23 * See the jQuery Library (http://jquery.com/) for full details. This just 24 * documents the function and classes that are added to jQuery by this plug-in. 25 * @memberOf jQuery 26 */ 27 28 /** 29 * jMatrixBrowseNS - Namespace encapsulating jMatrixBrowse. 30 * 31 * @namespace jMatrixBrowseNS 32 */ 33 var jMatrixBrowseNs = jMatrixBrowseNs || {}; 34 35 (function(jQuery, jMatrixBrowseNs) { 36 /** 37 * jMatrixBrowse - a jQuery plugin to create large draggable(like Google Maps) 38 * matrices. 39 * 40 * @class jMatrixBrowse 41 * @memberOf jQuery.fn 42 */ 43 jQuery.fn.jMatrixBrowse = function() { 44 45 var _self = this; 46 var _renderer; // jMatrixBrowse renderer. 47 var _configuration; // jMatrixBrowse configuration manager. 48 var _api; // API handler. 49 var _backgroundDataManager; // Background data manager. 50 var _elem; 51 52 //Public API 53 /** 54 * Reload data in the matrix for the visible window. 55 */ 56 this.reloadData = function() { 57 var cellWindow = _configuration.getCellWindow(_renderer.currentCell); 58 if (cellWindow == undefined) { 59 console.error('Unable to get cell window.'); 60 return; 61 } 62 var response = _api.getResponse(cellWindow); 63 64 if (response && response.data) { 65 for (var i = 0; i < response.data.length; ++i) { 66 for (var j = 0; j < response.data[i].length; ++j) { 67 var cellData = response.data[i][j]; 68 jQuery(_renderer.getCellElements()[i][j]).html(cellData); 69 } 70 } 71 } 72 } 73 74 this.getPosition = function() { 75 return _renderer.currentCell; 76 }; 77 78 // initialize the plugin. 79 init(this); 80 81 // Private methods 82 /** 83 * Initialize the jMatrixBrowse. 84 * @param {jQuery object} elem - the element to which to attach the jMatrixBrowse. 85 */ 86 function init(elem) { 87 _elem = jQuery('<div/>', { 88 position: 'absolute' 89 }).appendTo(elem); 90 91 // Initialize mock api 92 _api = new jMatrixBrowseNs.APIHandler('test'); 93 94 // Initialize configuration, get user options and extend with default. 95 _configuration = new jMatrixBrowseNs.Configuration(elem, _api); 96 97 // Initialize the jMatrixBrowseRenderer 98 _renderer = new jMatrixBrowseNs.jMatrixBrowseRenderer(_elem, _configuration, _api); 99 100 // Load data after renderer completes initialization. 101 _elem.bind('jMatrixBrowseRendererInitialized', function() { 102 _self.reloadData(); 103 }); 104 105 // Listen to events to implement reloading of data and headers 106 // Listen for drag and reposition cells 107 _elem.bind('jMatrixBrowseDrag', function (event) { 108 // Reposition matrix cells 109 checkAndRepositionCells(); 110 // Reposition headers 111 checkAndRepositionHeaders(); 112 }); 113 114 _elem.bind('jMatrixBrowseAnimationStep', function (event) { 115 // Reposition matrix cells 116 checkAndRepositionCells(); 117 // Reposition headers 118 checkAndRepositionHeaders(); 119 }); 120 121 // Listen for drag stop and reposition cells, needed when there is a quick drag. 122 _elem.bind('jMatrixBrowseDragStop', function (event) { 123 if (_configuration.isSnapEnabled() && !_renderer.getIsAnimating()) { 124 _renderer.snapToGrid(); 125 } 126 // Reposition matrix cells 127 checkAndRepositionCells(); 128 // Reposition headers 129 checkAndRepositionHeaders(); 130 }); 131 132 _elem.bind('jMatrixBrowseAnimationComplete', function (event) { 133 if (_configuration.isSnapEnabled()) { 134 _renderer.snapToGrid(); 135 } 136 // Reposition matrix cells 137 checkAndRepositionCells(); 138 // Reposition headers 139 checkAndRepositionHeaders(); 140 }); 141 142 // Listen for change and reload new data 143 _elem.bind('jMatrixBrowseChange', function (event) { 144 reloadData({ 145 currentCell: event.currentCell, 146 previousCell: event.previousCell, 147 direction: event.direction 148 }); 149 }); 150 151 // Listen for click event 152 _elem.bind('jMatrixBrowseClick', function (event) { 153 console.log('click: ' + event.row + ', ' + event.col); 154 }); 155 156 bindShortcuts(); 157 158 // Begin loading data in the background. 159 _backgroundDataManager = new jMatrixBrowseNs.BackgroundDataManager(_elem, _api, _configuration); 160 } 161 162 /** 163 * Computes the new cell coordinates when a drag results in overflow. 164 * @param {Number} overflow - Type of the overflow. 165 */ 166 function computeNewCellCoordinates(overflow) { 167 168 switch(overflow) { 169 case jMatrixBrowseNs.Constants.OVERFLOW_TOP: 170 ++_renderer.currentCell.row; 171 break; 172 173 case jMatrixBrowseNs.Constants.OVERFLOW_BOTTOM: 174 --_renderer.currentCell.row; 175 break; 176 177 case jMatrixBrowseNs.Constants.OVERFLOW_LEFT: 178 ++_renderer.currentCell.col; 179 break; 180 181 case jMatrixBrowseNs.Constants.OVERFLOW_RIGHT: 182 --_renderer.currentCell.col; 183 break; 184 } 185 } 186 187 // TODO: Move to Utils or Renderer and use in generate positions for jMatrixBrowseRenderer. 188 /** 189 * Check if the drag is valid. 190 * @param {Number} overflow - Type of the overflow to check for. 191 * @returns {boolean} true if the drag is valid. 192 */ 193 function isValidDrag(overflow) { 194 switch(overflow) { 195 case jMatrixBrowseNs.Constants.OVERFLOW_TOP: 196 if (_renderer.currentCell.row - _configuration.getNumberOfBackgroundCells() + _renderer.getCellElements().length - 1 >= _api.getMatrixSize().height-1) 197 return false; 198 return true; 199 200 case jMatrixBrowseNs.Constants.OVERFLOW_BOTTOM: 201 if (_renderer.currentCell.row <= 0 + _configuration.getNumberOfBackgroundCells()) 202 return false; 203 return true; 204 205 case jMatrixBrowseNs.Constants.OVERFLOW_LEFT: 206 if (_renderer.currentCell.col - _configuration.getNumberOfBackgroundCells() + _renderer.getCellElements()[0].length - 1 >= _api.getMatrixSize().width-1) 207 return false; 208 return true; 209 210 case jMatrixBrowseNs.Constants.OVERFLOW_RIGHT: 211 if (_renderer.currentCell.col <= 0 + _configuration.getNumberOfBackgroundCells()) 212 return false; 213 return true; 214 } 215 } 216 217 /** 218 * Check and resposition cells that are overflowing. 219 */ 220 function checkAndRepositionCells() { 221 var cellsRepositioned = false; 222 223 // Row on top might overflow from the top. 224 cellsRepositioned = checkAndRepositionCellRow(_renderer.getCellElements(), _renderer.getContainer(), 1, jMatrixBrowseNs.Constants.OVERFLOW_TOP) || cellsRepositioned; 225 // Row on bottom might overflow from the bottom. 226 cellsRepositioned = checkAndRepositionCellRow(_renderer.getCellElements(), _renderer.getContainer(), _renderer.getCellElements().length-2, jMatrixBrowseNs.Constants.OVERFLOW_BOTTOM) || cellsRepositioned; 227 // Column on left might overflow from the left. 228 cellsRepositioned = checkAndRepositionCellCol(_renderer.getCellElements(), _renderer.getContainer(), 1, jMatrixBrowseNs.Constants.OVERFLOW_LEFT) || cellsRepositioned; 229 // Column on right might overflow from the right. 230 cellsRepositioned = checkAndRepositionCellCol(_renderer.getCellElements(), _renderer.getContainer(), _renderer.getCellElements()[0].length-2, jMatrixBrowseNs.Constants.OVERFLOW_RIGHT) || cellsRepositioned; 231 232 // For handling quick drags, check for positioning again. 233 if (cellsRepositioned) { 234 checkAndRepositionCells(); 235 checkAndRepositionHeaders(); 236 } 237 } 238 239 /** 240 * Check and resposition headers according to cell positions. 241 */ 242 function checkAndRepositionHeaders() { 243 checkAndRepositionRowHeader(_renderer.getHeaders().row); 244 checkAndRepositionColumnHeader(_renderer.getHeaders().col); 245 } 246 247 /** 248 * Check and resposition headers according to cell positions. 249 * @param header - row header container 250 */ 251 function checkAndRepositionRowHeader(header) { 252 header.children().each(function(index, element) { 253 var containerOffset = _renderer.getContainer().offset(); 254 var elementOffset = jQuery(_renderer.getCellElements()[index][0]).offset(); 255 var top = elementOffset.top - containerOffset.top; 256 257 jQuery(element).css({ 258 top: top 259 }); 260 }); 261 } 262 263 /** 264 * Check and resposition headers according to cell positions. 265 * @param header - column header container 266 */ 267 function checkAndRepositionColumnHeader(header) { 268 header.children().each(function(index, element) { 269 var containerOffset = _renderer.getContainer().offset(); 270 var elementOffset = jQuery(_renderer.getCellElements()[0][index]).offset(); 271 var left = elementOffset.left - containerOffset.left; 272 jQuery(element).css({ 273 left: left 274 }); 275 }); 276 } 277 278 /** 279 * Checks if the given row is overflowing and repositions if necessary. 280 * @param {matrix} cellElements - The matrix of DOM objects representing cells. 281 * @param {jQuery Object} container - The container against which to check the overflow. 282 * @param {Number} row - Index of row to check the overflow for. 283 * @param {Number} overflow - Type of the overflow to check for. 284 * @returns {boolean} true if any cells were repositioned. false otherwise. 285 */ 286 function checkAndRepositionCellRow(cellElements, container, row, overflow) { 287 if (cellElements[row].length > 0 && jMatrixBrowseNs.Utils.isOverflowing(jQuery(cellElements[row][0]), container, overflow) && isValidDrag(overflow)) { 288 289 var previousCell = jQuery.extend({}, _renderer.currentCell); // Clone currentCell 290 291 // There is an overflow. 292 computeNewCellCoordinates(overflow); 293 294 var cellRow; 295 var direction; 296 297 switch (overflow) { 298 case jMatrixBrowseNs.Constants.OVERFLOW_TOP: 299 direction = 'top'; 300 // The row is overflowing from top. Move it to bottom. 301 var backgroundTopRow = 0; // TODO: get background top row 302 if (_renderer.moveRowToEnd(backgroundTopRow) === false) { 303 return false; 304 } 305 break; 306 307 case jMatrixBrowseNs.Constants.OVERFLOW_BOTTOM: 308 direction = 'bottom'; 309 // The row is overflowing from bottom. Move it to top. 310 var backgroundBottomRow = cellElements.length-1; // TODO: get background bottom row 311 if (_renderer.moveRowToTop(backgroundBottomRow) === false) { 312 return false; 313 } 314 break; 315 } 316 // Trigger event for change 317 _elem.trigger({ 318 type: 'jMatrixBrowseChange', 319 previousCell: previousCell, 320 currentCell: _renderer.currentCell, 321 direction: direction 322 }); 323 return true; 324 } 325 return false; 326 } 327 328 /** 329 * Checks if the given column is overflowing and repositions if necessary. 330 * @param {matrix} cellElements - The matrix of DOM objects representing cells. 331 * @param {jQuery Object} container - The container against which to check the overflow. 332 * @param {Number} col - Index of column to check the overflow for. 333 * @param {Number} overflow - Type of the overflow to check for. 334 * @returns {boolean} true if any cells were repositioned. false otherwise. 335 */ 336 function checkAndRepositionCellCol(cellElements, container, col, overflow) { 337 if (jMatrixBrowseNs.Utils.isOverflowing(jQuery(cellElements[0][col]), container, overflow) && isValidDrag(overflow)) { 338 339 var previousCell = jQuery.extend({}, _renderer.currentCell); // Clone currentCell 340 341 // There is an overflow. 342 computeNewCellCoordinates(overflow); 343 344 var direction; 345 switch (overflow) { 346 case jMatrixBrowseNs.Constants.OVERFLOW_LEFT: 347 direction = 'left'; 348 // The row is overflowing from left. Move it to right. 349 var backgroundLeftCol = 0; // TODO: Get position of background left col. 350 if (_renderer.moveColToRight(backgroundLeftCol) === false) { 351 return false; 352 } 353 break; 354 355 case jMatrixBrowseNs.Constants.OVERFLOW_RIGHT: 356 direction = 'right'; 357 // The row is overflowing from right. Move it to left. 358 var backgroundRightCol = cellElements[0].length-1; // TODO: Get position of background left col. 359 if (_renderer.moveColToLeft(backgroundRightCol) === false) { 360 return false; 361 } 362 break; 363 } 364 // Trigger event for change 365 _elem.trigger({ 366 type: 'jMatrixBrowseChange', 367 previousCell: previousCell, 368 currentCell: _renderer.currentCell, 369 direction: direction 370 }); 371 return true; 372 } 373 return false; 374 } 375 376 /** 377 * Reload column headers on change of matrix. 378 * @param {Number} event.currentCell - currentCell at the top left 379 * @param {Number} event.previousCell - previousCell at the top left 380 * @param {string} event.direction - direction of drag that triggered the change 381 */ 382 function reloadRowHeaders(event) { 383 var rowHeaders = _api.getRowHeadersFromTopRow(event.currentCell.row-_configuration.getNumberOfBackgroundCells()); 384 _renderer.getHeaders().row.children().each(function (index, element) { 385 if (index < rowHeaders.length) { 386 jQuery(element).html(rowHeaders[index]); 387 } 388 }); 389 } 390 391 /** 392 * Reload row headers on change of matrix. 393 * @param {Number} event.currentCell - currentCell at the top left 394 * @param {Number} event.previousCell - previousCell at the top left 395 * @param {string} event.direction - direction of drag that triggered the change 396 */ 397 function reloadColHeaders(event) { 398 var colHeaders = _api.getColHeadersFromLeftCol(event.currentCell.col-_configuration.getNumberOfBackgroundCells()); 399 _renderer.getHeaders().col.children().each(function (index, element) { 400 if (index < colHeaders.length) { 401 jQuery(element).html(colHeaders[index]); 402 } 403 }); 404 } 405 406 /** 407 * Computes the row index needed for reload. 408 * @param {Number} event.currentCell - currentCell at the top left 409 * @param {Number} event.previousCell - previousCell at the top left 410 * @param {string} direction - direction of overflow corresponding to the update 411 * @returns {Object} rowIndex - row1, row2 and rowsNotInBound 412 */ 413 function getRowIndexForReload(event, direction) { 414 var rowsNotInBound = 0; 415 var rowIndex; 416 var nRowsReloaded = Math.abs(event.currentCell.row - event.previousCell.row); 417 418 // Find indices of the first and last rows in matrix. 419 var firstRowIndex = event.currentCell.row - _configuration.getNumberOfBackgroundCells(); 420 var lastRowIndex = event.currentCell.row - _configuration.getNumberOfBackgroundCells() + _renderer.getCellElements().length - 1; 421 422 if (direction === 'top') { 423 // If overflow from top, bottom rows will have to be fetched. 424 // Check if the row is within matrix bounds 425 if (lastRowIndex >= _api.getMatrixSize().height) { 426 // Some rows might not be in bound. Find how many? 427 rowsNotInBound = lastRowIndex - _api.getMatrixSize().height + 1; 428 } 429 430 if (rowsNotInBound === nRowsReloaded) { 431 // We don't need to reload any row. 432 return -1; 433 } 434 435 rowIndex = { 436 row1: lastRowIndex - (nRowsReloaded - 1), 437 row2: lastRowIndex - rowsNotInBound 438 }; 439 } else if (direction === 'bottom') { 440 // If overflow from bottom, top rows will have to be fetched. 441 // First check if the rows are within matrix bounds 442 if (firstRowIndex < 0) { 443 // Some rows might not be in bound. Find how many? 444 rowsNotInBound = -firstRowIndex; 445 } 446 447 if (rowsNotInBound === nRowsReloaded) { 448 // We don't need to reload any row. 449 return -1; 450 } 451 452 rowIndex = { 453 row1: firstRowIndex + rowsNotInBound, 454 row2: firstRowIndex + (nRowsReloaded - 1) 455 }; 456 } else if (direction === 'both') { 457 // Check for the rows in both directions. 458 var rowIndexBottom = getRowIndexForReload(event, 'top'); 459 var rowIndexTop = getRowIndexForReload(event, 'bottom'); 460 if (rowIndexBottom === -1) 461 rowIndexBottom = {row2: lastRowIndex}; 462 if (rowIndexTop === -1) 463 rowIndexTop = {row1: firstRowIndex}; 464 rowIndex = { 465 row1: rowIndexTop.row1, 466 row2: rowIndexBottom.row2 467 }; 468 } 469 rowIndex.rowsNotInBound = rowsNotInBound; 470 return rowIndex; 471 } 472 473 /** 474 * Computes the col index needed for reload. 475 * @param {Number} event.currentCell - currentCell at the top left 476 * @param {Number} event.previousCell - previousCell at the top left 477 * @param {string} direction - direction of overflow corresponding to the update 478 * @returns {Object} colIndex - col1, col2 and colsNotInBound 479 */ 480 function getColIndexForReload(event, direction) { 481 var colsNotInBound = 0; 482 var colIndex; 483 var nColsReloaded = Math.abs(event.currentCell.col - event.previousCell.col); 484 485 // Find indices of the first and last columns in matrix. 486 var firstColIndex = event.currentCell.col - _configuration.getNumberOfBackgroundCells(); 487 var lastColIndex = event.currentCell.col - _configuration.getNumberOfBackgroundCells() + _renderer.getCellElements()[0].length - 1; 488 489 if (direction === 'left') { 490 // If overflow from left, right columns will have to be fetched. 491 // First check if the column is within matrix bounds 492 if (lastColIndex >= _api.getMatrixSize().width) { 493 // Some columns might not be in bound. Find how many? 494 colsNotInBound = lastColIndex - _api.getMatrixSize().width + 1; 495 if (colsNotInBound === nColsReloaded) { 496 // We don't need to reload any column. 497 return -1; 498 } 499 } 500 501 colIndex = { 502 col1: lastColIndex - (nColsReloaded - 1), 503 col2: lastColIndex 504 }; 505 506 } else if (direction === 'right'){ 507 // If overflow from right, left column will have to be fetched. 508 // First check if the col is within matrix bounds 509 if (firstColIndex < 0) { 510 // Some columns might not be in bound. Find how many? 511 colsNotInBound = -firstColIndex; 512 if (colsNotInBound === nColsReloaded) { 513 // We don't need to reload any column. 514 return -1; 515 } 516 } 517 518 colIndex = { 519 col1: firstColIndex + colsNotInBound, 520 col2: firstColIndex + (nColsReloaded - 1) 521 }; 522 } else if (direction === 'both') { 523 // Check for the rows in both directions. 524 var colIndexRight = getColIndexForReload(event, 'left'); 525 var colIndexLeft = getColIndexForReload(event, 'right'); 526 if (colIndexRight === -1) 527 colIndexRight = {col2: lastColIndex}; 528 if (colIndexLeft === -1) 529 colIndexLeft = {col1: firstColIndex}; 530 colIndex = { 531 col1: colIndexLeft.col1, 532 col2: colIndexRight.col2 533 }; 534 } 535 colIndex.colsNotInBound = colsNotInBound; 536 return colIndex; 537 } 538 539 /** 540 * Reload row data on change of matrix. 541 * @param {Number} event.currentCell - currentCell at the top left 542 * @param {Number} event.previousCell - previousCell at the top left 543 * @param {string} event.direction - direction of drag that triggered the change 544 */ 545 function reloadRowData(event) { 546 // Index of the rows that would be fetched. 547 var rowIndex = getRowIndexForReload(event, event.direction); 548 if (rowIndex === -1) { 549 // We don't need to reload any row. 550 return; 551 } 552 553 // Get col index by checking from both sides. 554 var colIndex = getColIndexForReload(event, 'both'); 555 556 // Get data from the background data manager. 557 var cells = _backgroundDataManager.getCellsForRequest({ 558 row1: rowIndex.row1, 559 row2: rowIndex.row2, 560 col1: colIndex.col1, 561 col2: colIndex.col2 562 }, function(cells) { 563 updateCellsForReload(rowIndex, colIndex, cells); 564 }); 565 } 566 567 /** 568 * Reload column data on change of matrix. 569 * @param {Number} event.currentCell - currentCell at the top left 570 * @param {Number} event.previousCell - previousCell at the top left 571 * @param {string} event.direction - direction of drag that triggered the change 572 */ 573 function reloadColData(event) { 574 // Index of the rows that would be fetched. 575 var colIndex = getColIndexForReload(event, event.direction); 576 if (colIndex === -1) { 577 // We don't need to reload any row. 578 return; 579 } 580 581 // Get row index by checking from both sides. 582 var rowIndex = getRowIndexForReload(event, 'both'); 583 584 // Get data from the background data manager. 585 var cells = _backgroundDataManager.getCellsForRequest({ 586 row1: rowIndex.row1, 587 row2: rowIndex.row2, 588 col1: colIndex.col1, 589 col2: colIndex.col2 590 }, function(cells) { 591 updateCellsForReload(rowIndex, colIndex, cells); 592 }); 593 } 594 595 /** 596 * Updates the cells which have been reloaded for the given row and col indices. 597 * @param {Object} rowIndex - row1 and row2 for the request that was made. 598 * @param {Object} colIndex - col1 and col2 for the request that was made. 599 * @param {Array} cells - Array of Array of the response data. 600 */ 601 function updateCellsForReload(rowIndex, colIndex, cells) { 602 for (var i = rowIndex.row1; i <= rowIndex.row2; ++i) { 603 // Find which row needs to be replaced. 604 var rowToBeReplacedIndex = i - _renderer.currentCell.row + _configuration.getNumberOfBackgroundCells(); 605 // Check if the row has already gone out of window. 606 if (rowToBeReplacedIndex < 0 || rowToBeReplacedIndex >= _renderer.getCellElements().length) 607 continue; 608 var rowToBeReplaced = _renderer.getCellElements()[rowToBeReplacedIndex]; 609 for (var j = colIndex.col1; j <= colIndex.col2; ++j) { 610 // Find which col needs to be replaced. 611 var colToBeReplacedIndex = j - _renderer.currentCell.col + _configuration.getNumberOfBackgroundCells(); 612 // Check if the column has already gone out of window. 613 if (colToBeReplacedIndex < 0 || colToBeReplacedIndex >= rowToBeReplaced.length) 614 continue; 615 // Get the cell that is to be replaced. 616 var cell = jQuery(rowToBeReplaced[colToBeReplacedIndex]); 617 updateCellForReload(cell, rowToBeReplacedIndex, colToBeReplacedIndex, cells[i-rowIndex.row1][j-colIndex.col1], i, j); 618 } 619 } 620 } 621 622 /** 623 * Updates the cell content for reload based on the reload strategy. 624 * @param {jQuery Object} cell - cell to be replaced/reloaded. 625 * @param {Number} rowIndex - row index of the cell to be replaced. 626 * @param {Number} colIndex - column index of the cell to be replaced. 627 * @param {jQuery Object} newCell - cell to be replaced with. 628 * @param {Number} newRowNumber - new row number of the cell. 629 * @param {Number} newColNumber - new column number of the cell. 630 */ 631 function updateCellForReload(cell, rowIndex, colIndex, newCell, newRowNumber, newColNumber) { 632 if (_configuration.getDataReloadStrategy() === jMatrixBrowseNs.Constants.RELOAD_CELL_REPLACEMENT) { 633 // Clone and move the cell from background container to matrix content. 634 newCell = newCell.clone().removeClass('jMatrixBrowse-background-cell').addClass('jMatrixBrowse-cell').css({ 635 width: cell.css('width'), 636 height: cell.css('height'), 637 top: cell.css('top'), 638 left: cell.css('left'), 639 position: 'absolute' 640 }); 641 cell.replaceWith(newCell); 642 _renderer.getCellElements()[rowIndex][colIndex] = newCell; 643 } else if (_configuration.getDataReloadStrategy() === jMatrixBrowseNs.Constants.RELOAD_HTML_REPLACEMENT) { 644 // Change only the html content of the cell. 645 var html = newCell.html(); 646 cell.html(html); 647 cell.attr('data-row', newRowNumber); 648 cell.attr('data-col', newColNumber); 649 } else if (_configuration.getDataReloadStrategy() === jMatrixBrowseNs.Constants.RELOAD_CELL_POSITION) { 650 // Cell is already in the matrix container. Change its position etc. to put it in correct place. 651 newCell = newCell.removeClass('jMatrixBrowse-background-cell').addClass('jMatrixBrowse-cell').css({ 652 width: cell.css('width'), 653 height: cell.css('height'), 654 top: cell.css('top'), 655 left: cell.css('left'), 656 position: 'absolute' 657 }); 658 cell.hide(); 659 newCell.show(); 660 _renderer.getCellElements()[rowIndex][colIndex] = newCell; 661 } 662 } 663 664 /** 665 * Reload row and column headers on change of matrix. 666 * @param {Number} event.currentCell - currentCell at the top left 667 * @param {Number} event.previousCell - previousCell at the top left 668 * @param {string} event.direction - direction of drag that triggered the change 669 */ 670 function reloadHeaders(event) { 671 if (event.direction === 'top' || event.direction === 'bottom') { 672 reloadRowHeaders(event); 673 } else { 674 reloadColHeaders(event); 675 } 676 } 677 678 /** 679 * Reload row and column data on change of matrix. 680 * @param {Number} event.currentCell - currentCell at the top left 681 * @param {Number} event.previousCell - previousCell at the top left 682 * @param {string} event.direction - direction of drag that triggered the change 683 */ 684 function reloadMatrixData(event) { 685 if (event.direction === 'top' || event.direction === 'bottom') { 686 reloadRowData(event); 687 } else { 688 reloadColData(event); 689 } 690 } 691 692 /** 693 * Reload data on change of matrix. 694 * @param {Number} event.currentCell - currentCell at the top left 695 * @param {Number} event.previousCell - previousCell at the top left 696 * @param {string} event.direction - direction of drag that triggered the change 697 */ 698 function reloadData(event) { 699 reloadHeaders(event); 700 reloadMatrixData(event); 701 } 702 703 /** 704 * Binds shortcuts for browsing. 705 */ 706 function bindShortcuts() { 707 // Arrow keys 708 jQuery(document).bind('keydown', 'right', function(e) { 709 e.preventDefault(); 710 _renderer.scrollRight(); 711 }); 712 713 jQuery(document).bind('keydown', 'left', function(e) { 714 e.preventDefault(); 715 _renderer.scrollLeft(); 716 }); 717 718 jQuery(document).bind('keydown', 'up', function(e) { 719 e.preventDefault(); 720 _renderer.scrollUp(); 721 }); 722 723 jQuery(document).bind('keydown', 'down', function(e) { 724 e.preventDefault(); 725 _renderer.scrollDown(); 726 }); 727 728 // Vi like browsing. 729 jQuery(document).bind('keydown', 'j', function() { 730 _renderer.scrollRight(); 731 }); 732 733 jQuery(document).bind('keydown', 'h', function() { 734 _renderer.scrollLeft(); 735 }); 736 737 jQuery(document).bind('keydown', 'k', function() { 738 _renderer.scrollUp(); 739 }); 740 741 jQuery(document).bind('keydown', 'l', function() { 742 _renderer.scrollDown(); 743 }); 744 745 // Page ups and downs using ctrl + arrow keys 746 jQuery(document).bind('keydown', 'ctrl+up', function() { 747 _renderer.pageUp(); 748 }); 749 750 jQuery(document).bind('keydown', 'ctrl+down', function() { 751 _renderer.pageDown(); 752 }); 753 754 jQuery(document).bind('keydown', 'ctrl+left', function() { 755 _renderer.pageLeft(); 756 }); 757 758 jQuery(document).bind('keydown', 'ctrl+right', function() { 759 _renderer.pageRight(); 760 }); 761 762 jQuery(document).bind('keydown', 'i', function() { 763 console.log('zoom in'); 764 _renderer.zoomIn(); 765 }); 766 767 jQuery(document).bind('keydown', 'o', function() { 768 console.log('zoom out'); 769 _renderer.zoomOut(); 770 }); 771 772 _elem.mousewheel(function(event, delta) { 773 var scrollLeft, scrollRight, scrollUp, scrollRight; 774 775 if (event.ctrlKey) { 776 // If ctrl key is down, we scroll by page. 777 scrollLeft = _renderer.pageLeft; 778 scrollRight = _renderer.pageRight; 779 // If shift key is down, we do horizontal scroll instead of vertical. 780 scrollDown = (event.shiftKey) ? _renderer.pageRight : _renderer.pageDown; 781 scrollUp = (event.shiftKey) ? _renderer.pageLeft : _renderer.pageUp; 782 } else { 783 scrollLeft = _renderer.scrollLeft; 784 scrollRight = _renderer.scrollRight; 785 // If shift key is down, we do horizontal scroll instead of vertical. 786 scrollDown = (event.shiftKey) ? _renderer.scrollRight : _renderer.scrollDown; 787 scrollUp = (event.shiftKey) ? _renderer.scrollLeft : _renderer.scrollUp; 788 } 789 790 // Is mouse wheel scrolled horizontally? 791 if (event.originalEvent.wheelDeltaX > 0) { 792 scrollLeft(); 793 } else if (event.originalEvent.wheelDeltaX < 0) { 794 scrollRight(); 795 } 796 797 // Is mouse wheel scrolled vertically? 798 if (event.originalEvent.wheelDeltaY > 0) { 799 scrollUp(); 800 } else if (event.originalEvent.wheelDeltaY < 0) { 801 scrollDown(); 802 } 803 }); 804 } 805 806 return this; 807 }; 808 })(jQuery, jMatrixBrowseNs); 809