From 64d19a051aeb7d22a0d5758b0d63c247291ecfeb Mon Sep 17 00:00:00 2001 From: caishi <1149225589@qq.com> Date: Thu, 16 Mar 2023 17:04:52 +0800 Subject: [PATCH] =?UTF-8?q?markdown=20#=E5=BC=95=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/forge/Issues/Component/newPanel.jsx | 1 + .../tpm/challengesnew/css/newquestion.css | 36 +++++++- .../tpm/challengesnew/tpm-md-editor.js | 83 ++++++++++++++++--- 3 files changed, 107 insertions(+), 13 deletions(-) diff --git a/src/forge/Issues/Component/newPanel.jsx b/src/forge/Issues/Component/newPanel.jsx index 0094be5a0..c34c4f64d 100644 --- a/src/forge/Issues/Component/newPanel.jsx +++ b/src/forge/Issues/Component/newPanel.jsx @@ -86,6 +86,7 @@ function NewPanel(props,ref){ onChange={onContentChange} className="mt20" isCanAtme = {true} + isQuoteIssue={true} owner = {owner} projectsId = {projectsId} changeAtWhoLoginList = {changeAtWhoLoginList} diff --git a/src/modules/tpm/challengesnew/css/newquestion.css b/src/modules/tpm/challengesnew/css/newquestion.css index eb1a67eb1..81c4dcdc8 100644 --- a/src/modules/tpm/challengesnew/css/newquestion.css +++ b/src/modules/tpm/challengesnew/css/newquestion.css @@ -5,9 +5,41 @@ color:#5091FF !important; border-color: #5091FF !important; } - +.quoteDiv{ + width: 240px!important; + max-height: 257px!important; +} +.quoteDiv > li{ + display: flex; + align-items: center; + height: 32px; + padding:0px 10px; + border-bottom: 1px solid rgba(212, 212, 212, 0.5); +} +.quoteDiv > li.active{ + background-color: #F3F4F6; +} +.quoteDiv > li:last-child{ + border-bottom: none; +} +.issueIndex{ + background-color: rgba(213, 220, 246, 0.36); + border-radius: 4px; + height: 19px; + line-height: 19px; + color: #666666; + text-align: center; + float: left; + padding: 0px 2px; + cursor: pointer; + font-size: 12px; + margin-right: 7px; +} +.issueName{ + flex:1 +} /*md编辑器中输入@弹出可选人列表样式*/ -.at_who_list{ +.at_who_list,.quoteDiv{ position: absolute; z-index: 100; width: 180px; diff --git a/src/modules/tpm/challengesnew/tpm-md-editor.js b/src/modules/tpm/challengesnew/tpm-md-editor.js index 61747f507..f5d703cff 100644 --- a/src/modules/tpm/challengesnew/tpm-md-editor.js +++ b/src/modules/tpm/challengesnew/tpm-md-editor.js @@ -74,7 +74,7 @@ function md_elocalStorage(editor, mdu, id) { return tid } -export default ({ mdID, onChange, onCMBeforeChange, onCMBlur, error = false, className = '', noStorage = false, imageExpand = true, placeholder = '', width = '100%', height = 400, initValue = '', emoji, watch, showNullButton = false, showResizeBar = false, startInit = true , forMember = true , isCanAtme = false , changeAtWhoLoginList, owner, projectsId }) => { +export default ({ mdID, onChange, onCMBeforeChange, onCMBlur, error = false, className = '', noStorage = false, imageExpand = true, placeholder = '', width = '100%', height = 400, initValue = '', emoji, watch, showNullButton = false, showResizeBar = false, startInit = true , forMember = true , isCanAtme = false , isQuoteIssue = false , changeAtWhoLoginList, owner, projectsId }) => { const editorEl = useRef(); const resizeBarEl = useRef(); @@ -91,6 +91,10 @@ export default ({ mdID, onChange, onCMBeforeChange, onCMBlur, error = false, cla const editorBodyId = `mdEditors_${mdID}`; const tipId = `e_tips_mdEditor_${mdID}`; + // quote相关 + const [issues, setIssues ] = useState([]); + const [ quoteVisible , setQuoteVisible ] = useState(false); + useEffect(()=>{ //请求members接口获取全部可@列表 isCanAtme && axios.get(`/${owner}/${projectsId}/members.json`).then(response=>{ @@ -104,8 +108,55 @@ export default ({ mdID, onChange, onCMBeforeChange, onCMBlur, error = false, cla atWhoVisibleRef.current = false; setAtWhoVisible(false); }) + + isQuoteIssue && getIssueList(); },[]) + // 请求issues接口获取全部可quote的issue列表 + function getIssueList(keywords){ + axios.get(`/v1/${owner}/${projectsId}/issues`,{params:{ + only_name:true,keywords + }}).then(result=>{ + if(result && result.data.total_count!== 0){ + setIssues(result.data.issues); + } + }) + } + // # 引用的弹框div + const QuoteDiv = ( +
+ { + issues && issues.length>0 && issues.map((i,k)=>{ + return( +
  • selectQuoteIssue(i)} onMouseOver={()=>onMouseOverQuote(k)}> + #{i.project_issues_index} + {i.subject} +
  • + ) + }) + } +
    + ) + // 点击选择要引用的issue + function selectQuoteIssue(i){ + const cm = editorInstance.cm; + //获取鼠标所在行的行数和ch + const cursor = cm.doc.getCursor(); + const line = cursor.line;//行 + const ch = cursor.ch;//列 + const startIndex = cm.getRange({line,ch:0},{line,ch}).lastIndexOf("@"); + //替换内容 + cm.replaceRange(`[#${i.project_issues_index}](/${owner}/${projectsId}/issues/${i.project_issues_index}) `,{line,ch:startIndex},{line,ch}); + //鼠标聚焦 + cm.focus(); + setQuoteVisible(false); + // 保存引用的issue + } + function onMouseOverQuote(key){ + document.getElementsByClassName("quote active")[0] && (document.getElementsByClassName("quote active")[0].className="quote"); + document.getElementsByClassName("quote")[key] && (document.getElementsByClassName("quote")[key].className="quote active"); + } + function onLayout() { let ro; if (editorEl.current) { @@ -153,21 +204,20 @@ export default ({ mdID, onChange, onCMBeforeChange, onCMBlur, error = false, cla } //markdown编辑器中输入的键盘监听事件 - function mdKeyDown(e){ + function mdKeyDown(e){ //获取光标位置 + const cssStyle = document.getElementsByClassName("CodeMirror cm-s-default CodeMirror-wrap")[0].firstChild.style; + //设置弹框位置 + const newTop = 62 + const newLeft = 20; if (e.shiftKey && e.code === "Digit2") { // 输入@键后在对应的位置显示可选的项目成员 atWhoVisibleRef.current = true; setAtWhoVisible(true); - //获取光标位置 - const cssStyle = document.getElementsByClassName("CodeMirror cm-s-default CodeMirror-wrap")[0].firstChild.style; - //设置弹框位置 - const newTop = 62 - const newLeft = 20; document.getElementById("at_who_list").style.top = parseInt(cssStyle.getPropertyValue("top").replace("px","")) + newTop +"px"; document.getElementById("at_who_list").style.left = parseInt(cssStyle.getPropertyValue("left").replace("px",""))+newLeft+"px"; - } + } //处理本来@了某人 -> 删掉 -> 撤回 的情况 - if(e.ctrlKey && e.code === "KeyZ" && allUsers.length != 0){ + if(e.ctrlKey && e.code === "KeyZ" && allUsers.length !== 0){ const codemirror = editorInstance.cm; let value = codemirror.getValue(); //处理初始内容就自带@谁的情况 @@ -194,6 +244,16 @@ export default ({ mdID, onChange, onCMBeforeChange, onCMBlur, error = false, cla } }) } + if(e.shiftKey && e.code === "Digit3"){ + // 输入#键后在对应的位置显示可选的项目issue + setQuoteVisible(true); + document.getElementById("quoteDiv").style.top = parseInt(cssStyle.getPropertyValue("top").replace("px","")) + newTop +"px"; + document.getElementById("quoteDiv").style.left = parseInt(cssStyle.getPropertyValue("left").replace("px",""))+newLeft+"px"; + } + if(e.code==="Space"){ + // 输入# 后又输入空格:隐藏issue列表 + setQuoteVisible(false); + } } useEffect(()=>{ @@ -374,10 +434,10 @@ export default ({ mdID, onChange, onCMBeforeChange, onCMBlur, error = false, cla } //isCanAtme:只有issue和合并请求以及评论部分可以@他人操作 //绑定@事件 - isCanAtme && editorInstance.cm.on("focus", () => { + (isCanAtme || isQuoteIssue) && editorInstance.cm.on("focus", () => { document.addEventListener("keydown", mdKeyDown); }); - isCanAtme && editorInstance.cm.on("blur", () => { + (isCanAtme || isQuoteIssue) && editorInstance.cm.on("blur", () => { document.removeEventListener("keydown",mdKeyDown); }); editorInstance.cm.on("change", (cm) => { @@ -565,6 +625,7 @@ export default ({ mdID, onChange, onCMBeforeChange, onCMBlur, error = false, cla return ( {atWhoVisible && atWhoList} + {quoteVisible && QuoteDiv }