X-Git-Url: https://scm.cri.ensmp.fr/git/ckeditor.git/blobdiff_plain/e11f66eb655db8339a2d9b197b89f6c3b26099e1..579f65bc95a773bc6f8da75f6849ea49f365368b:/skins/ckeditor/_source/plugins/selection/plugin.js
diff --git a/skins/ckeditor/_source/plugins/selection/plugin.js b/skins/ckeditor/_source/plugins/selection/plugin.js
deleted file mode 100644
index d8888c1..0000000
--- a/skins/ckeditor/_source/plugins/selection/plugin.js
+++ /dev/null
@@ -1,1601 +0,0 @@
-/*
-Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved.
-For licensing, see LICENSE.html or http://ckeditor.com/license
-*/
-
-(function()
-{
- // #### checkSelectionChange : START
-
- // The selection change check basically saves the element parent tree of
- // the current node and check it on successive requests. If there is any
- // change on the tree, then the selectionChange event gets fired.
- function checkSelectionChange()
- {
- try
- {
- // In IE, the "selectionchange" event may still get thrown when
- // releasing the WYSIWYG mode, so we need to check it first.
- var sel = this.getSelection();
- if ( !sel || !sel.document.getWindow().$ )
- return;
-
- var firstElement = sel.getStartElement();
- var currentPath = new CKEDITOR.dom.elementPath( firstElement );
-
- if ( !currentPath.compare( this._.selectionPreviousPath ) )
- {
- this._.selectionPreviousPath = currentPath;
- this.fire( 'selectionChange', { selection : sel, path : currentPath, element : firstElement } );
- }
- }
- catch (e)
- {}
- }
-
- var checkSelectionChangeTimer,
- checkSelectionChangeTimeoutPending;
-
- function checkSelectionChangeTimeout()
- {
- // Firing the "OnSelectionChange" event on every key press started to
- // be too slow. This function guarantees that there will be at least
- // 200ms delay between selection checks.
-
- checkSelectionChangeTimeoutPending = true;
-
- if ( checkSelectionChangeTimer )
- return;
-
- checkSelectionChangeTimeoutExec.call( this );
-
- checkSelectionChangeTimer = CKEDITOR.tools.setTimeout( checkSelectionChangeTimeoutExec, 200, this );
- }
-
- function checkSelectionChangeTimeoutExec()
- {
- checkSelectionChangeTimer = null;
-
- if ( checkSelectionChangeTimeoutPending )
- {
- // Call this with a timeout so the browser properly moves the
- // selection after the mouseup. It happened that the selection was
- // being moved after the mouseup when clicking inside selected text
- // with Firefox.
- CKEDITOR.tools.setTimeout( checkSelectionChange, 0, this );
-
- checkSelectionChangeTimeoutPending = false;
- }
- }
-
- // #### checkSelectionChange : END
-
- function rangeRequiresFix( range )
- {
- function isInlineCt( node )
- {
- return node && node.type == CKEDITOR.NODE_ELEMENT
- && node.getName() in CKEDITOR.dtd.$removeEmpty;
- }
-
- function singletonBlock( node )
- {
- var body = range.document.getBody();
- return !node.is( 'body' ) && body.getChildCount() == 1;
- }
-
- var start = range.startContainer,
- offset = range.startOffset;
-
- if ( start.type == CKEDITOR.NODE_TEXT )
- return false;
-
- // 1. Empty inline element. ^
- // 2. Adjoin to inline element.
text^
- // 3. The only empty block in document.
^
(#7222)
- return !CKEDITOR.tools.trim( start.getHtml() ) ? isInlineCt( start ) || singletonBlock( start )
- : isInlineCt( start.getChild( offset - 1 ) ) || isInlineCt( start.getChild( offset ) );
- }
-
- var selectAllCmd =
- {
- modes : { wysiwyg : 1, source : 1 },
- readOnly : CKEDITOR.env.ie || CKEDITOR.env.webkit,
- exec : function( editor )
- {
- switch ( editor.mode )
- {
- case 'wysiwyg' :
- editor.document.$.execCommand( 'SelectAll', false, null );
- // Force triggering selectionChange (#7008)
- editor.forceNextSelectionCheck();
- editor.selectionChange();
- break;
- case 'source' :
- // Select the contents of the textarea
- var textarea = editor.textarea.$;
- if ( CKEDITOR.env.ie )
- textarea.createTextRange().execCommand( 'SelectAll' );
- else
- {
- textarea.selectionStart = 0;
- textarea.selectionEnd = textarea.value.length;
- }
- textarea.focus();
- }
- },
- canUndo : false
- };
-
- function createFillingChar( doc )
- {
- removeFillingChar( doc );
-
- var fillingChar = doc.createText( '\u200B' );
- doc.setCustomData( 'cke-fillingChar', fillingChar );
-
- return fillingChar;
- }
-
- function getFillingChar( doc )
- {
- return doc && doc.getCustomData( 'cke-fillingChar' );
- }
-
- // Checks if a filling char has been used, eventualy removing it (#1272).
- function checkFillingChar( doc )
- {
- var fillingChar = doc && getFillingChar( doc );
- if ( fillingChar )
- {
- // Use this flag to avoid removing the filling char right after
- // creating it.
- if ( fillingChar.getCustomData( 'ready' ) )
- removeFillingChar( doc );
- else
- fillingChar.setCustomData( 'ready', 1 );
- }
- }
-
- function removeFillingChar( doc )
- {
- var fillingChar = doc && doc.removeCustomData( 'cke-fillingChar' );
- if ( fillingChar )
- {
- // We can't simply remove the filling node because the user
- // will actually enlarge it when typing, so we just remove the
- // invisible char from it.
- fillingChar.setText( fillingChar.getText().replace( /\u200B/g, '' ) );
- fillingChar = 0;
- }
- }
-
- CKEDITOR.plugins.add( 'selection',
- {
- init : function( editor )
- {
- // On WebKit only, we need a special "filling" char on some situations
- // (#1272). Here we set the events that should invalidate that char.
- if ( CKEDITOR.env.webkit )
- {
- editor.on( 'selectionChange', function() { checkFillingChar( editor.document ); } );
- editor.on( 'beforeSetMode', function() { removeFillingChar( editor.document ); } );
- editor.on( 'key', function( e )
- {
- // Remove the filling char before some keys get
- // executed, so they'll not get blocked by it.
- switch ( e.data.keyCode )
- {
- case 13 : // ENTER
- case CKEDITOR.SHIFT + 13 : // SHIFT-ENTER
- case 37 : // LEFT-ARROW
- case 39 : // RIGHT-ARROW
- case 8 : // BACKSPACE
- removeFillingChar( editor.document );
- }
- }, null, null, 10 );
-
- var fillingCharBefore,
- resetSelection;
-
- function beforeData()
- {
- var doc = editor.document,
- fillingChar = getFillingChar( doc );
-
- if ( fillingChar )
- {
- // If cursor is right blinking by side of the filler node, save it for restoring,
- // as the following text substitution will blind it. (#7437)
- var sel = doc.$.defaultView.getSelection();
- if ( sel.type == 'Caret' && sel.anchorNode == fillingChar.$ )
- resetSelection = 1;
-
- fillingCharBefore = fillingChar.getText();
- fillingChar.setText( fillingCharBefore.replace( /\u200B/g, '' ) );
- }
- }
- function afterData()
- {
- var doc = editor.document,
- fillingChar = getFillingChar( doc );
-
- if ( fillingChar )
- {
- fillingChar.setText( fillingCharBefore );
-
- if ( resetSelection )
- {
- doc.$.defaultView.getSelection().setPosition( fillingChar.$,fillingChar.getLength() );
- resetSelection = 0;
- }
- }
- }
- editor.on( 'beforeUndoImage', beforeData );
- editor.on( 'afterUndoImage', afterData );
- editor.on( 'beforeGetData', beforeData, null, null, 0 );
- editor.on( 'getData', afterData );
- }
-
- editor.on( 'contentDom', function()
- {
- var doc = editor.document,
- body = doc.getBody(),
- html = doc.getDocumentElement();
-
- if ( CKEDITOR.env.ie )
- {
- // Other browsers don't loose the selection if the
- // editor document loose the focus. In IE, we don't
- // have support for it, so we reproduce it here, other
- // than firing the selection change event.
-
- var savedRange,
- saveEnabled,
- restoreEnabled = 1;
-
- // "onfocusin" is fired before "onfocus". It makes it
- // possible to restore the selection before click
- // events get executed.
- body.on( 'focusin', function( evt )
- {
- // If there are elements with layout they fire this event but
- // it must be ignored to allow edit its contents #4682
- if ( evt.data.$.srcElement.nodeName != 'BODY' )
- return;
-
- // If we have saved a range, restore it at this
- // point.
- if ( savedRange )
- {
- if ( restoreEnabled )
- {
- // Well not break because of this.
- try
- {
- savedRange.select();
- }
- catch (e)
- {}
-
- // Update locked selection because of the normalized text nodes. (#6083, #6987)
- var lockedSelection = doc.getCustomData( 'cke_locked_selection' );
- if ( lockedSelection )
- {
- lockedSelection.unlock();
- lockedSelection.lock();
- }
- }
-
- savedRange = null;
- }
- });
-
- body.on( 'focus', function()
- {
- // Enable selections to be saved.
- saveEnabled = 1;
-
- saveSelection();
- });
-
- body.on( 'beforedeactivate', function( evt )
- {
- // Ignore this event if it's caused by focus switch between
- // internal editable control type elements, e.g. layouted paragraph. (#4682)
- if ( evt.data.$.toElement )
- return;
-
- // Disable selections from being saved.
- saveEnabled = 0;
- restoreEnabled = 1;
- });
-
- // IE before version 8 will leave cursor blinking inside the document after
- // editor blurred unless we clean up the selection. (#4716)
- if ( CKEDITOR.env.ie && CKEDITOR.env.version < 8 )
- {
- editor.on( 'blur', function( evt )
- {
- // Try/Catch to avoid errors if the editor is hidden. (#6375)
- try
- {
- editor.document && editor.document.$.selection.empty();
- }
- catch (e) {}
- });
- }
-
- // Listening on document element ensures that
- // scrollbar is included. (#5280)
- html.on( 'mousedown', function()
- {
- // Lock restore selection now, as we have
- // a followed 'click' event which introduce
- // new selection. (#5735)
- restoreEnabled = 0;
- });
-
- html.on( 'mouseup', function()
- {
- restoreEnabled = 1;
- });
-
- // In IE6/7 the blinking cursor appears, but contents are
- // not editable. (#5634)
- if ( CKEDITOR.env.ie && ( CKEDITOR.env.ie7Compat || CKEDITOR.env.version < 8 || CKEDITOR.env.quirks ) )
- {
- // The 'click' event is not fired when clicking the
- // scrollbars, so we can use it to check whether
- // the empty space following has been clicked.
- html.on( 'click', function( evt )
- {
- if ( evt.data.getTarget().getName() == 'html' )
- editor.getSelection().getRanges()[ 0 ].select();
- });
- }
-
- var scroll;
- // IE fires the "selectionchange" event when clicking
- // inside a selection. We don't want to capture that.
- body.on( 'mousedown', function( evt )
- {
- // IE scrolls document to top on right mousedown
- // when editor has no focus, remember this scroll
- // position and revert it before context menu opens. (#5778)
- if ( evt.data.$.button == 2 )
- {
- var sel = editor.document.$.selection;
- if ( sel.type == 'None' )
- scroll = editor.window.getScrollPosition();
- }
- disableSave();
- });
-
- body.on( 'mouseup',
- function( evt )
- {
- // Restore recorded scroll position when needed on right mouseup.
- if ( evt.data.$.button == 2 && scroll )
- {
- editor.document.$.documentElement.scrollLeft = scroll.x;
- editor.document.$.documentElement.scrollTop = scroll.y;
- }
- scroll = null;
-
- saveEnabled = 1;
- setTimeout( function()
- {
- saveSelection( true );
- },
- 0 );
- });
-
- body.on( 'keydown', disableSave );
- body.on( 'keyup',
- function()
- {
- saveEnabled = 1;
- saveSelection();
- });
-
-
- // IE is the only to provide the "selectionchange"
- // event.
- doc.on( 'selectionchange', saveSelection );
-
- function disableSave()
- {
- saveEnabled = 0;
- }
-
- function saveSelection( testIt )
- {
- if ( saveEnabled )
- {
- var doc = editor.document,
- sel = editor.getSelection(),
- nativeSel = sel && sel.getNative();
-
- // There is a very specific case, when clicking
- // inside a text selection. In that case, the
- // selection collapses at the clicking point,
- // but the selection object remains in an
- // unknown state, making createRange return a
- // range at the very start of the document. In
- // such situation we have to test the range, to
- // be sure it's valid.
- if ( testIt && nativeSel && nativeSel.type == 'None' )
- {
- // The "InsertImage" command can be used to
- // test whether the selection is good or not.
- // If not, it's enough to give some time to
- // IE to put things in order for us.
- if ( !doc.$.queryCommandEnabled( 'InsertImage' ) )
- {
- CKEDITOR.tools.setTimeout( saveSelection, 50, this, true );
- return;
- }
- }
-
- // Avoid saving selection from within text input. (#5747)
- var parentTag;
- if ( nativeSel && nativeSel.type && nativeSel.type != 'Control'
- && ( parentTag = nativeSel.createRange() )
- && ( parentTag = parentTag.parentElement() )
- && ( parentTag = parentTag.nodeName )
- && parentTag.toLowerCase() in { input: 1, textarea : 1 } )
- {
- return;
- }
-
- savedRange = nativeSel && sel.getRanges()[ 0 ];
-
- checkSelectionChangeTimeout.call( editor );
- }
- }
- }
- else
- {
- // In other browsers, we make the selection change
- // check based on other events, like clicks or keys
- // press.
-
- doc.on( 'mouseup', checkSelectionChangeTimeout, editor );
- doc.on( 'keyup', checkSelectionChangeTimeout, editor );
- }
- });
-
- // Clear the cached range path before unload. (#7174)
- editor.on( 'contentDomUnload', editor.forceNextSelectionCheck, editor );
-
- editor.addCommand( 'selectAll', selectAllCmd );
- editor.ui.addButton( 'SelectAll',
- {
- label : editor.lang.selectAll,
- command : 'selectAll'
- });
-
- editor.selectionChange = checkSelectionChangeTimeout;
-
- // IE9 might cease to work if there's an object selection inside the iframe (#7639).
- CKEDITOR.env.ie9Compat && editor.on( 'destroy', function()
- {
- var sel = editor.getSelection();
- sel && sel.getNative().clear();
- }, null, null, 9 );
- }
- });
-
- /**
- * Gets the current selection from the editing area when in WYSIWYG mode.
- * @returns {CKEDITOR.dom.selection} A selection object or null if not on
- * WYSIWYG mode or no selection is available.
- * @example
- * var selection = CKEDITOR.instances.editor1.getSelection();
- * alert( selection.getType() );
- */
- CKEDITOR.editor.prototype.getSelection = function()
- {
- return this.document && this.document.getSelection();
- };
-
- CKEDITOR.editor.prototype.forceNextSelectionCheck = function()
- {
- delete this._.selectionPreviousPath;
- };
-
- /**
- * Gets the current selection from the document.
- * @returns {CKEDITOR.dom.selection} A selection object.
- * @example
- * var selection = CKEDITOR.instances.editor1.document.getSelection();
- * alert( selection.getType() );
- */
- CKEDITOR.dom.document.prototype.getSelection = function()
- {
- var sel = new CKEDITOR.dom.selection( this );
- return ( !sel || sel.isInvalid ) ? null : sel;
- };
-
- /**
- * No selection.
- * @constant
- * @example
- * if ( editor.getSelection().getType() == CKEDITOR.SELECTION_NONE )
- * alert( 'Nothing is selected' );
- */
- CKEDITOR.SELECTION_NONE = 1;
-
- /**
- * Text or collapsed selection.
- * @constant
- * @example
- * if ( editor.getSelection().getType() == CKEDITOR.SELECTION_TEXT )
- * alert( 'Text is selected' );
- */
- CKEDITOR.SELECTION_TEXT = 2;
-
- /**
- * Element selection.
- * @constant
- * @example
- * if ( editor.getSelection().getType() == CKEDITOR.SELECTION_ELEMENT )
- * alert( 'An element is selected' );
- */
- CKEDITOR.SELECTION_ELEMENT = 3;
-
- /**
- * Manipulates the selection in a DOM document.
- * @constructor
- * @example
- */
- CKEDITOR.dom.selection = function( document )
- {
- var lockedSelection = document.getCustomData( 'cke_locked_selection' );
-
- if ( lockedSelection )
- return lockedSelection;
-
- this.document = document;
- this.isLocked = 0;
- this._ =
- {
- cache : {}
- };
-
- /**
- * IE BUG: The selection's document may be a different document than the
- * editor document. Return null if that's the case.
- */
- if ( CKEDITOR.env.ie )
- {
- var range = this.getNative().createRange();
- if ( !range
- || ( range.item && range.item(0).ownerDocument != this.document.$ )
- || ( range.parentElement && range.parentElement().ownerDocument != this.document.$ ) )
- {
- this.isInvalid = true;
- }
- }
-
- return this;
- };
-
- var styleObjectElements =
- {
- img:1,hr:1,li:1,table:1,tr:1,td:1,th:1,embed:1,object:1,ol:1,ul:1,
- a:1,input:1,form:1,select:1,textarea:1,button:1,fieldset:1,thead:1,tfoot:1
- };
-
- CKEDITOR.dom.selection.prototype =
- {
- /**
- * Gets the native selection object from the browser.
- * @function
- * @returns {Object} The native selection object.
- * @example
- * var selection = editor.getSelection().getNative();
- */
- getNative :
- CKEDITOR.env.ie ?
- function()
- {
- return this._.cache.nativeSel || ( this._.cache.nativeSel = this.document.$.selection );
- }
- :
- function()
- {
- return this._.cache.nativeSel || ( this._.cache.nativeSel = this.document.getWindow().$.getSelection() );
- },
-
- /**
- * Gets the type of the current selection. The following values are
- * available:
- *
- *
{@link CKEDITOR.SELECTION_NONE} (1): No selection.
- *
{@link CKEDITOR.SELECTION_TEXT} (2): Text is selected or
- * collapsed selection.
- *
{@link CKEDITOR.SELECTION_ELEMENT} (3): A element
- * selection.
- *
- * @function
- * @returns {Number} One of the following constant values:
- * {@link CKEDITOR.SELECTION_NONE}, {@link CKEDITOR.SELECTION_TEXT} or
- * {@link CKEDITOR.SELECTION_ELEMENT}.
- * @example
- * if ( editor.getSelection().getType() == CKEDITOR.SELECTION_TEXT )
- * alert( 'Text is selected' );
- */
- getType :
- CKEDITOR.env.ie ?
- function()
- {
- var cache = this._.cache;
- if ( cache.type )
- return cache.type;
-
- var type = CKEDITOR.SELECTION_NONE;
-
- try
- {
- var sel = this.getNative(),
- ieType = sel.type;
-
- if ( ieType == 'Text' )
- type = CKEDITOR.SELECTION_TEXT;
-
- if ( ieType == 'Control' )
- type = CKEDITOR.SELECTION_ELEMENT;
-
- // It is possible that we can still get a text range
- // object even when type == 'None' is returned by IE.
- // So we'd better check the object returned by
- // createRange() rather than by looking at the type.
- if ( sel.createRange().parentElement )
- type = CKEDITOR.SELECTION_TEXT;
- }
- catch(e) {}
-
- return ( cache.type = type );
- }
- :
- function()
- {
- var cache = this._.cache;
- if ( cache.type )
- return cache.type;
-
- var type = CKEDITOR.SELECTION_TEXT;
-
- var sel = this.getNative();
-
- if ( !sel )
- type = CKEDITOR.SELECTION_NONE;
- else if ( sel.rangeCount == 1 )
- {
- // Check if the actual selection is a control (IMG,
- // TABLE, HR, etc...).
-
- var range = sel.getRangeAt(0),
- startContainer = range.startContainer;
-
- if ( startContainer == range.endContainer
- && startContainer.nodeType == 1
- && ( range.endOffset - range.startOffset ) == 1
- && styleObjectElements[ startContainer.childNodes[ range.startOffset ].nodeName.toLowerCase() ] )
- {
- type = CKEDITOR.SELECTION_ELEMENT;
- }
- }
-
- return ( cache.type = type );
- },
-
- /**
- * Retrieve the {@link CKEDITOR.dom.range} instances that represent the current selection.
- * Note: Some browsers returns multiple ranges even on a sequent selection, e.g. Firefox returns
- * one range for each table cell when one or more table row is selected.
- * @return {Array}
- * @example
- * var ranges = selection.getRanges();
- * alert(ranges.length);
- */
- getRanges : (function()
- {
- var func = CKEDITOR.env.ie ?
- ( function()
- {
- function getNodeIndex( node ) { return new CKEDITOR.dom.node( node ).getIndex(); }
-
- // Finds the container and offset for a specific boundary
- // of an IE range.
- var getBoundaryInformation = function( range, start )
- {
- // Creates a collapsed range at the requested boundary.
- range = range.duplicate();
- range.collapse( start );
-
- // Gets the element that encloses the range entirely.
- var parent = range.parentElement(),
- doc = parent.ownerDocument;
-
- // Empty parent element, e.g. ^
- if ( !parent.hasChildNodes() )
- return { container : parent, offset : 0 };
-
- var siblings = parent.children,
- child,
- sibling,
- testRange = range.duplicate(),
- startIndex = 0,
- endIndex = siblings.length - 1,
- index = -1,
- position,
- distance;
-
- // Binary search over all element childs to test the range to see whether
- // range is right on the boundary of one element.
- while ( startIndex <= endIndex )
- {
- index = Math.floor( ( startIndex + endIndex ) / 2 );
- child = siblings[ index ];
- testRange.moveToElementText( child );
- position = testRange.compareEndPoints( 'StartToStart', range );
-
- if ( position > 0 )
- endIndex = index - 1;
- else if ( position < 0 )
- startIndex = index + 1;
- else
- {
- // IE9 report wrong measurement with compareEndPoints when range anchors between two BRs.
- // e.g.
text ^
(#7433)
- if ( CKEDITOR.env.ie9Compat && child.tagName == 'BR' )
- {
- var bmId = 'cke_range_marker';
- range.execCommand( 'CreateBookmark', false, bmId );
- child = doc.getElementsByName( bmId )[ 0 ];
- var offset = getNodeIndex( child );
- parent.removeChild( child );
- return { container : parent, offset : offset };
- }
- else
- return { container : parent, offset : getNodeIndex( child ) };
- }
- }
-
- // All childs are text nodes,
- // or to the right hand of test range are all text nodes. (#6992)
- if ( index == -1 || index == siblings.length - 1 && position < 0 )
- {
- // Adapt test range to embrace the entire parent contents.
- testRange.moveToElementText( parent );
- testRange.setEndPoint( 'StartToStart', range );
-
- // IE report line break as CRLF with range.text but
- // only LF with textnode.nodeValue, normalize them to avoid
- // breaking character counting logic below. (#3949)
- distance = testRange.text.replace( /(\r\n|\r)/g, '\n' ).length;
-
- siblings = parent.childNodes;
-
- // Actual range anchor right beside test range at the boundary of text node.
- if ( !distance )
- {
- child = siblings[ siblings.length - 1 ];
-
- if ( child.nodeType == CKEDITOR.NODE_ELEMENT )
- return { container : parent, offset : siblings.length };
- else
- return { container : child, offset : child.nodeValue.length };
- }
-
- // Start the measuring until distance overflows, meanwhile count the text nodes.
- var i = siblings.length;
- while ( distance > 0 )
- distance -= siblings[ --i ].nodeValue.length;
-
- return { container : siblings[ i ], offset : -distance };
- }
- // Test range was one offset beyond OR behind the anchored text node.
- else
- {
- // Adapt one side of test range to the actual range
- // for measuring the offset between them.
- testRange.collapse( position > 0 ? true : false );
- testRange.setEndPoint( position > 0 ? 'StartToStart' : 'EndToStart', range );
-
- // IE report line break as CRLF with range.text but
- // only LF with textnode.nodeValue, normalize them to avoid
- // breaking character counting logic below. (#3949)
- distance = testRange.text.replace( /(\r\n|\r)/g, '\n' ).length;
-
- // Actual range anchor right beside test range at the inner boundary of text node.
- if ( !distance )
- return { container : parent, offset : getNodeIndex( child ) + ( position > 0 ? 0 : 1 ) };
-
- // Start the measuring until distance overflows, meanwhile count the text nodes.
- while ( distance > 0 )
- {
- try
- {
- sibling = child[ position > 0 ? 'previousSibling' : 'nextSibling' ];
- distance -= sibling.nodeValue.length;
- child = sibling;
- }
- // Measurement in IE could be somtimes wrong because of