@@ -672,7 +672,7 @@ describe( 'LiveSelection', () => {
672672 } ) ;
673673 } ) ;
674674
675- describe ( 'attributes interface ' , ( ) => {
675+ describe ( 'attributes' , ( ) => {
676676 let fullP , emptyP , rangeInFullP , rangeInEmptyP ;
677677
678678 beforeEach ( ( ) => {
@@ -688,7 +688,7 @@ describe( 'LiveSelection', () => {
688688 rangeInEmptyP = new Range ( new Position ( root , [ 1 , 0 ] ) , new Position ( root , [ 1 , 0 ] ) ) ;
689689 } ) ;
690690
691- describe ( 'setAttribute' , ( ) => {
691+ describe ( 'setAttribute() ' , ( ) => {
692692 it ( 'should store attribute if the selection is in empty node' , ( ) => {
693693 selection . setRanges ( [ rangeInEmptyP ] ) ;
694694 selection . setAttribute ( 'foo' , 'bar' ) ;
@@ -699,7 +699,7 @@ describe( 'LiveSelection', () => {
699699 } ) ;
700700 } ) ;
701701
702- describe ( 'setAttributesTo' , ( ) => {
702+ describe ( 'setAttributesTo() ' , ( ) => {
703703 it ( 'should fire change:attribute event with correct parameters' , done => {
704704 selection . setAttributesTo ( { foo : 'bar' , abc : 'def' } ) ;
705705
@@ -737,7 +737,7 @@ describe( 'LiveSelection', () => {
737737 } ) ;
738738 } ) ;
739739
740- describe ( 'removeAttribute' , ( ) => {
740+ describe ( 'removeAttribute() ' , ( ) => {
741741 it ( 'should remove attribute set on the text fragment' , ( ) => {
742742 selection . setRanges ( [ rangeInFullP ] ) ;
743743 selection . setAttribute ( 'foo' , 'bar' ) ;
@@ -759,7 +759,7 @@ describe( 'LiveSelection', () => {
759759 } ) ;
760760 } ) ;
761761
762- describe ( 'clearAttributes' , ( ) => {
762+ describe ( 'clearAttributes() ' , ( ) => {
763763 it ( 'should remove all stored attributes if the selection is in empty node' , ( ) => {
764764 selection . setRanges ( [ rangeInEmptyP ] ) ;
765765 selection . setAttribute ( 'foo' , 'bar' ) ;
@@ -774,102 +774,166 @@ describe( 'LiveSelection', () => {
774774 expect ( emptyP . hasAttribute ( LiveSelection . _getStoreAttributeKey ( 'abc' ) ) ) . to . be . false ;
775775 } ) ;
776776 } ) ;
777- } ) ;
778777
779- describe ( 'update attributes on direct range change' , ( ) => {
780- beforeEach ( ( ) => {
781- root . insertChildren ( 0 , [
782- new Element ( 'p' , { p : true } ) ,
783- new Text ( 'a' , { a : true } ) ,
784- new Element ( 'p' , { p : true } ) ,
785- new Text ( 'b' , { b : true } ) ,
786- new Text ( 'c' , { c : true } ) ,
787- new Element ( 'p' , [ ] , [
788- new Text ( 'd' , { d : true } )
789- ] ) ,
790- new Element ( 'p' , { p : true } ) ,
791- new Text ( 'e' , { e : true } )
792- ] ) ;
778+ describe ( '_getStoredAttributes()' , ( ) => {
779+ it ( 'should return no values if there are no ranges in selection' , ( ) => {
780+ const values = Array . from ( selection . _getStoredAttributes ( ) ) ;
781+
782+ expect ( values ) . to . deep . equal ( [ ] ) ;
783+ } ) ;
793784 } ) ;
794785
795- it ( 'if selection is a range, should find first character in it and copy it\'s attributes' , ( ) => {
796- selection . setRanges ( [ new Range ( new Position ( root , [ 2 ] ) , new Position ( root , [ 5 ] ) ) ] ) ;
786+ describe ( 'are updated on a direct range change' , ( ) => {
787+ beforeEach ( ( ) => {
788+ root . insertChildren ( 0 , [
789+ new Element ( 'p' , { p : true } ) ,
790+ new Text ( 'a' , { a : true } ) ,
791+ new Element ( 'p' , { p : true } ) ,
792+ new Text ( 'b' , { b : true } ) ,
793+ new Text ( 'c' , { c : true } ) ,
794+ new Element ( 'p' , [ ] , [
795+ new Text ( 'd' , { d : true } )
796+ ] ) ,
797+ new Element ( 'p' , { p : true } ) ,
798+ new Text ( 'e' , { e : true } )
799+ ] ) ;
800+ } ) ;
797801
798- expect ( Array . from ( selection . getAttributes ( ) ) ) . to . deep . equal ( [ [ 'b' , true ] ] ) ;
802+ it ( 'if selection is a range, should find first character in it and copy it\'s attributes' , ( ) => {
803+ selection . setRanges ( [ new Range ( new Position ( root , [ 2 ] ) , new Position ( root , [ 5 ] ) ) ] ) ;
799804
800- // Step into elements when looking for first character:
801- selection . setRanges ( [ new Range ( new Position ( root , [ 5 ] ) , new Position ( root , [ 7 ] ) ) ] ) ;
805+ expect ( Array . from ( selection . getAttributes ( ) ) ) . to . deep . equal ( [ [ 'b' , true ] ] ) ;
802806
803- expect ( Array . from ( selection . getAttributes ( ) ) ) . to . deep . equal ( [ [ 'd' , true ] ] ) ;
804- } ) ;
807+ // Step into elements when looking for first character:
808+ selection . setRanges ( [ new Range ( new Position ( root , [ 5 ] ) , new Position ( root , [ 7 ] ) ) ] ) ;
805809
806- it ( 'if selection is collapsed it should seek a character to copy that character\'s attributes' , ( ) => {
807- // Take styles from character before selection.
808- selection . setRanges ( [ new Range ( new Position ( root , [ 2 ] ) , new Position ( root , [ 2 ] ) ) ] ) ;
809- expect ( Array . from ( selection . getAttributes ( ) ) ) . to . deep . equal ( [ [ 'a' , true ] ] ) ;
810+ expect ( Array . from ( selection . getAttributes ( ) ) ) . to . deep . equal ( [ [ 'd' , true ] ] ) ;
811+ } ) ;
810812
811- // If there are none,
812- // Take styles from character after selection.
813- selection . setRanges ( [ new Range ( new Position ( root , [ 3 ] ) , new Position ( root , [ 3 ] ) ) ] ) ;
814- expect ( Array . from ( selection . getAttributes ( ) ) ) . to . deep . equal ( [ [ 'b' , true ] ] ) ;
813+ it ( 'if selection is collapsed it should seek a character to copy that character\'s attributes' , ( ) => {
814+ // Take styles from character before selection.
815+ selection . setRanges ( [ new Range ( new Position ( root , [ 2 ] ) , new Position ( root , [ 2 ] ) ) ] ) ;
816+ expect ( Array . from ( selection . getAttributes ( ) ) ) . to . deep . equal ( [ [ 'a' , true ] ] ) ;
817+
818+ // If there are none,
819+ // Take styles from character after selection.
820+ selection . setRanges ( [ new Range ( new Position ( root , [ 3 ] ) , new Position ( root , [ 3 ] ) ) ] ) ;
821+ expect ( Array . from ( selection . getAttributes ( ) ) ) . to . deep . equal ( [ [ 'b' , true ] ] ) ;
822+
823+ // If there are none,
824+ // Look from the selection position to the beginning of node looking for character to take attributes from.
825+ selection . setRanges ( [ new Range ( new Position ( root , [ 6 ] ) , new Position ( root , [ 6 ] ) ) ] ) ;
826+ expect ( Array . from ( selection . getAttributes ( ) ) ) . to . deep . equal ( [ [ 'c' , true ] ] ) ;
827+
828+ // If there are none,
829+ // Look from the selection position to the end of node looking for character to take attributes from.
830+ selection . setRanges ( [ new Range ( new Position ( root , [ 0 ] ) , new Position ( root , [ 0 ] ) ) ] ) ;
831+ expect ( Array . from ( selection . getAttributes ( ) ) ) . to . deep . equal ( [ [ 'a' , true ] ] ) ;
832+
833+ // If there are no characters to copy attributes from, use stored attributes.
834+ selection . setRanges ( [ new Range ( new Position ( root , [ 0 , 0 ] ) , new Position ( root , [ 0 , 0 ] ) ) ] ) ;
835+ expect ( Array . from ( selection . getAttributes ( ) ) ) . to . deep . equal ( [ ] ) ;
836+ } ) ;
815837
816- // If there are none,
817- // Look from the selection position to the beginning of node looking for character to take attributes from.
818- selection . setRanges ( [ new Range ( new Position ( root , [ 6 ] ) , new Position ( root , [ 6 ] ) ) ] ) ;
819- expect ( Array . from ( selection . getAttributes ( ) ) ) . to . deep . equal ( [ [ 'c' , true ] ] ) ;
838+ it ( 'should overwrite any previously set attributes' , ( ) => {
839+ selection . collapse ( new Position ( root , [ 5 , 0 ] ) ) ;
820840
821- // If there are none,
822- // Look from the selection position to the end of node looking for character to take attributes from.
823- selection . setRanges ( [ new Range ( new Position ( root , [ 0 ] ) , new Position ( root , [ 0 ] ) ) ] ) ;
824- expect ( Array . from ( selection . getAttributes ( ) ) ) . to . deep . equal ( [ [ 'a' , true ] ] ) ;
841+ selection . setAttribute ( 'x' , true ) ;
842+ selection . setAttribute ( 'y' , true ) ;
825843
826- // If there are no characters to copy attributes from, use stored attributes.
827- selection . setRanges ( [ new Range ( new Position ( root , [ 0 , 0 ] ) , new Position ( root , [ 0 , 0 ] ) ) ] ) ;
828- expect ( Array . from ( selection . getAttributes ( ) ) ) . to . deep . equal ( [ ] ) ;
829- } ) ;
844+ expect ( Array . from ( selection . getAttributes ( ) ) ) . to . deep . equal ( [ [ 'd' , true ] , [ 'x' , true ] , [ 'y' , true ] ] ) ;
830845
831- it ( 'should overwrite any previously set attributes' , ( ) => {
832- selection . collapse ( new Position ( root , [ 5 , 0 ] ) ) ;
846+ selection . collapse ( new Position ( root , [ 1 ] ) ) ;
833847
834- selection . setAttribute ( 'x ', true ) ;
835- selection . setAttribute ( 'y' , true ) ;
848+ expect ( Array . from ( selection . getAttributes ( ) ) ) . to . deep . equal ( [ [ 'a ', true ] ] ) ;
849+ } ) ;
836850
837- expect ( Array . from ( selection . getAttributes ( ) ) ) . to . deep . equal ( [ [ 'd' , true ] , [ 'x' , true ] , [ 'y' , true ] ] ) ;
851+ it ( 'should fire change:attribute event' , ( ) => {
852+ const spy = sinon . spy ( ) ;
853+ selection . on ( 'change:attribute' , spy ) ;
838854
839- selection . collapse ( new Position ( root , [ 1 ] ) ) ;
855+ selection . setRanges ( [ new Range ( new Position ( root , [ 2 ] ) , new Position ( root , [ 5 ] ) ) ] ) ;
840856
841- expect ( Array . from ( selection . getAttributes ( ) ) ) . to . deep . equal ( [ [ 'a' , true ] ] ) ;
842- } ) ;
857+ expect ( spy . calledOnce ) . to . be . true ;
858+ } ) ;
843859
844- it ( 'should fire change:attribute event' , ( ) => {
845- const spy = sinon . spy ( ) ;
846- selection . on ( 'change:attribute' , spy ) ;
860+ it ( 'should not fire change:attribute event if attributes did not change' , ( ) => {
861+ selection . collapse ( new Position ( root , [ 5 , 0 ] ) ) ;
847862
848- selection . setRanges ( [ new Range ( new Position ( root , [ 2 ] ) , new Position ( root , [ 5 ] ) ) ] ) ;
863+ expect ( Array . from ( selection . getAttributes ( ) ) ) . to . deep . equal ( [ [ 'd' , true ] ] ) ;
849864
850- expect ( spy . calledOnce ) . to . be . true ;
865+ const spy = sinon . spy ( ) ;
866+ selection . on ( 'change:attribute' , spy ) ;
867+
868+ selection . collapse ( new Position ( root , [ 5 , 1 ] ) ) ;
869+
870+ expect ( Array . from ( selection . getAttributes ( ) ) ) . to . deep . equal ( [ [ 'd' , true ] ] ) ;
871+ expect ( spy . called ) . to . be . false ;
872+ } ) ;
851873 } ) ;
852874
853- it ( 'should not fire change:attribute event if attributes did not change' , ( ) => {
854- selection . collapse ( new Position ( root , [ 5 , 0 ] ) ) ;
875+ // #986
876+ describe ( 'are not inherited from the inside of object elements' , ( ) => {
877+ beforeEach ( ( ) => {
878+ doc . schema . registerItem ( 'image' ) ;
879+ doc . schema . allow ( { name : 'image' , inside : '$root' } ) ;
880+ doc . schema . allow ( { name : 'image' , inside : '$block' } ) ;
881+ doc . schema . allow ( { name : '$inline' , inside : 'image' } ) ;
882+ doc . schema . objects . add ( 'image' ) ;
855883
856- expect ( Array . from ( selection . getAttributes ( ) ) ) . to . deep . equal ( [ [ 'd' , true ] ] ) ;
884+ doc . schema . registerItem ( 'caption' ) ;
885+ doc . schema . allow ( { name : '$inline' , inside : 'caption' } ) ;
886+ doc . schema . allow ( { name : 'caption' , inside : 'image' } ) ;
887+ doc . schema . allow ( { name : '$text' , attributes : 'bold' , inside : 'caption' } ) ;
888+ } ) ;
857889
858- const spy = sinon . spy ( ) ;
859- selection . on ( 'change:attribute' , spy ) ;
890+ it ( 'ignores attributes inside an object if selection contains that object' , ( ) => {
891+ setData ( doc , '<p>[<image><$text bold="true">Caption for the image.</$text></image>]</p>' ) ;
860892
861- selection . collapse ( new Position ( root , [ 5 , 1 ] ) ) ;
893+ const liveSelection = LiveSelection . createFromSelection ( selection ) ;
862894
863- expect ( Array . from ( selection . getAttributes ( ) ) ) . to . deep . equal ( [ [ 'd' , true ] ] ) ;
864- expect ( spy . called ) . to . be . false ;
865- } ) ;
866- } ) ;
895+ expect ( liveSelection . hasAttribute ( 'bold' ) ) . to . equal ( false ) ;
896+ } ) ;
897+
898+ it ( 'ignores attributes inside an object if selection contains that object (deeper structure)' , ( ) => {
899+ setData ( doc , '<p>[<image><caption><$text bold="true">Caption for the image.</$text></caption></image>]</p>' ) ;
900+
901+ const liveSelection = LiveSelection . createFromSelection ( selection ) ;
902+
903+ expect ( liveSelection . hasAttribute ( 'bold' ) ) . to . equal ( false ) ;
904+ } ) ;
905+
906+ it ( 'ignores attributes inside an object if selection contains that object (block level)' , ( ) => {
907+ setData ( doc , '<p>foo</p>[<image><$text bold="true">Caption for the image.</$text></image>]<p>foo</p>' ) ;
908+
909+ const liveSelection = LiveSelection . createFromSelection ( selection ) ;
910+
911+ expect ( liveSelection . hasAttribute ( 'bold' ) ) . to . equal ( false ) ;
912+ } ) ;
913+
914+ it ( 'reads attributes from text even if the selection contains an object' , ( ) => {
915+ setData ( doc , '<p>x<$text bold="true">[bar</$text><image></image>foo]</p>' ) ;
916+
917+ const liveSelection = LiveSelection . createFromSelection ( selection ) ;
918+
919+ expect ( liveSelection . getAttribute ( 'bold' ) ) . to . equal ( true ) ;
920+ } ) ;
921+
922+ it ( 'reads attributes when the entire selection inside an object' , ( ) => {
923+ setData ( doc , '<p><image><caption><$text bold="true">[bar]</$text></caption></image></p>' ) ;
867924
868- describe ( '_getStoredAttributes' , ( ) => {
869- it ( 'should return no values if there are no ranges in selection' , ( ) => {
870- const values = Array . from ( selection . _getStoredAttributes ( ) ) ;
925+ const liveSelection = LiveSelection . createFromSelection ( selection ) ;
871926
872- expect ( values ) . to . deep . equal ( [ ] ) ;
927+ expect ( liveSelection . getAttribute ( 'bold' ) ) . to . equal ( true ) ;
928+ } ) ;
929+
930+ it ( 'stops reading attributes if selection starts with an object' , ( ) => {
931+ setData ( doc , '<p>[<image></image><$text bold="true">bar]</$text></p>' ) ;
932+
933+ const liveSelection = LiveSelection . createFromSelection ( selection ) ;
934+
935+ expect ( liveSelection . hasAttribute ( 'bold' ) ) . to . equal ( false ) ;
936+ } ) ;
873937 } ) ;
874938 } ) ;
875939} ) ;
0 commit comments