@@ -5,7 +5,8 @@ import {CompositeDisposable} from 'event-kit';
55
66import URIPattern , { nonURIMatch } from './uri-pattern' ;
77import RefHolder from '../models/ref-holder' ;
8- import { createItem } from '../helpers' ;
8+ import StubItem from '../atom-items/stub-item' ;
9+ import { createItem , autobind } from '../helpers' ;
910
1011/**
1112 * PaneItem registers an opener with the current Atom workspace as long as this component is mounted. The opener will
@@ -37,17 +38,22 @@ export default class PaneItem extends React.Component {
3738
3839 constructor ( props ) {
3940 super ( props ) ;
41+ autobind ( this , 'opener' ) ;
4042
4143 const uriPattern = new URIPattern ( this . props . uriPattern ) ;
4244 const currentlyOpen = this . props . workspace . getPaneItems ( )
43- . map ( item => {
45+ . reduce ( ( arr , item ) => {
4446 const element = item . getElement ? item . getElement ( ) : null ;
4547 const match = item . getURI ? uriPattern . matches ( item . getURI ( ) ) : nonURIMatch ;
4648 const stub = item . setRealItem ? item : null ;
47- return { element, match, stub} ;
48- } )
49- . filter ( each => each . element && each . match . ok ( ) )
50- . map ( each => new OpenItem ( each . match , each . element , each . stub ) ) ;
49+
50+ if ( element && match . ok ( ) ) {
51+ const openItem = new OpenItem ( match , element , stub ) ;
52+ arr . push ( openItem ) ;
53+ }
54+
55+ return arr ;
56+ } , [ ] ) ;
5157
5258 this . subs = new CompositeDisposable ( ) ;
5359 this . state = { uriPattern, currentlyOpen} ;
@@ -65,9 +71,11 @@ export default class PaneItem extends React.Component {
6571
6672 componentDidMount ( ) {
6773 for ( const openItem of this . state . currentlyOpen ) {
68- this . subs . add ( this . closeListener ( openItem . stubItem , openItem ) ) ;
74+ this . registerCloseListener ( openItem . stubItem , openItem ) ;
6975
70- openItem . hydrateStub ( ) ;
76+ openItem . hydrateStub ( {
77+ copy : ( ) => this . copyOpenItem ( openItem ) ,
78+ } ) ;
7179 }
7280
7381 this . subs . add ( this . props . workspace . addOpener ( this . opener ) ) ;
@@ -76,7 +84,7 @@ export default class PaneItem extends React.Component {
7684 render ( ) {
7785 return this . state . currentlyOpen . map ( item => {
7886 return (
79- < Fragment key = { item . getURI ( ) } >
87+ < Fragment key = { item . getKey ( ) } >
8088 { item . renderPortal ( this . props . children ) }
8189 </ Fragment >
8290 ) ;
@@ -87,7 +95,7 @@ export default class PaneItem extends React.Component {
8795 this . subs . dispose ( ) ;
8896 }
8997
90- opener = uri => {
98+ opener ( uri ) {
9199 const m = this . state . uriPattern . matches ( uri ) ;
92100 if ( ! m . ok ( ) ) {
93101 return undefined ;
@@ -99,31 +107,61 @@ export default class PaneItem extends React.Component {
99107 this . setState ( prevState => ( {
100108 currentlyOpen : [ ...prevState . currentlyOpen , openItem ] ,
101109 } ) , ( ) => {
102- const paneItem = openItem . create ( ) ;
110+ const paneItem = openItem . create ( {
111+ copy : ( ) => this . copyOpenItem ( openItem ) ,
112+ } ) ;
113+ this . registerCloseListener ( paneItem , openItem ) ;
114+ resolve ( paneItem ) ;
115+ } ) ;
116+ } ) ;
117+ }
103118
104- this . subs . add ( this . closeListener ( paneItem , openItem ) ) ;
119+ copyOpenItem ( openItem ) {
120+ const m = this . state . uriPattern . matches ( openItem . getURI ( ) ) ;
121+ if ( ! m . ok ( ) ) {
122+ return null ;
123+ }
105124
106- resolve ( paneItem ) ;
125+ const stub = StubItem . create ( 'generic' , openItem . getStubProps ( ) , openItem . getURI ( ) ) ;
126+
127+ const copiedItem = new OpenItem ( m , stub . getElement ( ) , stub ) ;
128+ this . setState ( prevState => ( {
129+ currentlyOpen : [ ...prevState . currentlyOpen , copiedItem ] ,
130+ } ) , ( ) => {
131+ this . registerCloseListener ( stub , copiedItem ) ;
132+ copiedItem . hydrateStub ( {
133+ copy : ( ) => this . copyOpenItem ( copiedItem ) ,
107134 } ) ;
108135 } ) ;
136+
137+ return stub ;
109138 }
110139
111- closeListener ( paneItem , openItem ) {
112- return this . props . workspace . onDidDestroyPaneItem ( ( { item} ) => {
140+ registerCloseListener ( paneItem , openItem ) {
141+ const sub = this . props . workspace . onDidDestroyPaneItem ( ( { item} ) => {
113142 if ( item === paneItem ) {
143+ sub . dispose ( ) ;
144+ this . subs . remove ( sub ) ;
114145 this . setState ( prevState => ( {
115146 currentlyOpen : prevState . currentlyOpen . filter ( each => each !== openItem ) ,
116147 } ) ) ;
117148 }
118149 } ) ;
150+
151+ this . subs . add ( sub ) ;
119152 }
120153}
121154
122155/**
123156 * A subtree rendered through a portal onto a detached DOM node for use as the root as a PaneItem.
124157 */
125158class OpenItem {
159+ static nextID = 0
160+
126161 constructor ( match , element = null , stub = null ) {
162+ this . id = this . constructor . nextID ;
163+ this . constructor . nextID ++ ;
164+
127165 this . domNode = element || document . createElement ( 'div' ) ;
128166 this . stubItem = stub ;
129167 this . match = match ;
@@ -134,18 +172,34 @@ class OpenItem {
134172 return this . match . getURI ( ) ;
135173 }
136174
137- create ( ) {
175+ create ( extra = { } ) {
138176 const h = this . itemHolder . isEmpty ( ) ? null : this . itemHolder ;
139- return createItem ( this . domNode , h , this . match . getURI ( ) ) ;
177+ return createItem ( this . domNode , h , this . match . getURI ( ) , extra ) ;
140178 }
141179
142- hydrateStub ( ) {
180+ hydrateStub ( extra = { } ) {
143181 if ( this . stubItem ) {
144- this . stubItem . setRealItem ( this . create ( ) ) ;
182+ this . stubItem . setRealItem ( this . create ( extra ) ) ;
145183 this . stubItem = null ;
146184 }
147185 }
148186
187+ getKey ( ) {
188+ return this . id ;
189+ }
190+
191+ getStubProps ( ) {
192+ if ( ! this . itemHolder . isEmpty ( ) ) {
193+ const item = this . itemHolder . get ( ) ;
194+ return {
195+ title : item . getTitle ? item . getTitle ( ) : null ,
196+ iconName : item . getIconName ? item . getIconName ( ) : null ,
197+ } ;
198+ } else {
199+ return { } ;
200+ }
201+ }
202+
149203 renderPortal ( renderProp ) {
150204 return ReactDOM . createPortal (
151205 renderProp ( {
0 commit comments