diff --git a/app/src/main/assets/content.js b/app/src/main/assets/content.js index 850ea69287..9e77cb3fbe 100644 --- a/app/src/main/assets/content.js +++ b/app/src/main/assets/content.js @@ -27,9 +27,22 @@ function getStyle(dom, name) { return window.getComputedStyle(dom)[name] } +// 跳转方法 +function customLinkgo(self) { + let datas = self.dataset.datas +// console.log(datas) + window.OnLinkClickListener.onClick(datas); +} + +var typeClassList = [ + "community_article-container", + "answer-container", + "game-container" +] + $(document).ready(function() { setupWhenContentEditable(); - + // 触发删除 document.addEventListener('keydown', e => { let event = e || window.event @@ -37,6 +50,8 @@ $(document).ready(function() { let s = document.getSelection() let r = s.getRangeAt(0) + let customDom = s.focusNode.previousElementSibling + if (r.startOffset === r.endOffset && r.endOffset === 0) { let preDOM = s.focusNode.parentNode.previousElementSibling @@ -46,6 +61,12 @@ $(document).ready(function() { preDOM.parentElement.removeChild(preDOM) } } + // 删除整个自定义链接 + if (r.startOffset === r.endOffset && r.endOffset <= 1 && + customDom && customDom instanceof Element && typeClassList.indexOf(customDom.className) > -1) { + + customDom.parentElement.removeChild(customDom) + } } }) }); \ No newline at end of file diff --git a/app/src/main/assets/editor.html b/app/src/main/assets/editor.html index ea5ba649ec..12d6a16691 100644 --- a/app/src/main/assets/editor.html +++ b/app/src/main/assets/editor.html @@ -1,6 +1,82 @@ + diff --git a/app/src/main/assets/editor_insert_answer_icon.png b/app/src/main/assets/editor_insert_answer_icon.png new file mode 100644 index 0000000000..69f8000d24 Binary files /dev/null and b/app/src/main/assets/editor_insert_answer_icon.png differ diff --git a/app/src/main/assets/editor_insert_article_icon.png b/app/src/main/assets/editor_insert_article_icon.png new file mode 100644 index 0000000000..4d3b8eb86f Binary files /dev/null and b/app/src/main/assets/editor_insert_article_icon.png differ diff --git a/app/src/main/assets/rich_editor.js b/app/src/main/assets/rich_editor.js index bf6b91ba31..10a8cd6c06 100644 --- a/app/src/main/assets/rich_editor.js +++ b/app/src/main/assets/rich_editor.js @@ -16,15 +16,6 @@ // alert("") -// link block -// var html = "
\n" + -// "In HTML and XHTML, the blockquote element defines\n" + -// "
\n" + -// "In HTML and XHTML, the blockquote element defines\n" + -// "
" + -// "
\n" -// document.execCommand('insertHTML', false, html); - var RE = {}; RE.currentSelection = { @@ -433,6 +424,61 @@ RE.removeFormat = function() { document.execCommand('removeFormat', false, null); } +RE.insertCustomStyleLink = function(type, aUrl, title, content, imgurl, obj) { + + RE.restorerange(); + let html = ` 
+ +
+
+ +
+
+

${title}

+

${content}

+
+
+
+
 ` + var tags = ``, gameHtml = `` + let array = "" + try { + array = JSON.parse(content) + } catch(error) { + } + if (array instanceof Array) { + array.forEach(item => { + tags += `` + }) + + gameHtml = ` 
+ +
+
+ +
+
+

${title}

+

${tags}

+
+
+
 ` + } + + switch(type) { + case 'answer': + document.execCommand("insertHTML",false, html); + break + case 'community_article': + document.execCommand("insertHTML",false, html); + break + case 'game': + document.execCommand("insertHTML",false, gameHtml); + break + } + RE.callback(); +} + // Event Listeners RE.editor.addEventListener("input", RE.callback); RE.editor.addEventListener("keyup", function(e) { @@ -445,8 +491,26 @@ RE.editor.addEventListener("keyup", function(e) { RE.editor.addEventListener("click", function(e) { RE.enabledEditingItems RE.sendElementNameToNative() + let s = document.getSelection() + let isNeedRemoveR = RE.recursion(e.target) + if (isNeedRemoveR && s.rangeCount) { + s.removeAllRanges() + } }); +RE.recursion = function(dom) { + let parenDom = dom.parentElement + if (parenDom && parenDom instanceof Element && + typeClassList.indexOf(parenDom.className) > -1) { + return parenDom + } else if(parenDom && parenDom instanceof Element && + typeClassList.indexOf(parenDom.className) === -1 && parenDom.nodeName !== 'BODY') { + return RE.recursion(parenDom) + } else { + return null + } +} + // 返回组件标签 多个标签以"空格"划分 RE.sendElementNameToNative = function() { if (window.getSelection) { diff --git a/app/src/main/java/com/gh/base/BaseRichEditorActivity.kt b/app/src/main/java/com/gh/base/BaseRichEditorActivity.kt index 9e3fffe148..ac5cb38f24 100644 --- a/app/src/main/java/com/gh/base/BaseRichEditorActivity.kt +++ b/app/src/main/java/com/gh/base/BaseRichEditorActivity.kt @@ -1,8 +1,10 @@ package com.gh.base import android.annotation.SuppressLint +import android.app.Activity import android.content.ClipboardManager import android.content.Context +import android.content.Intent import android.os.Bundle import android.text.TextUtils import android.view.View @@ -10,9 +12,12 @@ import android.webkit.JavascriptInterface import butterknife.OnClick import com.gh.common.view.RichEditor import com.gh.gamecenter.R +import com.gh.gamecenter.entity.GameEntity import com.gh.gamecenter.qa.editor.GameActivity import com.gh.gamecenter.qa.editor.InsertAnswerWrapperActivity import com.gh.gamecenter.qa.editor.InsertArticleWrapperActivity +import com.gh.gamecenter.qa.entity.AnswerEntity +import com.gh.gamecenter.qa.entity.ArticleEntity import com.halo.assistant.HaloApp import com.lightgame.utils.Utils import com.lightgame.view.CheckableImageView @@ -39,12 +44,29 @@ abstract class BaseRichEditorActivity : BaseActivity() { private val mEditorInsertDetail by bindView(R.id.editor_insert_detail) + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (resultCode != Activity.RESULT_OK) return + when (requestCode) { + INSERT_ANSWER_CODE -> { + mRichEditor.insertAnswerLink(data?.getParcelableExtra(AnswerEntity::class.java.simpleName)) + } + INSERT_ARTICLE_CODE -> { + mRichEditor.insertCommunityArticleLink(data?.getParcelableExtra(ArticleEntity::class.java.simpleName)) + } + INSERT_GAME_CODE -> { + mRichEditor.insertGameLink(data?.getParcelableExtra(GameEntity::class.java.simpleName)) + } + } + } + @SuppressLint("AddJavascriptInterface") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 防止个别手机在Js里无法获取粘贴内容 mRichEditor.addJavascriptInterface(OnPasteListener(), "onPasteListener") mRichEditor.addJavascriptInterface(OnCursorChangeListener(), "OnCursorChangeListener") + mRichEditor.addJavascriptInterface(OnLinkClickListener(), "OnLinkClickListener") } @OnClick(R.id.editor_image, R.id.editor_font, R.id.editor_link, R.id.editor_paragraph, @@ -135,13 +157,13 @@ abstract class BaseRichEditorActivity : BaseActivity() { mEditorParagraphQuote.isChecked = !mEditorParagraphQuote.isChecked } R.id.editor_link_answer -> { - startActivity(InsertAnswerWrapperActivity.getIntent(this)) + startActivityForResult(InsertAnswerWrapperActivity.getIntent(this), INSERT_ANSWER_CODE) } R.id.editor_link_article -> { - startActivity(InsertArticleWrapperActivity.getIntent(this)) + startActivityForResult(InsertArticleWrapperActivity.getIntent(this), INSERT_ARTICLE_CODE) } R.id.editor_link_game -> { - startActivity(GameActivity.getIntent(this)) + startActivityForResult(GameActivity.getIntent(this), INSERT_GAME_CODE) } } } @@ -181,6 +203,12 @@ abstract class BaseRichEditorActivity : BaseActivity() { } } + private inner class OnLinkClickListener { + @JavascriptInterface + fun onClick(content: String) { + } + } + companion object { const val ELEMENT_NAME_BOLD = " b " const val ELEMENT_NAME_ITALIC = " i " @@ -190,5 +218,8 @@ abstract class BaseRichEditorActivity : BaseActivity() { const val ELEMENT_PARAGRAPH_H3 = " h3 " const val ELEMENT_PARAGRAPH_H4 = " h4 " const val ELEMENT_PARAGRAPH_QUOTE = " blockquote " + const val INSERT_ANSWER_CODE = 411 + const val INSERT_ARTICLE_CODE = 412 + const val INSERT_GAME_CODE = 413 } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/view/RichEditor.java b/app/src/main/java/com/gh/common/view/RichEditor.java index ca40913ed3..f2eec8bb3f 100644 --- a/app/src/main/java/com/gh/common/view/RichEditor.java +++ b/app/src/main/java/com/gh/common/view/RichEditor.java @@ -15,10 +15,14 @@ import android.webkit.WebViewClient; import com.gh.common.util.AskUtils; import com.gh.common.util.DisplayUtils; +import com.gh.common.util.GsonUtils; import com.gh.common.util.ImageUtils; import com.gh.common.util.NetworkUtils; import com.gh.common.util.RichEditorUtils; import com.gh.gamecenter.BuildConfig; +import com.gh.gamecenter.entity.GameEntity; +import com.gh.gamecenter.qa.entity.AnswerEntity; +import com.gh.gamecenter.qa.entity.ArticleEntity; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; @@ -241,6 +245,39 @@ public class RichEditor extends WebView { return TextUtils.isEmpty(mContents) ? "" : mContents; } + public void insertAnswerLink(AnswerEntity entity) { + if (entity == null) return; + exec("javascript:RE.insertCustomStyleLink('" + + "answer" + "', '" + + "javascript:void(0);" + "', '" + + entity.getQuestions().getTitle() + "', '" + + entity.getBrief() + "', '" + + "file:///android_asset/editor_insert_answer_icon.png" + "', '" + + entity.getId() + "');"); + } + + public void insertCommunityArticleLink(ArticleEntity entity) { + if (entity == null) return; + exec("javascript:RE.insertCustomStyleLink('" + + "community_article" + "', '" + + "javascript:void(0);" + "', '" + + entity.getTitle() + "', '" + + entity.getBrief() + "', '" + + "file:///android_asset/editor_insert_article_icon.png" + "', '" + + entity.getId() + "');"); + } + + public void insertGameLink(GameEntity entity) { + if (entity == null) return; + exec("javascript:RE.insertCustomStyleLink('" + + "game" + "', '" + + "javascript:void(0);" + "', '" + + entity.getName() + "', '" + + GsonUtils.toJson(entity.getTag()) + "', '" + + entity.getIcon() + "', '" + + entity.getId() + "');"); + } + public void setEditorFontColor(int color) { String hex = convertHexColorString(color); exec("javascript:RE.setBaseTextColor('" + hex + "');"); diff --git a/app/src/main/java/com/gh/gamecenter/qa/editor/AnswerAdapter.kt b/app/src/main/java/com/gh/gamecenter/qa/editor/AnswerAdapter.kt index 80a86f7853..34c79df183 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/editor/AnswerAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/editor/AnswerAdapter.kt @@ -1,6 +1,8 @@ package com.gh.gamecenter.qa.editor +import android.app.Activity import android.content.Context +import android.content.Intent import android.support.v7.widget.RecyclerView import android.view.View import android.view.ViewGroup @@ -34,7 +36,19 @@ class AnswerAdapter(context: Context, private val mEntrance: String?) : ListAdap override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { when (getItemViewType(position)) { - ItemViewType.ITEM_BODY -> (holder as AnswerViewHolder).initCollectionAnswerViewHolder(mEntityList[position], mEntrance) + ItemViewType.ITEM_BODY -> { + val answerViewHolder = holder as AnswerViewHolder + val entity = mEntityList[position] + answerViewHolder.initCollectionAnswerViewHolder(entity, mEntrance) + answerViewHolder.itemView.setOnClickListener { + if (mContext is Activity) { + val intent = Intent() + intent.putExtra(AnswerEntity::class.java.simpleName, entity) + (mContext as Activity).setResult(Activity.RESULT_OK, intent) + (mContext as Activity).finish() + } + } + } ItemViewType.ITEM_FOOTER -> { val footerViewHolder = holder as FooterViewHolder footerViewHolder.initItemPadding() diff --git a/app/src/main/java/com/gh/gamecenter/qa/editor/ArticleAdapter.kt b/app/src/main/java/com/gh/gamecenter/qa/editor/ArticleAdapter.kt index 6c0508b519..0bfcb1a3cb 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/editor/ArticleAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/editor/ArticleAdapter.kt @@ -1,6 +1,8 @@ package com.gh.gamecenter.qa.editor +import android.app.Activity import android.content.Context +import android.content.Intent import android.support.v7.widget.RecyclerView import android.view.View import android.view.ViewGroup @@ -39,6 +41,14 @@ class ArticleAdapter(context: Context, private val mEntrance: String?) : ListAda val articleHolder = holder as CollectionCommunityArticleViewHolder val entity = mEntityList[position] articleHolder.binding.data = entity + articleHolder.itemView.setOnClickListener { + if (mContext is Activity) { + val intent = Intent() + intent.putExtra(ArticleEntity::class.java.simpleName, entity) + (mContext as Activity).setResult(Activity.RESULT_OK, intent) + (mContext as Activity).finish() + } + } } ItemViewType.ITEM_FOOTER -> { val footerViewHolder = holder as FooterViewHolder diff --git a/app/src/main/java/com/gh/gamecenter/qa/editor/GameAdapter.kt b/app/src/main/java/com/gh/gamecenter/qa/editor/GameAdapter.kt index b63354c905..e7f2a322d0 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/editor/GameAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/editor/GameAdapter.kt @@ -1,6 +1,8 @@ package com.gh.gamecenter.qa.editor +import android.app.Activity import android.content.Context +import android.content.Intent import android.support.v7.widget.RecyclerView import android.view.View import android.view.ViewGroup @@ -30,6 +32,14 @@ class GameAdapter(context: Context) : ListAdapter(context) { holder.binding.game = entity holder.binding.subjectTag = "type" holder.binding.downloadBtn.visibility = View.GONE + holder.itemView.setOnClickListener { + if (mContext is Activity) { + val intent = Intent() + intent.putExtra(GameEntity::class.java.simpleName, entity) + (mContext as Activity).setResult(Activity.RESULT_OK, intent) + (mContext as Activity).finish() + } + } } } diff --git a/app/src/main/java/com/gh/gamecenter/qa/entity/ArticleEntity.kt b/app/src/main/java/com/gh/gamecenter/qa/entity/ArticleEntity.kt index 998fd67a6d..808b42cc07 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/entity/ArticleEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/entity/ArticleEntity.kt @@ -6,6 +6,7 @@ import com.gh.gamecenter.entity.UserEntity import com.google.gson.annotations.SerializedName import kotlinx.android.parcel.Parcelize +@Parcelize data class ArticleEntity(@SerializedName("_id") val id: String = "", val title: String = "", @@ -15,11 +16,12 @@ data class ArticleEntity(@SerializedName("_id") val count: Count = Count(), val community: CommunityEntity = CommunityEntity(), val time: TimeEntity? = TimeEntity(), - val user: UserEntity = UserEntity()) { + val user: UserEntity = UserEntity()) : Parcelable { + @Parcelize data class TimeEntity(var create: Long? = 0, var update: Long? = 0, - var edit: Long? = 0) + var edit: Long? = 0) : Parcelable } @Parcelize