データソース

このサンプルでは、コメントコンポーネントに構成したコメント、ユーザー、リアクションとサーバー(データベース)側との連携するためのデータソース機能を確認することができます。

コメントコンポーネントは、リモート要求オプションを設定するためのインターフェースを提供します。データソース機能を有効にすると、変更されたデータをリモートデータベースと同期することが可能になります。 データソース機能の設定 dataSourceの定義でenabledプロパティをtrueに設定し、remoteプロパティを使用してリクエスト処理を実装します。remoteプロパティでコメント、ユーザー、リアクションに関する処理を設定することで、データの取得や更新、削除などの操作を実行できるようになります。 設定例は以下の通りです。 コメントの操作に伴う要求と応答 コメントの読み込み、追加、更新、削除を行う場合、コメントに対する操作を伴うリクエストが開始され、サーバーに送信されます。 操作 要求の種類 要求データ 応答データ 読み込み GET なし(取得するコメントの種類に応じて、typeなどのクエリパラメータが付与される) コメントレコードの配列 追加 POST 追加されたコメント(userId, content, parentId?, mentionInfo?) 追加されたデータ 更新 PUT 更新されたコメント(userId, content, parentId?, mentionInfo?) 更新されたデータ 削除 DELETE 削除されたコメントのID 制限なし ※ デフォルトでは、POST/PUTリクエストの要求データ形式はフォームデータになります。 コメントの読み込みのGETリクエストには、操作に応じて以下のクエリパラメータが自動的に付与されます。クライアントサイドで明示的に指定する必要はありません。サーバーサイドでは、リクエストに含まれるパラメータを受け取り、データ処理を行います。 クエリパラメータ 説明 設定例 type 取得コメントの種類。page, sticked, reply, link を指定できる ${url}?type=page&pageNumber=0&pageSize=2${url}?type=sticked${url}?type=reply&commentId=1&loadedCount=0${url}?type=link&url=xxxxx pageNumber 動的読み込み時のページ番号 ${url}?type=page&pageNumber=0&pageSize=2 pageSize 1ページあたりのコメント数 ${url}?type=page&pageNumber=0&pageSize=2 commentId 親コメントのID。指定されたコメントへの返信を取得 ${url}?type=reply&commentId=1&loadedCount=0 loadedCount 取得済みの返信数(動的読み込み時に使用) ${url}?type=reply&commentId=1&loadedCount=0 url リンクからコメントを取得する場合のURL ${url}?type=link&url=xxxxx ユーザー情報の要求と応答 メンション機能を使用する場合、ユーザーIDまたはユーザー名を検索し、以下の操作を行います。 操作 要求の種類 要求データ 応答データ 読み込み GET ユーザーID 一致したユーザー情報 読み込み GET ユーザー名 一致したユーザー情報の配列 リアクション情報の要求と応答 コメントに対してリアクションの表示、追加、削除を行う場合、各操作を伴うリクエストが開始され、サーバーに送信されます。 操作 要求の種類 要求データ 応答データ 読み込み GET コメントIDとユーザーID リアクションの配列 追加 POST リアクションが追加されたコメント(userId, commentId, reactChar) 操作の成功または失敗 削除 DELETE リアクションが削除されたコメント(userId, commentId, reactChar) 操作の成功または失敗 コンテンツタイプの指定 remoteプロパティのrequestDataTypeを使用して、HTTP通信においてPOST/PUTリクエストに送信されるデータの形式を指定できます。デフォルトではGcCommentRequestDataType.FormDataです。 GcCommentRequestDataTypeの値 説明 JSON JSON形式 FormData フォームデータ形式
import "./styles.css"; import "@mescius/inputman.comment/CSS/gc.inputman.comment.css"; import "@mescius/inputman.richtexteditor/CSS/gc.inputman.richtexteditor.css"; import { InputMan } from "@mescius/inputman.comment"; import * as RichTextEditorControl from "@mescius/inputman.richtexteditor"; import "@mescius/inputman.richtexteditor/JS/plugins/all"; const baseURL = window.location.origin + '/inputmanjs/demos/server/api/DataSource'; const loadReactionCount = async () => { const response = await fetch(`${baseURL}/reactions/count`); if (response.ok) { const res = await response.json(); return res.totalReactions; } else { return 0; } }; const loadCommentCount = async () => { const response = await fetch(`${baseURL}/comments/count`); if (response.ok) { return (await response.json()).totalComments; } else { return 0; } }; const gcComment = new InputMan.GcComment(document.getElementById('gcComment'), { openLinkMode: InputMan.OpenLinkMode.GoToComment, userInfo: { id: '1', name: '森上 偉久馬', avatar: '$IMDEMOROOT$/ja/samples/comment/datasource/img/avatar1.png', }, header: [ [ { name: InputMan.GcCommentHeaderFooterItem.Search, align: 'right', }, { name: InputMan.GcCommentHeaderFooterItem.Sort, align: 'left', }, ], [ InputMan.GcCommentHeaderFooterItem.CommentCount, InputMan.GcCommentHeaderFooterItem.ReactionCount ], ], editorConfig: { editorType: InputMan.GcCommentEditorType.GcRichTextEditor, plugins: [RichTextEditorControl.InputMan.GcRichTextEditorPluginItem.All], height: 150, menubar: [], toolbar: [ RichTextEditorControl.InputMan.GcRichTextEditorToolbarItem.Emoticons, RichTextEditorControl.InputMan.GcRichTextEditorToolbarItem.BlockQuote, RichTextEditorControl.InputMan.GcRichTextEditorToolbarItem.SeparateLine, RichTextEditorControl.InputMan.GcRichTextEditorToolbarItem.FontFamily, RichTextEditorControl.InputMan.GcRichTextEditorToolbarItem.FontSize, RichTextEditorControl.InputMan.GcRichTextEditorToolbarItem.SeparateLine, RichTextEditorControl.InputMan.GcRichTextEditorToolbarItem.Bold, RichTextEditorControl.InputMan.GcRichTextEditorToolbarItem.Italic, RichTextEditorControl.InputMan.GcRichTextEditorToolbarItem.Strikethrough, RichTextEditorControl.InputMan.GcRichTextEditorToolbarItem.Underline, RichTextEditorControl.InputMan.GcRichTextEditorToolbarItem.SeparateLine, RichTextEditorControl.InputMan.GcRichTextEditorToolbarItem.Paste, RichTextEditorControl.InputMan.GcRichTextEditorToolbarItem.PasteText, RichTextEditorControl.InputMan.GcRichTextEditorToolbarItem.SeparateLine, RichTextEditorControl.InputMan.GcRichTextEditorToolbarItem.HTMLCode, RichTextEditorControl.InputMan.GcRichTextEditorToolbarItem.CharMap, RichTextEditorControl.InputMan.GcRichTextEditorToolbarItem.Link, ] }, dataSource: { enabled: true, remote: { comments: { read: { url: `${baseURL}/comments`, }, create: { url: `${baseURL}/comments`, }, update: { url: `${baseURL}/comments`, }, delete: { url: `${baseURL}/comments`, } }, users: { read: { url: `${baseURL}/users`, schema: { dataSchema: { name: 'username' } } } }, reactions: { read: { url: `${baseURL}/reactions`, }, create: { url: `${baseURL}/reactions`, }, delete: { url: `${baseURL}/reactions`, } } } }, loadReactionCount, loadCommentCount, loadUsersInfoHandler: async (context) => { let users = []; const response = await fetch(`${baseURL}/users`); if (response.ok) { users = await response.json(); if (context.loadType === InputMan.LoadUserType.FilterText) { return users.filter((u) => u.name.includes(context.value)); } else if (context.loadType === InputMan.LoadUserType.ById) { return users.filter((u) => u.id === context.value); } } else { console.error('ユーザー情報の読み込みが失敗しました:', response.statusText); } } }); const UpdateCount = async () => { const commentCount = await loadCommentCount(); const reactionCount = await loadReactionCount(); gcComment.execCommand(InputMan.GcCommentCommand.UpdateCommentCount, { count: commentCount }); gcComment.execCommand(InputMan.GcCommentCommand.UpdateReactionCount, { count: reactionCount }); } gcComment.addEventListener(InputMan.GcCommentEvent.AfterExecuteCommand, (args) => { if (args.command === InputMan.GcCommentCommand.PostComment || args.command === InputMan.GcCommentCommand.UpdateComment) { const mentionInfo = args.value.mentionInfo; if (Array.isArray(mentionInfo) && mentionInfo.length > 0) { const nameList = mentionInfo.map(i => i.userName); alert(`${nameList.join(",")} 宛に、コメントを確認するようメールを送信しました。`); } } const needUpdateCountCommands = [ InputMan.GcCommentCommand.DeleteComment, InputMan.GcCommentCommand.PostComment, InputMan.GcCommentCommand.ReplyToComment, InputMan.GcCommentCommand.Clear, InputMan.GcCommentCommand.SetComments, InputMan.GcCommentCommand.ReactToComment, ]; if (needUpdateCountCommands.includes(args.command)) { UpdateCount(); } });
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <meta name="description" content="コメントコンポーネント 使い方" lang="ja" xml:lang="ja" /> <title>コメントコンポーネント - データソース</title> <!-- SystemJS --> <script src="node_modules/systemjs/dist/system.src.js"></script> <script src="systemjs.config.js"></script> <script> window.onload = function () { System.import('./src/app'); } </script> </head> <body> <div id="gcComment"></div> </body> </html>
body { box-sizing: content-box !important; height: 551px !important; }
System.config({ transpiler: 'plugin-babel', babelOptions: { es2015: true }, meta: { '*.css': { loader: 'css' } }, paths: { // paths serve as alias 'npm:': 'node_modules/' }, // map tells the System loader where to look for things map: { '@mescius/inputman': 'npm:@mescius/inputman/index.js', '@mescius/inputman/CSS': 'npm:@mescius/inputman/CSS', '@mescius/inputman.richtexteditor': 'npm:@mescius/inputman.richtexteditor/index.js', "@mescius/inputman.richtexteditor/CSS": "npm:@mescius/inputman.richtexteditor/CSS", '@mescius/inputman.richtexteditor/JS/plugins/advlist': 'npm:@mescius/inputman.richtexteditor/JS/plugins/advlist/plugin.js', '@mescius/inputman.richtexteditor/JS/plugins/all': 'npm:@mescius/inputman.richtexteditor/JS/plugins/all/plugin.js', '@mescius/inputman.richtexteditor/JS/plugins/autosave': 'npm:@mescius/inputman.richtexteditor/JS/plugins/autosave/plugin.js', '@mescius/inputman.richtexteditor/JS/plugins/charmap': 'npm:@mescius/inputman.richtexteditor/JS/plugins/charmap/plugin.js', '@mescius/inputman.richtexteditor/JS/plugins/directionality': 'npm:@mescius/inputman.richtexteditor/JS/plugins/directionality/plugin.js', '@mescius/inputman.richtexteditor/JS/plugins/emoticons': 'npm:@mescius/inputman.richtexteditor/JS/plugins/emoticons/plugin.js', '@mescius/inputman.richtexteditor/JS/plugins/fullscreen': 'npm:@mescius/inputman.richtexteditor/JS/plugins/fullscreen/plugin.js', '@mescius/inputman.richtexteditor/JS/plugins/htmlcode': 'npm:@mescius/inputman.richtexteditor/JS/plugins/htmlcode/plugin.js', '@mescius/inputman.richtexteditor/JS/plugins/image': 'npm:@mescius/inputman.richtexteditor/JS/plugins/image/plugin.js', '@mescius/inputman.richtexteditor/JS/plugins/link': 'npm:@mescius/inputman.richtexteditor/JS/plugins/link/plugin.js', '@mescius/inputman.richtexteditor/JS/plugins/lists': 'npm:@mescius/inputman.richtexteditor/JS/plugins/lists/plugin.js', '@mescius/inputman.richtexteditor/JS/plugins/media': 'npm:@mescius/inputman.richtexteditor/JS/plugins/media/plugin.js', '@mescius/inputman.richtexteditor/JS/plugins/pagebreak': 'npm:@mescius/inputman.richtexteditor/JS/plugins/pagebreak/plugin.js', '@mescius/inputman.richtexteditor/JS/plugins/preview': 'npm:@mescius/inputman.richtexteditor/JS/plugins/preview/plugin.js', '@mescius/inputman.richtexteditor/JS/plugins/save': 'npm:@mescius/inputman.richtexteditor/JS/plugins/save/plugin.js', '@mescius/inputman.richtexteditor/JS/plugins/searchreplace': 'npm:@mescius/inputman.richtexteditor/JS/plugins/searchreplace/plugin.js', '@mescius/inputman.richtexteditor/JS/plugins/table': 'npm:@mescius/inputman.richtexteditor/JS/plugins/table/plugin.js', '@mescius/inputman.richtexteditor/JS/plugins/template': 'npm:@mescius/inputman.richtexteditor/JS/plugins/template/plugin.js', '@mescius/inputman.richtexteditor/JS/plugins/wordcount': 'npm:@mescius/inputman.richtexteditor/JS/plugins/wordcount/plugin.js', '@mescius/inputman.comment': 'npm:@mescius/inputman.comment/index.js', '@mescius/inputman.comment/CSS': 'npm:@mescius/inputman.comment/CSS', '@mescius/wijmo': 'npm:@mescius/wijmo/index.js', '@mescius/wijmo.styles': 'npm:@mescius/wijmo.styles', '@mescius/wijmo.cultures': 'npm:@mescius/wijmo.cultures', '@mescius/wijmo.input': 'npm:@mescius/wijmo.input/index.js', '@mescius/wijmo.grid': 'npm:@mescius/wijmo.grid/index.js', '@mescius/wijmo.nav': 'npm:@mescius/wijmo.nav/index.js', '@mescius/spread-sheets': 'npm:@mescius/spread-sheets/index.js', '@mescius/spread-sheets-resources-ja': 'npm:@mescius/spread-sheets-resources-ja/index.js', '@mescius/spread-sheets/styles': 'npm:@mescius/spread-sheets/styles', 'css': 'npm:systemjs-plugin-css/css.js', 'plugin-babel': 'npm:systemjs-plugin-babel/plugin-babel.js', 'systemjs-babel-build': 'npm:systemjs-plugin-babel/systemjs-babel-browser.js' }, // packages tells the System loader how to load when no filename and/or no extension packages: { src: { defaultExtension: 'js' }, "node_modules": { defaultExtension: 'js' }, } });