Skip to content

Commit 0dbfb61

Browse files
committed
Merge pull request JedWatson#27 from JodusNodus/master
Allow interaction with codemirror object from parent.
2 parents 70b6c2f + a547c6a commit 0dbfb61

File tree

5 files changed

+103
-91
lines changed

5 files changed

+103
-91
lines changed

‎dist/react-codemirror.js‎

Lines changed: 92 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
elseif(typeofdefine=="function"&&define.amd)// AMD
6565
returndefine([],mod);
6666
else// Plain browser env
67-
this.CodeMirror=mod();
67+
(this||window).CodeMirror=mod();
6868
})(function(){
6969
"use strict";
7070

@@ -874,7 +874,7 @@
874874
// given line.
875875
functionupdateWidgetHeight(line){
876876
if(line.widgets)for(vari=0;i<line.widgets.length;++i)
877-
line.widgets[i].height=line.widgets[i].node.offsetHeight;
877+
line.widgets[i].height=line.widgets[i].node.parentNode.offsetHeight;
878878
}
879879

880880
// Do a bulk-read of the DOM positions and sizes needed to draw the
@@ -1145,10 +1145,6 @@
11451145
if(!cm.state.focused){cm.display.input.focus();onFocus(cm);}
11461146
}
11471147

1148-
functionisReadOnly(cm){
1149-
returncm.options.readOnly||cm.doc.cantEdit;
1150-
}
1151-
11521148
// This will be set to an array of strings when copying, so that,
11531149
// when pasting, we know what kind of selections the copied text
11541150
// was made out of.
@@ -1203,7 +1199,7 @@
12031199
varpasted=e.clipboardData&&e.clipboardData.getData("text/plain");
12041200
if(pasted){
12051201
e.preventDefault();
1206-
if(!isReadOnly(cm)&&!cm.options.disableInput)
1202+
if(!cm.isReadOnly()&&!cm.options.disableInput)
12071203
runInOp(cm,function(){applyTextInput(cm,pasted,0,null,"paste");});
12081204
returntrue;
12091205
}
@@ -1306,7 +1302,7 @@
13061302
});
13071303

13081304
on(te,"paste",function(e){
1309-
if(handlePaste(e,cm))returntrue;
1305+
if(signalDOMEvent(cm,e)||handlePaste(e,cm))return
13101306

13111307
cm.state.pasteIncoming=true;
13121308
input.fastPoll();
@@ -1340,7 +1336,7 @@
13401336
on(te,"copy",prepareCopyCut);
13411337

13421338
on(display.scroller,"paste",function(e){
1343-
if(eventInWidget(display,e))return;
1339+
if(eventInWidget(display,e)||signalDOMEvent(cm,e))return;
13441340
cm.state.pasteIncoming=true;
13451341
input.focus();
13461342
});
@@ -1474,7 +1470,7 @@
14741470
// in which case reading its value would be expensive.
14751471
if(this.contextMenuPending||!cm.state.focused||
14761472
(hasSelection(input)&&!prevInput&&!this.composing)||
1477-
isReadOnly(cm)||cm.options.disableInput||cm.state.keySeq)
1473+
cm.isReadOnly()||cm.options.disableInput||cm.state.keySeq)
14781474
returnfalse;
14791475

14801476
vartext=input.value;
@@ -1625,7 +1621,9 @@
16251621
vardiv=input.div=display.lineDiv;
16261622
disableBrowserMagic(div);
16271623

1628-
on(div,"paste",function(e){handlePaste(e,cm);})
1624+
on(div,"paste",function(e){
1625+
if(!signalDOMEvent(cm,e))handlePaste(e,cm);
1626+
})
16291627

16301628
on(div,"compositionstart",function(e){
16311629
vardata=e.data;
@@ -1663,7 +1661,7 @@
16631661

16641662
on(div,"input",function(){
16651663
if(input.composing)return;
1666-
if(isReadOnly(cm)||!input.pollContent())
1664+
if(cm.isReadOnly()||!input.pollContent())
16671665
runInOp(input.cm,function(){regChange(cm);});
16681666
});
16691667

@@ -1743,8 +1741,13 @@
17431741
try{varrng=range(start.node,start.offset,end.offset,end.node);}
17441742
catch(e){}// Our model of the DOM might be outdated, in which case the range we try to set can be impossible
17451743
if(rng){
1746-
sel.removeAllRanges();
1747-
sel.addRange(rng);
1744+
if(!gecko&&this.cm.state.focused){
1745+
sel.collapse(start.node,start.offset);
1746+
if(!rng.collapsed)sel.addRange(rng);
1747+
}else{
1748+
sel.removeAllRanges();
1749+
sel.addRange(rng);
1750+
}
17481751
if(old&&sel.anchorNode==null)sel.addRange(old);
17491752
elseif(gecko)this.startGracePeriod();
17501753
}
@@ -1888,7 +1891,7 @@
18881891
this.div.focus();
18891892
},
18901893
applyComposition: function(composing){
1891-
if(isReadOnly(this.cm))
1894+
if(this.cm.isReadOnly())
18921895
operation(this.cm,regChange)(this.cm)
18931896
elseif(composing.data&&composing.data!=composing.startData)
18941897
operation(this.cm,applyTextInput)(this.cm,composing.data,0,composing.sel);
@@ -1900,7 +1903,7 @@
19001903

19011904
onKeyPress: function(e){
19021905
e.preventDefault();
1903-
if(!isReadOnly(this.cm))
1906+
if(!this.cm.isReadOnly())
19041907
operation(this.cm,applyTextInput)(this.cm,String.fromCharCode(e.charCode==null ? e.keyCode : e.charCode),0);
19051908
},
19061909

@@ -2205,15 +2208,16 @@
22052208

22062209
// Give beforeSelectionChange handlers a change to influence a
22072210
// selection update.
2208-
functionfilterSelectionChange(doc,sel){
2211+
functionfilterSelectionChange(doc,sel,options){
22092212
varobj={
22102213
ranges: sel.ranges,
22112214
update: function(ranges){
22122215
this.ranges=[];
22132216
for(vari=0;i<ranges.length;i++)
22142217
this.ranges[i]=newRange(clipPos(doc,ranges[i].anchor),
22152218
clipPos(doc,ranges[i].head));
2216-
}
2219+
},
2220+
origin: options&&options.origin
22172221
};
22182222
signal(doc,"beforeSelectionChange",doc,obj);
22192223
if(doc.cm)signal(doc.cm,"beforeSelectionChange",doc.cm,obj);
@@ -2239,7 +2243,7 @@
22392243

22402244
functionsetSelectionNoUndo(doc,sel,options){
22412245
if(hasHandler(doc,"beforeSelectionChange")||doc.cm&&hasHandler(doc.cm,"beforeSelectionChange"))
2242-
sel=filterSelectionChange(doc,sel);
2246+
sel=filterSelectionChange(doc,sel,options);
22432247

22442248
varbias=options&&options.bias||
22452249
(cmp(sel.primary().head,doc.sel.primary().head)<0 ? -1 : 1);
@@ -2273,8 +2277,9 @@
22732277
varout;
22742278
for(vari=0;i<sel.ranges.length;i++){
22752279
varrange=sel.ranges[i];
2276-
varnewAnchor=skipAtomic(doc,range.anchor,bias,mayClear);
2277-
varnewHead=skipAtomic(doc,range.head,bias,mayClear);
2280+
varold=sel.ranges.length==doc.sel.ranges.length&&doc.sel.ranges[i];
2281+
varnewAnchor=skipAtomic(doc,range.anchor,old&&old.anchor,bias,mayClear);
2282+
varnewHead=skipAtomic(doc,range.head,old&&old.head,bias,mayClear);
22782283
if(out||newAnchor!=range.anchor||newHead!=range.head){
22792284
if(!out)out=sel.ranges.slice(0,i);
22802285
out[i]=newRange(newAnchor,newHead);
@@ -2283,54 +2288,59 @@
22832288
returnout ? normalizeSelection(out,sel.primIndex) : sel;
22842289
}
22852290

2286-
// Ensure a given position is not inside an atomic range.
2287-
functionskipAtomic(doc,pos,bias,mayClear){
2288-
varflipped=false,curPos=pos;
2289-
vardir=bias||1;
2290-
doc.cantEdit=false;
2291-
search: for(;;){
2292-
varline=getLine(doc,curPos.line);
2293-
if(line.markedSpans){
2294-
for(vari=0;i<line.markedSpans.length;++i){
2295-
varsp=line.markedSpans[i],m=sp.marker;
2296-
if((sp.from==null||(m.inclusiveLeft ? sp.from<=curPos.ch : sp.from<curPos.ch))&&
2297-
(sp.to==null||(m.inclusiveRight ? sp.to>=curPos.ch : sp.to>curPos.ch))){
2298-
if(mayClear){
2299-
signal(m,"beforeCursorEnter");
2300-
if(m.explicitlyCleared){
2301-
if(!line.markedSpans)break;
2302-
else{--i;continue;}
2303-
}
2304-
}
2305-
if(!m.atomic)continue;
2306-
varnewPos=m.find(dir<0 ? -1 : 1);
2307-
if(cmp(newPos,curPos)==0){
2308-
newPos.ch+=dir;
2309-
if(newPos.ch<0){
2310-
if(newPos.line>doc.first)newPos=clipPos(doc,Pos(newPos.line-1));
2311-
elsenewPos=null;
2312-
}elseif(newPos.ch>line.text.length){
2313-
if(newPos.line<doc.first+doc.size-1)newPos=Pos(newPos.line+1,0);
2314-
elsenewPos=null;
2315-
}
2316-
if(!newPos){
2317-
if(flipped){
2318-
// Driven in a corner -- no valid cursor position found at all
2319-
// -- try again *with* clearing, if we didn't already
2320-
if(!mayClear)returnskipAtomic(doc,pos,bias,true);
2321-
// Otherwise, turn off editing until further notice, and return the start of the doc
2322-
doc.cantEdit=true;
2323-
returnPos(doc.first,0);
2324-
}
2325-
flipped=true;newPos=pos;dir=-dir;
2326-
}
2327-
}
2328-
curPos=newPos;
2329-
continue search;
2291+
functionskipAtomicInner(doc,pos,oldPos,dir,mayClear){
2292+
varline=getLine(doc,pos.line);
2293+
if(line.markedSpans)for(vari=0;i<line.markedSpans.length;++i){
2294+
varsp=line.markedSpans[i],m=sp.marker;
2295+
if((sp.from==null||(m.inclusiveLeft ? sp.from<=pos.ch : sp.from<pos.ch))&&
2296+
(sp.to==null||(m.inclusiveRight ? sp.to>=pos.ch : sp.to>pos.ch))){
2297+
if(mayClear){
2298+
signal(m,"beforeCursorEnter");
2299+
if(m.explicitlyCleared){
2300+
if(!line.markedSpans)break;
2301+
else{--i;continue;}
23302302
}
23312303
}
2304+
if(!m.atomic)continue;
2305+
2306+
if(oldPos){
2307+
varnear=m.find(dir<0 ? 1 : -1),diff;
2308+
if(dir<0 ? m.inclusiveRight : m.inclusiveLeft)near=movePos(doc,near,-dir,line);
2309+
if(near&&near.line==pos.line&&(diff=cmp(near,oldPos))&&(dir<0 ? diff<0 : diff>0))
2310+
returnskipAtomicInner(doc,near,pos,dir,mayClear);
2311+
}
2312+
2313+
varfar=m.find(dir<0 ? -1 : 1);
2314+
if(dir<0 ? m.inclusiveLeft : m.inclusiveRight)far=movePos(doc,far,dir,line);
2315+
returnfar ? skipAtomicInner(doc,far,pos,dir,mayClear) : null;
23322316
}
2333-
returncurPos;
2317+
}
2318+
returnpos;
2319+
}
2320+
2321+
// Ensure a given position is not inside an atomic range.
2322+
functionskipAtomic(doc,pos,oldPos,bias,mayClear){
2323+
vardir=bias||1;
2324+
varfound=skipAtomicInner(doc,pos,oldPos,dir,mayClear)||
2325+
(!mayClear&&skipAtomicInner(doc,pos,oldPos,dir,true))||
2326+
skipAtomicInner(doc,pos,oldPos,-dir,mayClear)||
2327+
(!mayClear&&skipAtomicInner(doc,pos,oldPos,-dir,true));
2328+
if(!found){
2329+
doc.cantEdit=true;
2330+
returnPos(doc.first,0);
2331+
}
2332+
returnfound;
2333+
}
2334+
2335+
functionmovePos(doc,pos,dir,line){
2336+
if(dir<0&&pos.ch==0){
2337+
if(pos.line>doc.first)returnclipPos(doc,Pos(pos.line-1));
2338+
elsereturnnull;
2339+
}elseif(dir>0&&pos.ch==(line||getLine(doc,pos.line)).text.length){
2340+
if(pos.line<doc.first+doc.size-1)returnPos(pos.line+1,0);
2341+
elsereturnnull;
2342+
}else{
2343+
returnnewPos(pos.line,pos.ch+dir);
23342344
}
23352345
}
23362346

@@ -3659,7 +3669,7 @@
36593669
}
36603670

36613671
varsel=cm.doc.sel,modifier=mac ? e.metaKey : e.ctrlKey,contained;
3662-
if(cm.options.dragDrop&&dragAndDrop&&!isReadOnly(cm)&&
3672+
if(cm.options.dragDrop&&dragAndDrop&&!cm.isReadOnly()&&
36633673
type=="single"&&(contained=sel.contains(start))>-1&&
36643674
(cmp((contained=sel.ranges[contained]).from(),start)<0||start.xRel>0)&&
36653675
(cmp(contained.to(),start)>0||start.xRel<0))
@@ -3883,7 +3893,7 @@
38833893
e_preventDefault(e);
38843894
if(ie)lastDrop=+newDate;
38853895
varpos=posFromMouse(cm,e,true),files=e.dataTransfer.files;
3886-
if(!pos||isReadOnly(cm))return;
3896+
if(!pos||cm.isReadOnly())return;
38873897
// Might be a file drop, in which case we simply extract the text
38883898
// and insert it.
38893899
if(files&&files.length&&window.FileReader&&window.File){
@@ -4122,7 +4132,7 @@
41224132
cm.display.input.ensurePolled();
41234133
varprevShift=cm.display.shift,done=false;
41244134
try{
4125-
if(isReadOnly(cm))cm.state.suppressEdits=true;
4135+
if(cm.isReadOnly())cm.state.suppressEdits=true;
41264136
if(dropShift)cm.display.shift=false;
41274137
done=bound(cm)!=Pass;
41284138
}finally{
@@ -4895,7 +4905,7 @@
48954905
if(dir>0&&!moveOnce(!first))break;
48964906
}
48974907
}
4898-
varresult=skipAtomic(doc,Pos(line,ch),origDir,true);
4908+
varresult=skipAtomic(doc,Pos(line,ch),pos,origDir,true);
48994909
if(!possible)result.hitSide=true;
49004910
returnresult;
49014911
}
@@ -5283,6 +5293,7 @@
52835293
signal(this,"overwriteToggle",this,this.state.overwrite);
52845294
},
52855295
hasFocus: function(){returnthis.display.input.getField()==activeElt();},
5296+
isReadOnly: function(){return!!(this.options.readOnly||this.doc.cantEdit);},
52865297

52875298
scrollTo: methodOp(function(x,y){
52885299
if(x!=null||y!=null)resolveScrollToPos(this);
@@ -6719,7 +6730,7 @@
67196730
parentStyle+="width: "+cm.display.wrapper.clientWidth+"px;";
67206731
removeChildrenAndAdd(cm.display.measure,elt("div",[widget.node],null,parentStyle));
67216732
}
6722-
returnwidget.height=widget.node.offsetHeight;
6733+
returnwidget.height=widget.node.parentNode.offsetHeight;
67236734
}
67246735

67256736
functionaddLineWidget(doc,handle,node,options){
@@ -7129,7 +7140,7 @@
71297140
if(nextChange==pos){// Update current marker set
71307141
spanStyle=spanEndStyle=spanStartStyle=title=css="";
71317142
collapsed=null;nextChange=Infinity;
7132-
varfoundBookmarks=[];
7143+
varfoundBookmarks=[],endStyles
71337144
for(varj=0;j<spans.length;++j){
71347145
varsp=spans[j],m=sp.marker;
71357146
if(m.type=="bookmark"&&sp.from==pos&&m.widgetNode){
@@ -7142,14 +7153,17 @@
71427153
if(m.className)spanStyle+=" "+m.className;
71437154
if(m.css)css=(css ? css+"" : "")+m.css;
71447155
if(m.startStyle&&sp.from==pos)spanStartStyle+=" "+m.startStyle;
7145-
if(m.endStyle&&sp.to==nextChange)spanEndStyle+=" "+m.endStyle;
7156+
if(m.endStyle&&sp.to==nextChange)(endStyles||(endStyles=[])).push(m.endStyle,sp.to)
71467157
if(m.title&&!title)title=m.title;
71477158
if(m.collapsed&&(!collapsed||compareCollapsedMarkers(collapsed.marker,m)<0))
71487159
collapsed=sp;
71497160
}elseif(sp.from>pos&&nextChange>sp.from){
71507161
nextChange=sp.from;
71517162
}
71527163
}
7164+
if(endStyles)for(varj=0;j<endStyles.length;j+=2)
7165+
if(endStyles[j+1]==nextChange)spanEndStyle+=" "+endStyles[j]
7166+
71537167
if(collapsed&&(collapsed.from||0)==pos){
71547168
buildCollapsedSpan(builder,(collapsed.to==null ? len+1 : collapsed.to)-pos,
71557169
collapsed.marker,collapsed.from==null);
@@ -7497,10 +7511,11 @@
74977511
extendSelection(this,clipPos(this,head),other&&clipPos(this,other),options);
74987512
}),
74997513
extendSelections: docMethodOp(function(heads,options){
7500-
extendSelections(this,clipPosArray(this,heads,options));
7514+
extendSelections(this,clipPosArray(this,heads),options);
75017515
}),
75027516
extendSelectionsBy: docMethodOp(function(f,options){
7503-
extendSelections(this,map(this.sel.ranges,f),options);
7517+
varheads=map(this.sel.ranges,f);
7518+
extendSelections(this,clipPosArray(this,heads),options);
75047519
}),
75057520
setSelections: docMethodOp(function(ranges,primary,options){
75067521
if(!ranges.length)return;
@@ -8917,7 +8932,7 @@
89178932

89188933
// THE END
89198934

8920-
CodeMirror.version="5.9.0";
8935+
CodeMirror.version="5.10.0";
89218936

89228937
returnCodeMirror;
89238938
});
@@ -8929,7 +8944,6 @@
89298944
varCM=require('codemirror');
89308945
varReact=(typeofwindow!=="undefined" ? window['React'] : typeofglobal!=="undefined" ? global['React'] : null);
89318946
varclassName=require('classnames');
8932-
89338947
varCodeMirror=React.createClass({
89348948
displayName: 'CodeMirror',
89358949

@@ -8947,7 +8961,6 @@ var CodeMirror = React.createClass({
89478961
isFocused: false
89488962
};
89498963
},
8950-
89518964
componentDidMount: functioncomponentDidMount(){
89528965
vartextareaNode=this.refs.textarea;
89538966
this.codeMirror=CM.fromTextArea(textareaNode,this.props.options);
@@ -8956,8 +8969,8 @@ var CodeMirror = React.createClass({
89568969
this.codeMirror.on('blur',this.focusChanged.bind(this,false));
89578970
this._currentCodemirrorValue=this.props.defaultValue||this.props.value||'';
89588971
this.codeMirror.setValue(this._currentCodemirrorValue);
8972+
this.props.interact(this.codeMirror);
89598973
},
8960-
89618974
componentWillUnmount: functioncomponentWillUnmount(){
89628975
// todo: is there a lighter-weight way to remove the cm instance?
89638976
if(this.codeMirror){

‎dist/react-codemirror.min.js‎

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
(0)