UISourceCode.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. export default class UISourceCode extends Common.Object{constructor(project,url,contentType){super();this._project=project;this._url=url;const parsedURL=url.asParsedURL();if(parsedURL){this._origin=parsedURL.securityOrigin();this._parentURL=this._origin+parsedURL.folderPathComponents;this._name=parsedURL.lastPathComponent;if(parsedURL.queryParams){this._name+='?'+parsedURL.queryParams;}}else{this._origin='';this._parentURL='';this._name=url;}
  2. this._contentType=contentType;this._requestContentPromise=null;this._decorations=null;this._hasCommits=false;this._messages=null;this._contentLoaded=false;this._content=null;this._forceLoadOnCheckContent=false;this._checkingContent=false;this._lastAcceptedContent=null;this._workingCopy=null;this._workingCopyGetter=null;}
  3. requestMetadata(){return this._project.requestMetadata(this);}
  4. name(){return this._name;}
  5. mimeType(){return this._project.mimeType(this);}
  6. url(){return this._url;}
  7. parentURL(){return this._parentURL;}
  8. origin(){return this._origin;}
  9. fullDisplayName(){return this._project.fullDisplayName(this);}
  10. displayName(skipTrim){if(!this._name){return Common.UIString('(index)');}
  11. let name=this._name;try{if(this.project().type()===Workspace.projectTypes.FileSystem){name=unescape(name);}else{name=decodeURI(name);}}catch(e){}
  12. return skipTrim?name:name.trimEndWithMaxLength(100);}
  13. canRename(){return this._project.canRename();}
  14. rename(newName){let fulfill;const promise=new Promise(x=>fulfill=x);this._project.rename(this,newName,innerCallback.bind(this));return promise;function innerCallback(success,newName,newURL,newContentType){if(success){this._updateName((newName),(newURL),(newContentType));}
  15. fulfill(success);}}
  16. remove(){this._project.deleteFile(this);}
  17. _updateName(name,url,contentType){const oldURL=this._url;this._url=this._url.substring(0,this._url.length-this._name.length)+name;this._name=name;if(url){this._url=url;}
  18. if(contentType){this._contentType=contentType;}
  19. this.dispatchEventToListeners(Events.TitleChanged,this);this.project().workspace().dispatchEventToListeners(Workspace.Workspace.Events.UISourceCodeRenamed,{oldURL:oldURL,uiSourceCode:this});}
  20. contentURL(){return this.url();}
  21. contentType(){return this._contentType;}
  22. async contentEncoded(){await this.requestContent();return this._contentEncoded||false;}
  23. project(){return this._project;}
  24. requestContent(){if(this._requestContentPromise){return this._requestContentPromise;}
  25. if(this._contentLoaded){return Promise.resolve((this._content));}
  26. this._requestContentPromise=this._requestContentImpl();return this._requestContentPromise;}
  27. async _requestContentImpl(){try{const content=await this._project.requestFileContent(this);if(!this._contentLoaded){this._contentLoaded=true;this._content=content;this._contentEncoded=content.isEncoded;}}catch(err){this._contentLoaded=true;this._content={error:err?String(err):'',isEncoded:false};}
  28. return(this._content);}
  29. async checkContentUpdated(){if(!this._contentLoaded&&!this._forceLoadOnCheckContent){return;}
  30. if(!this._project.canSetFileContent()||this._checkingContent){return;}
  31. this._checkingContent=true;const updatedContent=await this._project.requestFileContent(this);this._checkingContent=false;if(updatedContent.content===null){const workingCopy=this.workingCopy();this._contentCommitted('',false);this.setWorkingCopy(workingCopy);return;}
  32. if(this._lastAcceptedContent===updatedContent.content){return;}
  33. if(this._content&&this._content.content===updatedContent.content){this._lastAcceptedContent=null;return;}
  34. if(!this.isDirty()||this._workingCopy===updatedContent.content){this._contentCommitted((updatedContent.content),false);return;}
  35. await Common.Revealer.reveal(this);await new Promise(resolve=>setTimeout(resolve,0));const shouldUpdate=window.confirm(ls`This file was changed externally. Would you like to reload it?`);if(shouldUpdate){this._contentCommitted((updatedContent.content),false);}else{this._lastAcceptedContent=updatedContent.content;}}
  36. forceLoadOnCheckContent(){this._forceLoadOnCheckContent=true;}
  37. _commitContent(content){if(this._project.canSetFileContent()){this._project.setFileContent(this,content,false);}
  38. this._contentCommitted(content,true);}
  39. _contentCommitted(content,committedByUser){this._lastAcceptedContent=null;this._content={content,isEncoded:false};this._contentLoaded=true;this._requestContentPromise=null;this._hasCommits=true;this._innerResetWorkingCopy();const data={uiSourceCode:this,content,encoded:this._contentEncoded};this.dispatchEventToListeners(Events.WorkingCopyCommitted,data);this._project.workspace().dispatchEventToListeners(Workspace.Workspace.Events.WorkingCopyCommitted,data);if(committedByUser){this._project.workspace().dispatchEventToListeners(Workspace.Workspace.Events.WorkingCopyCommittedByUser,data);}}
  40. addRevision(content){this._commitContent(content);}
  41. hasCommits(){return this._hasCommits;}
  42. workingCopy(){if(this._workingCopyGetter){this._workingCopy=this._workingCopyGetter();this._workingCopyGetter=null;}
  43. if(this.isDirty()){return(this._workingCopy);}
  44. return(this._content&&this._content.content)||'';}
  45. resetWorkingCopy(){this._innerResetWorkingCopy();this._workingCopyChanged();}
  46. _innerResetWorkingCopy(){this._workingCopy=null;this._workingCopyGetter=null;}
  47. setWorkingCopy(newWorkingCopy){this._workingCopy=newWorkingCopy;this._workingCopyGetter=null;this._workingCopyChanged();}
  48. setContent(content,isBase64){this._contentEncoded=isBase64;if(this._project.canSetFileContent()){this._project.setFileContent(this,content,isBase64);}
  49. this._contentCommitted(content,true);}
  50. setWorkingCopyGetter(workingCopyGetter){this._workingCopyGetter=workingCopyGetter;this._workingCopyChanged();}
  51. _workingCopyChanged(){this._removeAllMessages();this.dispatchEventToListeners(Events.WorkingCopyChanged,this);this._project.workspace().dispatchEventToListeners(Workspace.Workspace.Events.WorkingCopyChanged,{uiSourceCode:this});}
  52. removeWorkingCopyGetter(){if(!this._workingCopyGetter){return;}
  53. this._workingCopy=this._workingCopyGetter();this._workingCopyGetter=null;}
  54. commitWorkingCopy(){if(this.isDirty()){this._commitContent(this.workingCopy());}}
  55. isDirty(){return this._workingCopy!==null||this._workingCopyGetter!==null;}
  56. extension(){return Common.ParsedURL.extractExtension(this._name);}
  57. content(){return(this._content&&this._content.content)||'';}
  58. loadError(){return(this._content&&this._content.error);}
  59. searchInContent(query,caseSensitive,isRegex){const content=this.content();if(!content){return this._project.searchInFileContent(this,query,caseSensitive,isRegex);}
  60. return Promise.resolve(Common.ContentProvider.performSearchInContent(content,query,caseSensitive,isRegex));}
  61. contentLoaded(){return this._contentLoaded;}
  62. uiLocation(lineNumber,columnNumber){if(typeof columnNumber==='undefined'){columnNumber=0;}
  63. return new UILocation(this,lineNumber,columnNumber);}
  64. messages(){return this._messages?new Set(this._messages):new Set();}
  65. addLineMessage(level,text,lineNumber,columnNumber){return this.addMessage(level,text,new TextUtils.TextRange(lineNumber,columnNumber||0,lineNumber,columnNumber||0));}
  66. addMessage(level,text,range){const message=new Message(this,level,text,range);if(!this._messages){this._messages=new Set();}
  67. this._messages.add(message);this.dispatchEventToListeners(Events.MessageAdded,message);return message;}
  68. removeMessage(message){if(this._messages&&this._messages.delete(message)){this.dispatchEventToListeners(Events.MessageRemoved,message);}}
  69. _removeAllMessages(){if(!this._messages){return;}
  70. for(const message of this._messages){this.dispatchEventToListeners(Events.MessageRemoved,message);}
  71. this._messages=null;}
  72. addLineDecoration(lineNumber,type,data){this.addDecoration(TextUtils.TextRange.createFromLocation(lineNumber,0),type,data);}
  73. addDecoration(range,type,data){const marker=new LineMarker(range,type,data);if(!this._decorations){this._decorations=new Platform.Multimap();}
  74. this._decorations.set(type,marker);this.dispatchEventToListeners(Events.LineDecorationAdded,marker);}
  75. removeDecorationsForType(type){if(!this._decorations){return;}
  76. const markers=this._decorations.get(type);this._decorations.deleteAll(type);markers.forEach(marker=>{this.dispatchEventToListeners(Events.LineDecorationRemoved,marker);});}
  77. allDecorations(){return this._decorations?this._decorations.valuesArray():[];}
  78. removeAllDecorations(){if(!this._decorations){return;}
  79. const decorationList=this._decorations.valuesArray();this._decorations.clear();decorationList.forEach(marker=>this.dispatchEventToListeners(Events.LineDecorationRemoved,marker));}
  80. decorationsForType(type){return this._decorations?this._decorations.get(type):null;}}
  81. export const Events={WorkingCopyChanged:Symbol('WorkingCopyChanged'),WorkingCopyCommitted:Symbol('WorkingCopyCommitted'),TitleChanged:Symbol('TitleChanged'),MessageAdded:Symbol('MessageAdded'),MessageRemoved:Symbol('MessageRemoved'),LineDecorationAdded:Symbol('LineDecorationAdded'),LineDecorationRemoved:Symbol('LineDecorationRemoved')};export class UILocation{constructor(uiSourceCode,lineNumber,columnNumber){this.uiSourceCode=uiSourceCode;this.lineNumber=lineNumber;this.columnNumber=columnNumber;}
  82. linkText(skipTrim){let linkText=this.uiSourceCode.displayName(skipTrim);if(typeof this.lineNumber==='number'){linkText+=':'+(this.lineNumber+1);}
  83. return linkText;}
  84. id(){return this.uiSourceCode.project().id()+':'+this.uiSourceCode.url()+':'+this.lineNumber+':'+
  85. this.columnNumber;}
  86. toUIString(){return this.uiSourceCode.url()+':'+(this.lineNumber+1);}
  87. static comparator(location1,location2){return location1.compareTo(location2);}
  88. compareTo(other){if(this.uiSourceCode.url()!==other.uiSourceCode.url()){return this.uiSourceCode.url()>other.uiSourceCode.url()?1:-1;}
  89. if(this.lineNumber!==other.lineNumber){return this.lineNumber-other.lineNumber;}
  90. return this.columnNumber-other.columnNumber;}}
  91. export class Message{constructor(uiSourceCode,level,text,range){this._uiSourceCode=uiSourceCode;this._level=level;this._text=text;this._range=range;}
  92. uiSourceCode(){return this._uiSourceCode;}
  93. level(){return this._level;}
  94. text(){return this._text;}
  95. range(){return this._range;}
  96. lineNumber(){return this._range.startLine;}
  97. columnNumber(){return this._range.startColumn;}
  98. isEqual(another){return this._uiSourceCode===another._uiSourceCode&&this.text()===another.text()&&this.level()===another.level()&&this.range().equal(another.range());}
  99. remove(){this._uiSourceCode.removeMessage(this);}}
  100. Message.Level={Error:'Error',Warning:'Warning'};export class LineMarker{constructor(range,type,data){this._range=range;this._type=type;this._data=data;}
  101. range(){return this._range;}
  102. type(){return this._type;}
  103. data(){return this._data;}}
  104. export class UISourceCodeMetadata{constructor(modificationTime,contentSize){this.modificationTime=modificationTime;this.contentSize=contentSize;}}
  105. self.Workspace=self.Workspace||{};Workspace=Workspace||{};Workspace.UISourceCode=UISourceCode;Workspace.UISourceCode.Events=Events;Workspace.UISourceCode.Message=Message;Workspace.UISourceCode.LineMarker=LineMarker;Workspace.UILocation=UILocation;Workspace.UISourceCodeMetadata=UISourceCodeMetadata;