Файловый менеджер - Редактировать - /var/www/html/mediawiki-1.43.1/extensions/VisualEditor/lib/ve/src/ce/ve.ce.Document.js
Ðазад
/*! * VisualEditor ContentEditable Document class. * * @copyright See AUTHORS.txt */ /** * ContentEditable document. * * @class * @extends ve.Document * * @constructor * @param {ve.dm.Document} model Model to observe * @param {ve.ce.Surface} surface Surface document is part of */ ve.ce.Document = function VeCeDocument( model, surface ) { // Parent constructor ve.ce.Document.super.call( this, new ve.ce.DocumentNode( model.getDocumentNode(), surface ) ); this.lang = null; this.dir = null; this.setLang( model.getLang() ); this.setDir( model.getDir() ); // Properties this.model = model; }; /* Inheritance */ OO.inheritClass( ve.ce.Document, ve.Document ); /* Events */ /** * Language or direction changed * * @event ve.ce.Document#langChange */ /* Methods */ /** * Set the document view language * * @param {string} lang Language code */ ve.ce.Document.prototype.setLang = function ( lang ) { this.getDocumentNode().$element.prop( 'lang', lang ); this.lang = lang; this.emit( 'langChange' ); }; /** * Set the document view directionality * * @param {string} dir Directionality (ltr/rtl) */ ve.ce.Document.prototype.setDir = function ( dir ) { this.getDocumentNode().$element.prop( 'dir', dir ); this.dir = dir; this.emit( 'langChange' ); }; /** * Get the document view language * * @return {string} Language code */ ve.ce.Document.prototype.getLang = function () { return this.lang; }; /** * Get the document view directionality * * @return {string} Directionality (ltr/rtl) */ ve.ce.Document.prototype.getDir = function () { return this.dir; }; /** * Get a slug at an offset. * * @param {number} offset Offset to get slug at * @return {HTMLElement} Slug at offset */ ve.ce.Document.prototype.getSlugAtOffset = function ( offset ) { const node = this.getBranchNodeFromOffset( offset ); return node ? node.getSlugAtOffset( offset ) : null; }; /** * Calculate the DOM position corresponding to a DM offset * * If there are multiple DOM locations, heuristically pick the best one for cursor placement * * @private * @param {number} offset Linear model offset * @return {ve.ce.NodeAndOffset} Position * @throws {Error} Offset could not be translated to a DOM element and offset */ ve.ce.Document.prototype.getNodeAndOffset = function ( offset ) { const countedNodes = []; // 1. Step with ve.adjacentDomPosition( …, { stop: function () { return true; } } ) // until we hit a position at the correct offset (which is guaranteed to be the first // such position in document order). // 2. Use ve.adjacentDomPosition( …, { stop: … } ) once to return all // subsequent positions at the same offset. // 3. Look at the possible positions and pick as follows: // - If there is a unicorn, return just inside it // - Else if there is a nail, return just outside it // - Else if there is a text node, return an offset in it // - Else return the first matching offset // // Offsets of DOM nodes are counted to match their model equivalents. // // TODO: take the following into account: // Unfortunately, there is no way to avoid slugless block nodes with no DM length: an // IME can remove all the text from a node at a time when it is unsafe to fixup the node // contents. In this case, a maximally deep element gives better bounding rectangle // coordinates than any of its containers. if ( !this.model.getDocumentRange().containsRange( new ve.Range( offset ) ) ) { throw new Error( 'Offset is out of bounds' ); } const branchNode = this.getBranchNodeFromOffset( offset ); let count = branchNode.getOffset() + ( branchNode.isWrapped() ? 1 : 0 ); let node; if ( !( branchNode instanceof ve.ce.ContentBranchNode ) ) { // The cursor does not lie in a ContentBranchNode, so we can determine // everything from the DM tree let i, ceChild; for ( i = 0; ; i++ ) { ceChild = branchNode.children[ i ]; if ( count === offset ) { break; } if ( !ceChild ) { throw new Error( 'Offset lies beyond branchNode' ); } count += ceChild.getOuterLength(); if ( count > offset ) { if ( ceChild.getOuterLength() !== 2 ) { throw new Error( 'Offset lies inside child of strange size' ); } node = ceChild.$element[ 0 ]; if ( node ) { return { node: node, offset: 0 }; } // Else ceChild has no DOM representation; step forwards break; } } // Offset lies directly in branchNode, just before ceChild node = branchNode.$element[ 0 ]; while ( ceChild && !ceChild.$element[ 0 ] ) { // Node does not have a DOM representation; move forwards past it i++; ceChild = branchNode.children[ i ]; } if ( !ceChild || !ceChild.$element[ 0 ] ) { // Offset lies just at the end of branchNode return { node: node, offset: node.childNodes.length }; } return { node: node, offset: Array.prototype.indexOf.call( node.childNodes, ceChild.$element[ 0 ] ) }; } // Else the cursor lies in a ContentBranchNode, so we must traverse the DOM, keeping // count of the corresponding DM position until it reaches offset. let position = { node: branchNode.$element[ 0 ], offset: 0 }; function noDescend() { return this.classList.contains( 've-ce-branchNode-blockSlug' ) || ve.rejectsCursor( this ); } while ( true ) { if ( count === offset ) { break; } position = ve.adjacentDomPosition( position, 1, { noDescend: noDescend, stop: function () { return true; } } ); const step = position.steps[ 0 ]; node = step.node; if ( node.nodeType === Node.TEXT_NODE ) { if ( step.type === 'leave' ) { // Skip without incrementing continue; } // else the code below always breaks or skips over the text node; // therefore it is guaranteed that step.type === 'enter' (we just // stepped in) // TODO: what about zero-length text nodes? if ( offset <= count + node.data.length ) { // Match the appropriate offset in the text node position = { node: node, offset: offset - count }; break; } else { // Skip over the text node count += node.data.length; position = { node: node, offset: node.data.length }; continue; } } // else it is an element node (TODO: handle comment etc) if ( !( node.classList.contains( 've-ce-branchNode' ) || node.classList.contains( 've-ce-leafNode' ) ) ) { // Nodes like b, inline slug, browser-generated br that doesn't have // class ve-ce-leafNode: continue walk without incrementing continue; } if ( step.type === 'leave' ) { // Below we'll guarantee that .ve-ce-branchNode/.ve-ce-leafNode elements // are only entered if their open/close tags take up a model offset, so // we can increment unconditionally here count++; continue; } // else step.type === 'enter' || step.type === 'cross' const model = $.data( node, 'view' ).model; if ( countedNodes.indexOf( model ) !== -1 ) { // This DM node is rendered as multiple DOM elements, and we have already // counted it as part of an earlier element. Skip past without incrementing position = { node: node.parentNode, offset: ve.parentIndex( node ) + 1 }; continue; } countedNodes.push( model ); if ( offset >= count + model.getOuterLength() ) { // Offset doesn't lie inside the node. Skip past and count length // skip past the whole node position = { node: node.parentNode, offset: ve.parentIndex( node ) + 1 }; count += model.getOuterLength(); } else if ( step.type === 'cross' ) { if ( offset === count + 1 ) { // The offset lies inside the crossed node position = { node: node, offset: 0 }; break; } count += 2; } else { count += 1; } } // Now "position" is the first DOM position (in document order) at the correct // model offset. // If the position is exactly after the first of multiple view nodes sharing a model, // then jump to the position exactly after the final such view node. const prevNode = position.node.childNodes[ position.offset - 1 ]; if ( prevNode && prevNode.nodeType === Node.ELEMENT_NODE && ( prevNode.classList.contains( 've-ce-branchNode' ) || prevNode.classList.contains( 've-ce-leafNode' ) ) ) { const $viewNodes = $.data( prevNode, 'view' ).$element; if ( $viewNodes.length > 1 ) { position.node = $viewNodes.get( -1 ).parentNode; position.offset = 1 + ve.parentIndex( $viewNodes.get( -1 ) ); } } // Find all subsequent DOM positions at the same model offset const found = {}; function stop( s ) { let m; if ( s.node.nodeType === Node.TEXT_NODE ) { return s.type === 'internal'; } if ( s.node.classList.contains( 've-ce-branchNode' ) || s.node.classList.contains( 've-ce-leafNode' ) ) { m = $.data( s.node, 'view' ).model; if ( countedNodes.indexOf( m ) !== -1 ) { return false; } countedNodes.push( m ); return true; } return false; } const steps = ve.adjacentDomPosition( position, 1, { stop: stop, noDescend: noDescend } ).steps; steps.slice( 0, -1 ).forEach( ( s ) => { // Step type cannot be "internal", else the offset would have incremented const hasClass = function ( className ) { return s.node.nodeType === Node.ELEMENT_NODE && s.node.classList.contains( className ); }; found.preUnicorn = found.preUnicorn || ( hasClass( 've-ce-pre-unicorn' ) && s ); found.postUnicorn = found.postUnicorn || ( hasClass( 've-ce-post-unicorn' ) && s ); found.preOpenNail = found.preOpenNail || ( hasClass( 've-ce-nail-pre-open' ) && s ); found.postOpenNail = found.postOpenNail || ( hasClass( 've-ce-nail-post-open' ) && s ); found.preCloseNail = found.preCloseNail || ( hasClass( 've-ce-nail-pre-close' ) && s ); found.postCloseNail = found.postCloseNail || ( hasClass( 've-ce-nail-post-close' ) && s ); found.focusableNode = found.focusableNode || ( hasClass( 've-ce-focusableNode' ) && s ); found.text = found.text || ( s.node.nodeType === Node.TEXT_NODE && s ); } ); // If there is a unicorn, it should be a unique pre/post-Unicorn pair containing text or // nothing return the position just inside. if ( found.preUnicorn ) { return ve.ce.nextCursorOffset( found.preUnicorn.node ); } if ( found.postUnicorn ) { return ve.ce.previousCursorOffset( found.postUnicorn.node ); } if ( found.preOpenNail ) { // This will also cover the case where there is a post-open nail, as there will // be no offset difference between them return ve.ce.previousCursorOffset( found.preOpenNail.node ); } if ( found.postCloseNail ) { // This will also cover the case where there is a pre-close nail, as there will // be no offset difference between them return ve.ce.nextCursorOffset( found.postCloseNail.node ); } if ( found.text ) { if ( position.node.nodeType === Node.TEXT_NODE ) { return position; } // We must either have entered or left the text node return { node: found.text.node, offset: 0 }; } return position; }; /** * Get the block directionality of some range * * Uses the computed CSS direction value of the current node * * @param {ve.Range} range * @return {string} 'rtl', 'ltr' */ ve.ce.Document.prototype.getDirectionalityFromRange = function ( range ) { const selectedNodes = this.selectNodes( range, 'covered' ); let effectiveNode; if ( selectedNodes.length > 1 ) { // Selection of multiple nodes // Get the common parent node effectiveNode = this.selectNodes( range, 'siblings' )[ 0 ].node.getParent(); } else { // Selection of a single node effectiveNode = selectedNodes[ 0 ].node; while ( effectiveNode.isContent() ) { // This means that we're in a leaf node, like TextNode // those don't read the directionality properly, we will // have to climb up the parentage chain until we find a // wrapping node like paragraph or list item, etc. effectiveNode = effectiveNode.parent; } } return effectiveNode.$element.css( 'direction' ); };
| ver. 1.1 | |
.
| PHP 8.4.18 | Ð“ÐµÐ½ÐµÑ€Ð°Ñ†Ð¸Ñ Ñтраницы: 0 |
proxy
|
phpinfo
|
ÐаÑтройка