Файловый менеджер - Редактировать - /var/www/html/mediawiki-1.43.1/extensions/VisualEditor/lib/ve/src/ce/nodes/ve.ce.TableNode.js
Ðазад
/*! * VisualEditor ContentEditable TableNode class. * * @copyright See AUTHORS.txt */ /** * ContentEditable table node. * * @class * @extends ve.ce.BranchNode * @constructor * @param {ve.dm.TableNode} model Model to observe * @param {Object} [config] Configuration options */ ve.ce.TableNode = function VeCeTableNode() { // Parent constructor ve.ce.TableNode.super.apply( this, arguments ); // Properties this.surface = null; this.active = false; this.startCell = null; this.endCell = null; // Stores the original table selection as // a fragment when entering cell edit mode this.editingFragment = null; // DOM changes this.$element .addClass( 've-ce-tableNode' ) .prop( 'contentEditable', 'false' ); }; /* Inheritance */ OO.inheritClass( ve.ce.TableNode, ve.ce.BranchNode ); /* Static properties */ ve.ce.TableNode.static.autoFocus = false; /* Methods */ /** * @inheritdoc */ ve.ce.TableNode.prototype.onSetup = function () { // Parent method ve.ce.TableNode.super.prototype.onSetup.call( this ); // Exit if already setup or not attached if ( this.surface || !this.root ) { return; } this.surface = this.getRoot().getSurface(); // Overlay this.$selectionBox = $( '<div>' ).addClass( 've-ce-tableNodeOverlay-selection-box' ); this.$selectionBoxAnchor = $( '<div>' ).addClass( 've-ce-tableNodeOverlay-selection-box-anchor' ); if ( OO.ui.isMobile() ) { this.nodeContext = new ve.ui.TableLineContext( this, 'table' ); } else { this.nodeContext = null; } this.colContext = new ve.ui.TableLineContext( this, 'col' ); this.rowContext = new ve.ui.TableLineContext( this, 'row' ); this.$overlay = $( '<div>' ) .addClass( 've-ce-tableNodeOverlay oo-ui-element-hidden' ) .append( this.$selectionBox, this.$selectionBoxAnchor, this.nodeContext ? this.nodeContext.$element : undefined, this.colContext.$element, this.rowContext.$element, this.$rowBracket, this.$colBracket ); this.surface.surface.$blockers.append( this.$overlay ); // Events this.$element.on( { 'mousedown.ve-ce-tableNode': this.onTableMouseDown.bind( this ), 'dblclick.ve-ce-tableNode': this.onTableDblClick.bind( this ) } ); this.$overlay.on( { 'mousedown.ve-ce-tableNode': this.onTableMouseDown.bind( this ), 'dblclick.ve-ce-tableNode': this.onTableDblClick.bind( this ) } ); this.onTableMouseUpHandler = this.onTableMouseUp.bind( this ); this.onTableMouseMoveHandler = this.onTableMouseMove.bind( this ); // Select and position events both fire updateOverlay, so debounce. Also makes // sure that this.selectedRectangle is up to date before redrawing. this.updateOverlayDebounced = ve.debounce( this.updateOverlay.bind( this ) ); this.surface.getModel().connect( this, { select: 'onSurfaceModelSelect' } ); this.surface.connect( this, { position: this.updateOverlayDebounced, activation: 'onSurfaceActivation' } ); }; /** * @inheritdoc */ ve.ce.TableNode.prototype.onTeardown = function () { // Parent method ve.ce.TableNode.super.prototype.onTeardown.call( this ); // Not yet setup if ( !this.surface ) { return; } // Events this.$element.off( '.ve-ce-tableNode' ); this.$overlay.off( '.ve-ce-tableNode' ); this.surface.getModel().disconnect( this ); this.surface.disconnect( this ); this.$overlay.remove(); this.surface = null; }; /** * Handle table double click events * * @param {jQuery.Event} e Double click event */ ve.ce.TableNode.prototype.onTableDblClick = function ( e ) { if ( !this.getCellNodeFromEvent( e ) ) { return; } if ( this.surface.getModel().getSelection() instanceof ve.dm.TableSelection ) { // Don't change selection in setEditing to avoid scrolling to bottom of cell this.setEditing( true, true ); // getOffsetFromEventCoords doesn't work in ce=false in Firefox, so ensure // this is called after setEditing( true ). const offset = this.surface.getOffsetFromEventCoords( e.originalEvent ); if ( offset !== -1 ) { // Set selection to where the double click happened this.surface.getModel().setLinearSelection( new ve.Range( offset ) ); } else { this.setEditing( true ); } } }; /** * Handle mouse down or touch start events * * @param {jQuery.Event} e Mouse down or touch start event */ ve.ce.TableNode.prototype.onTableMouseDown = function ( e ) { const cellNode = this.getCellNodeFromEvent( e ); if ( !cellNode ) { return; } const endCell = this.getModel().getMatrix().lookupCell( cellNode.getModel() ); if ( !endCell ) { e.preventDefault(); return; } const selection = this.surface.getModel().getSelection(); let startCell; let newSelection; if ( e.shiftKey && this.active ) { // Extend selection from the anchor cell if ( selection instanceof ve.dm.TableSelection ) { startCell = { col: selection.fromCol, row: selection.fromRow }; } else { startCell = this.getModel().getMatrix().lookupCell( this.getActiveCellNode().getModel() ); } } else if ( ( e.which === OO.ui.MouseButtons.RIGHT || this.surface.isDeactivated() ) && selection instanceof ve.dm.TableSelection && selection.containsCell( endCell ) ) { // Right click within the current selection, or any click in deactviated selection: // leave selection as is newSelection = selection; // Make sure there's a startCell startCell = this.startCell || endCell; } else { // Select single cell startCell = endCell; } if ( !newSelection ) { newSelection = new ve.dm.TableSelection( this.getModel().getOuterRange(), startCell.col, startCell.row, endCell.col, endCell.row ); newSelection = newSelection.expand( this.getModel().getDocument() ); } if ( this.editingFragment ) { if ( newSelection.equals( this.editingFragment.getSelection() ) ) { // Clicking on the editing cell, don't prevent default return; } else { this.setEditing( false, true ); } } this.surface.getModel().setSelection( newSelection ); // Ensure surface is active as native 'focus' event won't be fired this.surface.activate(); // Right-click on a cell which isn't being edited if ( e.which === OO.ui.MouseButtons.RIGHT && !this.getActiveCellNode() ) { // The same technique is used in ve.ce.FocusableNode // Make ce=true so we get cut/paste options in the context menu cellNode.$element.prop( 'contentEditable', true ); // Select the clicked element so we get a copy option in the context menu ve.selectElement( cellNode.$element[ 0 ] ); setTimeout( () => { // Undo ce=true as soon as the context menu is shown cellNode.$element.prop( 'contentEditable', 'false' ); // Trigger onModelSelect to restore the selection this.surface.onModelSelect(); } ); return; } this.startCell = startCell; this.endCell = endCell; if ( !( selection instanceof ve.dm.TableSelection ) && OO.ui.isMobile() ) { // On mobile, fall through to the double-click behavior on a single tap -- // this will place the cursor within the cell, rather than remaining in // table-selection mode. // As we just have only just set the table selection, the surface is in // process of deactivating, so wait for the event loop to clear before // continuing. setTimeout( () => { this.onTableDblClick( e ); } ); } else { this.surface.$document.on( { 'mouseup touchend': this.onTableMouseUpHandler, 'mousemove touchmove': this.onTableMouseMoveHandler } ); } e.preventDefault(); }; /** * Get a table cell node from a mouse event * * Works around various issues with touch events and browser support. * * @param {jQuery.Event} e Mouse event * @return {ve.ce.TableCellNode|null} Table cell node */ ve.ce.TableNode.prototype.getCellNodeFromEvent = function ( e ) { // 'touchmove' doesn't give a correct e.target, so calculate it from coordinates if ( e.type === 'touchstart' && e.originalEvent.touches.length > 1 ) { // Ignore multi-touch return null; } else if ( e.type === 'touchmove' ) { if ( e.originalEvent.touches.length > 1 ) { // Ignore multi-touch return null; } const touch = e.originalEvent.touches[ 0 ]; return this.getCellNodeFromPoint( touch.clientX, touch.clientY ); } else { return this.getNearestCellNode( e.target ); } }; /** * Get the cell node from a point * * @param {number} x X offset * @param {number} y Y offset * @return {ve.ce.TableCellNode|null} Table cell node, or null if none found */ ve.ce.TableNode.prototype.getCellNodeFromPoint = function ( x, y ) { return this.getNearestCellNode( this.surface.getElementDocument().elementFromPoint( x, y ) ); }; /** * Get the nearest cell node in this table to an element * * If the nearest cell node is in another table, return null. * * @param {HTMLElement} element Element target to find nearest cell node to * @return {ve.ce.TableCellNode|null} Table cell node, or null if none found */ ve.ce.TableNode.prototype.getNearestCellNode = function ( element ) { const $element = $( element ), $table = $element.closest( 'table' ); // Nested table, ignore if ( !this.$element.is( $table ) ) { return null; } return $element.closest( 'td, th' ).data( 'view' ); }; /** * Handle mouse/touch move events * * @param {jQuery.Event} e Mouse/touch move event */ ve.ce.TableNode.prototype.onTableMouseMove = function ( e ) { const endCellNode = this.getCellNodeFromEvent( e ); if ( !endCellNode ) { return; } const endCell = this.getModel().matrix.lookupCell( endCellNode.getModel() ); if ( !endCell || endCell === this.endCell ) { return; } this.endCell = endCell; let selection = new ve.dm.TableSelection( this.getModel().getOuterRange(), this.startCell.col, this.startCell.row, endCell.col, endCell.row ); selection = selection.expand( this.getModel().getDocument() ); this.surface.getModel().setSelection( selection ); }; /** * Handle mouse up or touch end events * * @param {jQuery.Event} e Mouse up or touch end event */ ve.ce.TableNode.prototype.onTableMouseUp = function () { this.startCell = null; this.endCell = null; this.surface.$document.off( { 'mouseup touchend': this.onTableMouseUpHandler, 'mousemove touchmove': this.onTableMouseMoveHandler } ); }; /** * Set the editing state of the table * * @param {boolean} isEditing The table is being edited * @param {boolean} noSelect Don't change the selection */ ve.ce.TableNode.prototype.setEditing = function ( isEditing, noSelect ) { const surfaceModel = this.surface.getModel(), documentModel = surfaceModel.getDocument(); let selection = surfaceModel.getSelection(); if ( isEditing ) { if ( !selection.isSingleCell( documentModel ) ) { selection = selection.collapseToFrom(); this.surface.getModel().setSelection( selection ); } const cell = this.getCellNodesFromSelection( selection )[ 0 ]; if ( !cell.isCellEditable() ) { return; } this.editingFragment = this.surface.getModel().getFragment( selection ); cell.setEditing( true ); if ( !noSelect ) { const cellRange = cell.getModel().getRange(); const offset = surfaceModel.getDocument().data.getNearestContentOffset( cellRange.end, -1 ); if ( offset > cellRange.start ) { surfaceModel.setLinearSelection( new ve.Range( offset ) ); } } } else { let activeCellNode; if ( ( activeCellNode = this.getActiveCellNode() ) ) { activeCellNode.setEditing( false ); if ( !noSelect ) { surfaceModel.setSelection( this.editingFragment.getSelection() ); } } this.editingFragment = null; } this.$element.toggleClass( 've-ce-tableNode-editing', isEditing ); this.$overlay.toggleClass( 've-ce-tableNodeOverlay-editing', isEditing ); }; /** * Handle select events from the surface model. * * @param {ve.dm.Selection} selection */ ve.ce.TableNode.prototype.onSurfaceModelSelect = function ( selection ) { // The table is active if there is a linear selection inside a cell being edited // or a table selection matching this table. const active = ( this.editingFragment !== null && selection instanceof ve.dm.LinearSelection && this.editingFragment.getSelection().getRanges( this.editingFragment.getDocument() )[ 0 ].containsRange( selection.getRange() ) ) || ( selection instanceof ve.dm.TableSelection && selection.tableRange.equalsSelection( this.getModel().getOuterRange() ) ); if ( active ) { if ( !this.active ) { this.$overlay.removeClass( 'oo-ui-element-hidden' ); // Only register touchstart event after table has become active to prevent // accidental focusing of the table while scrolling this.$element.on( 'touchstart.ve-ce-tableNode', this.onTableMouseDown.bind( this ) ); } // Ignore update the overlay if the table selection changed, i.e. not an in-cell selection change if ( selection instanceof ve.dm.TableSelection ) { if ( this.editingFragment ) { this.setEditing( false, true ); } this.updateOverlayDebounced(); } } else if ( !active && this.active ) { this.$overlay.addClass( 'oo-ui-element-hidden' ); if ( this.editingFragment ) { this.setEditing( false, true ); } // When the table of the active node is deactivated, clear the active node if ( this.getActiveCellNode() ) { this.surface.setActiveNode( null ); } this.$element.off( 'touchstart.ve-ce-tableNode' ); } this.$element.toggleClass( 've-ce-tableNode-active', active ); this.active = active; }; /** * Get the active node in this table, if it has one * * @return {ve.ce.TableNode|null} The active cell node in this table */ ve.ce.TableNode.prototype.getActiveCellNode = function () { const activeNode = this.surface.getActiveNode(), tableNodeOfActiveCellNode = activeNode && activeNode instanceof ve.ce.TableCellNode && activeNode.findParent( ve.ce.TableNode ); return tableNodeOfActiveCellNode === this ? activeNode : null; }; /** * Handle activation events from the surface */ ve.ce.TableNode.prototype.onSurfaceActivation = function () { this.$overlay.toggleClass( 've-ce-tableNodeOverlay-deactivated', !!this.surface.isShownAsDeactivated() ); }; /** * Update the overlay positions */ ve.ce.TableNode.prototype.updateOverlay = function () { if ( !this.active || !this.root || !this.surface || // Overlay isn't attached, e.g. in tests !this.surface.surface.$blockers[ 0 ].parentNode ) { return; } const selection = this.editingFragment ? this.editingFragment.getSelection() : this.surface.getModel().getSelection(); const documentModel = this.editingFragment ? this.editingFragment.getDocument() : this.surface.getModel().getDocument(); // getBoundingClientRect is more accurate but must be used consistently // due to the iOS7 bug where it is relative to the document. const tableOffset = this.getFirstSectionNode().$element[ 0 ].getBoundingClientRect(); const surfaceOffset = this.surface.getSurface().$element[ 0 ].getBoundingClientRect(); if ( !tableOffset ) { return; } const selectionRect = this.surface.getSelection( selection ).getSelectionBoundingRect(); if ( !selectionRect ) { return; } // Compute a bounding box for the given cell elements const selectionOffset = ve.translateRect( selectionRect, surfaceOffset.left - tableOffset.left, surfaceOffset.top - tableOffset.top ); let anchorOffset; if ( selection.isSingleCell( documentModel ) ) { // Optimization, use same rects as whole selection anchorOffset = selectionOffset; } else { anchorOffset = ve.translateRect( this.surface.getSelection( selection.collapseToFrom() ).getSelectionBoundingRect(), surfaceOffset.left - tableOffset.left, surfaceOffset.top - tableOffset.top ); } // Resize controls this.$selectionBox.css( { top: selectionOffset.top, left: selectionOffset.left, width: selectionOffset.width, height: selectionOffset.height } ); this.$selectionBoxAnchor.css( { top: anchorOffset.top, left: anchorOffset.left, width: anchorOffset.width, height: anchorOffset.height } ); // Position controls this.$overlay.css( { top: tableOffset.top - surfaceOffset.top, left: tableOffset.left - surfaceOffset.left, width: tableOffset.width } ); // this.nodeContext doesn't need to adjust to the line this.colContext.icon.$element.css( { left: selectionOffset.left, width: selectionOffset.width } ); this.rowContext.icon.$element.css( { top: selectionOffset.top, height: selectionOffset.height } ); if ( this.nodeContext ) { this.nodeContext.$element.toggleClass( 'oo-ui-element-hidden', this.surface.isReadOnly() ); } this.colContext.$element.toggleClass( 'oo-ui-element-hidden', this.surface.isReadOnly() ); this.rowContext.$element.toggleClass( 'oo-ui-element-hidden', this.surface.isReadOnly() ); // Classes this.$selectionBox.toggleClass( 've-ce-tableNodeOverlay-selection-box-notEditable', !selection.isEditable( documentModel ) ); }; /** * Get the first section node of the table, skipping over any caption nodes * * @return {ve.ce.TableSectionNode} First table section node */ ve.ce.TableNode.prototype.getFirstSectionNode = function () { let i = 0; while ( !( this.children[ i ] instanceof ve.ce.TableSectionNode ) ) { i++; } return this.children[ i ]; }; /** * Get a cell node from a single cell selection * * @param {ve.dm.TableSelection} selection Single cell table selection * @return {ve.ce.TableCellNode[]} Cell nodes */ ve.ce.TableNode.prototype.getCellNodesFromSelection = function ( selection ) { const cells = selection.getMatrixCells( this.getModel().getDocument() ), nodes = []; for ( let i = 0, l = cells.length; i < l; i++ ) { const cellModel = cells[ i ].node; const cellView = this.getNodeFromOffset( cellModel.getOffset() - this.model.getOffset() ); nodes.push( cellView ); } return nodes; }; /* Static Properties */ ve.ce.TableNode.static.name = 'table'; ve.ce.TableNode.static.tagName = 'table'; /* Registration */ ve.ce.nodeFactory.register( ve.ce.TableNode );
| ver. 1.1 | |
.
| PHP 8.4.18 | Ð“ÐµÐ½ÐµÑ€Ð°Ñ†Ð¸Ñ Ñтраницы: 0 |
proxy
|
phpinfo
|
ÐаÑтройка