e-learning、オラクル研修、LMS(学習管理システム)のiStudy

e-learning、オラクル研修、LMS(学習管理システム)のiStudy

第134回「実用WEBアプリ 文書管理システム(15) メニューバーの追加 」

2015.07.29

こんにちは。インストラクターの蓑島です。

今回は文書管理システムにメニューバーを追加します。メニューバーを設けることで、登録、更新、検索などクリック一つで簡単になり大変便利になります。

具体的にメニューバーを設けたのは、DOC_SHOWプロシージャ画面です。このプロシージャは、指定された文書やディレクトリを表示するものでしたね。文書の場合はその文章の内容を表示し、ディレクトリの場合はそのディレクトリに所属するサブディレクトリや文章の一覧を表示するものでした。

では早速、そのプロシージャを実行します。5番の番号を指定して実行します。私の環境では5番は、「桃太郎」の文書です。
http://localhost:8080/dad/doc_show?p_id=5

画面上部に表示された行がメニューバーです。黄色くハイライトされている項目にリンクが張ってあり、クリックすると現在表示している文書やディレクトリに対して、今まで作成してきた過去のプロシージャで様々な機能を使うことができます。

各メニューの項目やリンクは以下の通りです。


現在の場所の下の階層をツリー表示します。
リンク先 「doc_tree?p_id=指定番号」


現在の場所の上のディレクトリを表示します。
リンク先 「doc_show?p_id=親ディレクトリの番号」

検索
現在のディレクトリ以下の階層に対して、キーワード検索を行います。
指定番号が文書の場合のリンク先 「doc_find?p_oya_dir=親ディレクトリの番号」
指定番号がディレクトリの場合のリンク先 「doc_find?p_oya_dir=指定番号」

登録(ディレクトリ)
現在のディレクトリの直下にディレクトリを追加します。
指定番号が文書の場合のリンク先 「doc_dir_make?p_oya_dir=親ディレクトリの番号」
指定番号がディレクトリの場合のリンク先 「doc_dir_make?p_oya_dir=指定番号」

登録(文書)
現在のディレクトリの直下に文書を作成します。
指定番号が文書の場合のリンク先 「doc_doc_make?p_oya_dir=親ディレクトリの番号」
指定番号がディレクトリの場合のリンク先 「doc_doc_make?p_oya_dir=指定番号」

更新
指定された番号の文書やディレクトリを更新します。
リンク先  「doc_update?p_id=指定番号」

実際にいくつかメニューを使ってみます。5番の桃太郎の文書のメニューバーで、「更新」をクリックします。

確かに、5番の桃太郎の文書の更新画面が表示されましたね。

もう一つやってみます。5番の桃太郎の文書で、「検索」をクリックします。

そうすると、5番の文書の親ディレクトリ(ここでは4番)がセットされた検索画面となっています。親ディレクトリが指定されているときは、そのディレクトリ以下を検索対象とするロジックでしたね。(バックナンバー第129回~131回参照)
このように該当文書やディレクトリに合わせたリンク先が生成されていることがわかります。

最後に5番の文書で、「▼」をクリックします。

前回(バックナンバー133回)作成した階層ツリーが表示されました。親ディレクトリ(4番)以下が表示されます。もとの5番の文書の位置は黄色くハイライトされています。

このように、メニューがあれば関連する操作がクリック一つになりますのでとても軽いサクサクした使用感となります。

ではソースコードを解説します。

メニューバーそのものはファンクションで生成し、そのメニューバーをDOC_SHOWプロシージャで表示します。

以下は今回作成したそのファンクションです。名前はDOC_FNC_MENUであり、パラメータ(P_ID)で番号を指定してその番号にあったメニューバーを文字列で返します。これをDOC_SHOWプロシージャからコールする形でメニューバーを表示するわけです。

SQL> CONNECT SCOTT/xxxxx スキーマユーザで(私の場合、SCOTT)
SQL> SET DEFINE OFF -- ソースコード中に&があるので、SQL*PlusやSQL*Developerの文字列置換機能をOFFにする

注意)以下のソースコードはブラウザ表示のために、山括弧(「<」と「>」)を全角にしています。 コピーして実行する方は、必ず、すべての山括弧(「<」と「>」)を半角に変換してください。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
CREATE OR REPLACE
FUNCTION DOC_FUNC_MENU (P_ID IN DOCS.ID%TYPE) RETURN VARCHAR2 IS
   V_STR  VARCHAR2(32767);
   V_KBN      DOCS.KBN%TYPE;   -- 1:文章 2:ディレクトリ
   V_OYA_DIR  DOCS.OYA_DIR%TYPE;  -- 親ディレクトリの番号
   -- 各、リンクの文字列
   C_DOWN     VARCHAR2(500) := '▼' ;
   C_UP       VARCHAR2(500) := '▲' ;
   C_SELECT   VARCHAR2(500) := '<b>検索</b>' ;
   C_INSERT1   VARCHAR2(500) := '<b>登録(ディレクトリ)</b>' ;
   C_INSERT2   VARCHAR2(500) := '<b>登録(文書)</b>' ;
   C_UPDATE   VARCHAR2(500) := '<b>更新</b>' ;
   C_BLANK    VARCHAR2(20) := '  ' ;
 
-- ハイライトしたり、マウスオーバーメッセージを付加するためのファンクション
   FUNCTION FNC_MOUSE_OVER(P_STR IN VARCHAR2, P_MSG IN VARCHAR2) RETURN VARCHAR2
   IS
     V_STR2  VARCHAR2(32767);
   BEGIN
     V_STR2 := P_STR;
    IF UPPER (V_STR2) LIKE '%HREF%'  THEN
       V_STR2 := '<font style="background-color: yellow">' || V_STR2 || '</font>' ;
       V_STR2 := '<abbr title="' || P_MSG || '">' ||V_STR2 || '</abbr>' ;
    END IF;
     RETURN  V_STR2;
   END FNC_MOUSE_OVER;
   
-- メインの実行部
BEGIN
--  番号が指定されていれば、文書、ディレクトリの区分(V_KBN)と親ディレクトリの番号(V_OYA_DIR)を取得
     BEGIN
     IF P_ID IS NOT NULL THEN
        SELECT KBN, OYA_DIR INTO V_KBN, V_OYA_DIR  FROM DOCS WHERE ID = P_ID;
     END IF;
     EXCEPTION
        WHEN NO_DATA_FOUND THEN
             NULL ;
     END ;
 
   -- 「▼」のリンク
   IF  P_ID IS NULL THEN   -- 最上位ディレクトリの一覧を表示しているとき
       C_DOWN := '<A HREF="doc_tree">' || C_DOWN || '</A>' ;
   ELSE
       C_DOWN := '<A HREF="doc_tree?p_id=' ||TO_CHAR(P_ID) || '">' || C_DOWN || '</A>' ;
   END IF;
     
    -- 「▲」のリンク
    IF P_ID IS NULL THEN  -- 最上位ディレクトリの一覧を表示しているとき
       NULL ;
    ELSIF V_OYA_DIR IS NULL THEN  -- 親ディレクトリがなとき(最上位ディレクトリ)
       C_UP := '<A HREF="doc_show">' || C_UP || '</A>' ;
    ELSIF  V_OYA_DIR IS NOT NULL THEN  -- 親ディレクトリがある(サブディレクトリ・文書)
       C_UP := '<A HREF="doc_show?p_id=' ||TO_CHAR(V_OYA_DIR) || '">' || C_UP || '</A>' ;
    END IF;
    
      -- 「検索」のリンク
   IF P_ID IS NULL THEN  -- 最上位ディレクトリの一覧を表示しているとき
     C_SELECT := '<A HREF="doc_find">' || C_SELECT || '</A>' ;
   ELSIF  V_KBN = 2 THEN  -- ディレクトリの場合
     C_SELECT := '<A HREF="doc_find?p_oya_dir=' || TO_CHAR(P_ID) || '">' || C_SELECT || '</A>' ;
   ELSIF  V_KBN = 1  THEN   -- 文書の場合
     C_SELECT := '<A HREF="doc_find?p_oya_dir=' || TO_CHAR(V_OYA_DIR) || '">' || C_SELECT || '</A>' ;
   END IF;
  
     -- 「登録(ディレクトリ)」のリンク
   IF P_ID IS NULL THEN -- 最上位ディレクトリの一覧を表示しているとき
     C_INSERT1 := '<A HREF="doc_dir_make">' || C_INSERT1 || '</A>' ;
   ELSIF V_KBN = 2 THEN  -- ディレクトリの場合
     C_INSERT1 := '<A HREF="doc_dir_make?p_oya_id=' || TO_CHAR(P_ID)  || '">' || C_INSERT1 || '</A>' ;
   ELSIF V_KBN = 1 THEN  -- 文書の場合
     C_INSERT1 := '<A HREF="doc_dir_make?p_oya_id=' || TO_CHAR(V_OYA_DIR)  || '">' || C_INSERT1 || '</A>' ;
   END IF;
   
    -- 「登録(文書)」のリンク
    IF P_ID IS NULL THEN   -- 最上位ディレクトリの一覧を表示しているとき
       NULL ;
    ELSIF V_KBN = 2 THEN  -- ディレクトリの場合
       C_INSERT2 := '<A HREF="doc_doc_make?p_oya_id=' || TO_CHAR(P_ID)  || '">' || C_INSERT2 || '</A>' ;
    ELSIF V_KBN = 1 THEN  -- 文書の場合
       C_INSERT2 := '<A HREF="doc_doc_make?p_oya_id=' || TO_CHAR(V_OYA_DIR)  || '">' || C_INSERT2 || '</A>' ;
   END IF;
   
   -- 「更新」のリンク
   IF P_ID IS NULL THEN  -- 最上位ディレクトリの一覧を表示しているとき
       NULL ;
   ELSE  -- ディレクトリまたは文書の場合
      C_UPDATE := '<A HREF="doc_update?p_id=' ||TO_CHAR(P_ID) || '">' || C_UPDATE || '</A>' ;
   END IF;
   
   -- 各リンク項目にマウスオーバーメッセージを追加したり、黄色やグレイにハイライトしたり
   C_DOWN := FNC_MOUSE_OVER(C_DOWN, 'この下の階層ツリーを表示します' );
   C_UP := FNC_MOUSE_OVER(C_UP, '上の階層に移動します' );
   C_SELECT := FNC_MOUSE_OVER(C_SELECT, 'デフォルトで現在のディレクトリ以下を' ||
          'キーワードで検索します。親ディレクトリ番号を省略すればすべてのディレクトリを対象にできます' );
   C_INSERT1 := FNC_MOUSE_OVER(C_INSERT1, 'デフォルトで現在のディレクトリ以下に' ||
          '新規ディレクトリを登録します。親ディレクトリIDを変えれば異なるディレクトリも可能です。' );
   C_INSERT2 := FNC_MOUSE_OVER(C_INSERT2, 'デフォルトで現在のディレクトリ以下に' ||
          '新規の文書を登録します。親ディレクトリIDを変えれば異なるディレクトリも可能です。' );
   IF V_KBN = 1 THEN 
     C_UPDATE := FNC_MOUSE_OVER(C_UPDATE, 'この文書を更新します' );
   ELSE
     C_UPDATE := FNC_MOUSE_OVER(C_UPDATE, 'このディレクトリを更新します' );
   END IF;
   
   -- 最終的にそれらのリンク項目を一行にまとめ
   V_STR := '【' || C_BLANK || '<font size="-1">' ||C_DOWN || C_BLANK || C_UP || C_BLANK || 
            C_SELECT || C_BLANK || C_INSERT1 || C_BLANK || C_INSERT2 || C_BLANK || C_UPDATE || '</font>' || C_BLANK || '】<br>' ;
 
   -- それをリターンする
   RETURN V_STR;
END DOC_FUNC_MENU;
/
 
ファンクションが作成されました。

上記のファンクションは、指定された番号(P_ID)をもとに、それに合ったメニューバーを生成し、リターンします。あらかじめメニューの項目を変数で用意(7~12行目)して、29行目以下の実行部で、それぞれのメニューの項目に指定された番号にあったリンクを張っていきます(44~88行目)。その後、90~103行目で、それらのメニューの項目で、リンクの貼られているものについては黄色にハイライトしたり、マウスオーバーのメッセージを付加します。その処理は、16~26行目で宣言してあるローカルファンクション FNC_MOUSE_OVERで行っています。

最終的に、リンクの項目を1列にまとめてリターンします(106~110行目)。

このようにあらかじめ項目を変数で用意して、その変数に対してリンク文字列や、マウスオーバーの文字列を付加し、最終的に各変数を連結して組み立てることで、どの画面に移動しても、メニューバーの各項目の位置はぶれずに固定されます。

以上が今回、作成したメニューバー用のファンクションのコードです。

それとは別に既存のプロシージャにも若干の変更を加える必要があります。

<<<DOC_SHOWプロシージャの変更点>>>
バックナンバー125回に掲載してあるDOC_SHOWプロシージャの2箇所に以下の行を追加

20行目でBODYタグを出力している直後の場所
(追加する行) HTP.P(DOC_FUNC_MENU(REC1.ID));

51行目でBODYタグを出力している直後の場所
(追加する行) HTP.P(DOC_FUNC_MENU(REC2.ID));

<<<DOC_DIR_MAKEプロシージャの変更点>>>
バックナンバー121回に掲載してあるDOC_DIR_MAKEプロシージャを以下のように修正

パラメータの追加
(1行目 変更前) CREATE OR REPLACE PROCEDURE DOC_DIR_MAKE
(1行目 変更後)CREATE OR REPLACE PROCEDURE DOC_DIR_MAKE ( P_OYA_ID IN VARCHAR2 DEFAULT NULL)

画面の項目に値をセット
(16行目 変更前)'<INPUT TYPE="TEXT" NAME="P_OYA_ID" SIZE="8"> (省略:最上位ディレクトリ)</TD></TR>');
(16行目 変更後)'<INPUT TYPE="TEXT" NAME="P_OYA_ID" SIZE="8" VALUE="' ||P_OYA_ID||'"> (省略:最上位ディレクトリ)</TD></TR>');

<<<DOC_DOC_MAKEプロシージャの変更点>>>
バックナンバー122回に掲載してあるDOC_DOC_MAKEプロシージャを以下のように修正

パラメータの追加
(1行目 変更前)CREATE OR PRELACE PROCEDURE DOC_DOC_MAKE
(1行目 変更後)CREATE OR REPLACE PROCEDURE DOC_DOC_MAKE ( P_OYA_ID IN VARCHAR2 DEFAULT NULL)

画面の項目に値をセット
(16行目 変更前)'<INPUT TYPE="TEXT" NAME="P_OYA_ID" SIZE="8"> (必須)</TD></TR>');
(16行目 変更後)'<INPUT TYPE="TEXT" NAME="P_OYA_ID" SIZE="8" VALUE="' ||P_OYA_ID||'"> (必須)</TD></TR>');

以上の修正により、DOC_SHOWプロシージャの結果画面にメニューバーが追加されたり、DOC_DIR_MAKEプロシージャや、DOC_DOC_MAKEプロシージャが指定文書の親ディレクトリを引き継ぐことができます。

これにより、メニューバーとしての実装ができました。

それでは今回はここまでにいたします。

次回実装を考えている機能は、複数文書やディレクトリを一括で他のディレクトリに移動させる機能です。ディレクトリ移動は、各文書や各ディレクトリの個々の更新画面から可能です。しかし、多数の文書、ディレクトリを選択しておいて一括で他のディレクトリに移動させることができれば便利ですね。適切なディレクトリ管理は文書管理の基本ですからとても役に立つ機能になると思います。

それではまた次回、ご期待ください。

先頭へ戻る