1 /** 
  2  * @fileoverview UAT documentPanel
  3  *    サーバ対応ドキュメントパネル機能
  4  *    調整後はxUIに統合予定
  5  * @aouther kiyo@nekomataya.info (ねこまたや)
  6  * @version 0.9.1 20190221
  7  */
  8 /*
  9 ドキュメントパネル自体が、データリストを保持する構造にする
 10 
 11 
 12 実際にデータを保持しているモジュールに対してリスト取得リクエストを出し、自分自身のデータリストを管理する
 13 アプリケーション内の請求手続きは一種類にしてサービスエージェントを通してモジュール間の差異を吸収する
 14 
 15 ローカルストレージを使用した参考リポジトリを設計実装する
 16 (サービスモジュールのデフォルト値として登録する)
 17 
 18 UI上のドキュメントパネルのオプションリストは、表示用のバッファとして利用(保持リスト本体ではない)
 19 
 20 リストのソート タイトルソート・話数ソート・フィルタ等の補助機能を実装
 21 カット番号リストは、ソートを基本 逆順表示 番号フィルタ を設計実装
 22 
 23 ドキュメントエントリは、SCiオブジェクトにサービスへの参照を拡張して使用
 24 
 25 
 26     serviceAgent.currentRepository
 27 
 28 現在使用しているリポジトリのリスト
 29 サービスにアクセスするごとに更新
 30 サービスエージェント上のエントリへの参照
 31 
 32     documentDepot.products
 33 
 34 プロダクトコレクション サービスにアクセスするごとに抽出更新
 35 各プロダクトは独立したデータとして一覧アクセスできるようにしておく
 36 フィルタは、Depotのオブジェクトメソッドで実装
 37 nas.Pm.Opus オブジェクトを使用 リポジトリへの参照を加える
 38 opusが同じでもリポジトリが異なる場合は、同エントリ内で複数を保持
 39 
 40 空プロダクトを作成する際は、リポジトリ内に対応する TITLE及びOPUSを同時に作成するようにトライする
 41 対応するオブジェクトが存在しないエントリは処理に失敗する
 42 
 43 カット(=ドキュメント)のエントリは空のままでも良いがOPUSを持たないタイトルはアプリの表示規則上許可されない
 44 
 45 
 46 主にローカルリポジトリや、ホームリポジトリでの使用を前提とする?
 47 
 48 
 49     documentDepot.documents
 50     
 51 ドキュメントエントリーコレクション サービスにアクセスするごとに更新
 52 ドキュメントエントリはカプセル化されたオブジェクトにする SCi互換
 53 ListEntry オブジェクトのコレクションとして実装
 54 
 55     currentProduct        現在ブラウザで選択中のプロダクト識別子
 56     currentSelection        現在ブラウザで選択中のドキュメント識別子
 57     currentDocument         現在編集対象のXps      (xUI.XPS の相互参照)
 58     currentReferenece       現在表示対象の参考Xps  (xUI.referenceXPSの相互参照)
 59 として扱う
 60 */
 61 //エントリを格納するオブジェクト xUIを再初期化するのでこのコードが消える
 62 //良くない
 63 /** @class アプリケーション内でドキュメントエントリを格納するクラス
 64  */
 65 documentDepot = {
 66     products    :[],
 67     documents   :[],
 68     currentProduct:null,
 69     currentSelection:null,
 70     currentDocument:null,
 71     currentReferenece:null
 72 };
 73 /**
 74  *  ドキュメントブラウザの保持データを初期化
 75  *
 76  *    ドキュメントセレクタのアップデートを行う<br />
 77  *    タイトルリスト及びドキュメントコレクションをクリア後<br />
 78  *    リポジトリのエントリリストを走査してコレクションを再構築してブラウザをアップデートする
 79  *    ** リポジトリ(エントリリスト)の更新は行わない 必要に従って事前に更新の要あり
 80  *
 81  *    逐次的に画面の再描画が可能なように変更する20170322
 82  *
 83  *    引数リストを受けて、現在のエントリと比較を行い逐次更新を行うように変更するか?
 84  *    ならば 事前に引数リスト組む必要あり
 85  *    または 参照するエントリリストの複製を持って差分のみの更新を行う? 複製が大変?
 86 */
 87 documentDepot.documentsUpdate=function(){
 88 console.log('=+=============+++===== documentsUpdate ')
 89 /*  既存データをクリアしない
 90 引数で受け取ったデータ群は、新規のデータ構造を組んで従来のデータと照合しながら更新を行う
 91     既存エントリ>新規データで置き換え
 92     新規エントリ>新規データから追加
 93 リムーブの機能が必要となるが、それをどうするか?
 94     ○エントリそのものにリムーブメソッドを設ける
 95     ○アップデートメソッドに第二引数を設けてリストを与えて処理する
 96 
 97 大量のリストが与えられた場合に、逐次的に一定数で画面をリフレッシュする(リストを分割処理する)機能を作る?
 98 エントリ全体の比較更新と、逐次リフレッシュを機能分割したほうが良さそう?
 99 
100 ただし全体のパフォーマンスをひどく下げているのは、ServiceAgent.getList の再帰呼び出しなのでこの処理は後回しでもOK 2017.04.19
101 
102 */
103     documentDepot.products  = [];
104     documentDepot.getProducts();
105     documentDepot.documents = serviceAgent.currentRepository.entryList;//カレントリポジトリのリストのみ
106 }
107 /**
108  *    カレントのドキュメント情報からプロダクト識別子の配列を抽出して戻す
109  *    @return {Array}
110 */
111 documentDepot.getProducts=function(){
112     var myProducts  =[];
113 //productsData を走査してプロダクトリストを作成する
114     for (var idx = 0 ; idx < serviceAgent.currentRepository.productsData.length ; idx ++){
115         var myTitle = serviceAgent.currentRepository.productsData[idx].name;
116         if(serviceAgent.currentRepository.productsData[idx].episodes){
117         for (var ide = 0 ; ide < serviceAgent.currentRepository.productsData[idx].episodes[0].length ; ide ++){
118                 var myOpus = serviceAgent.currentRepository.productsData[idx].episodes[0][ide].name;
119                 var mySubtitle = serviceAgent.currentRepository.productsData[idx].episodes[0][ide].description;
120                 var myIdentifier = 
121                         encodeURIComponent(myTitle)+
122                     "#" + encodeURIComponent(myOpus)+
123                     ((String(mySubtitle).length)?"["+mySubtitle+"]":"")
124                 myProducts.push(myIdentifier);
125             }
126         }
127     }
128     documentDepot.products=myProducts
129     return myProducts;
130 }
131 
132 /*  OPUSセレクタを更新する
133 引数:エントリフィルタ用正規表現
134 戻値:フィルタリング済のリスト配列
135 更新後のセレクタ内に現在の被選択アイテムがある場合はそれを選択状態にする
136 ない場合は選択アイテムを空に
137 プロダクトリストは、都度生成に変更(スタティックには持たない)
138  */
139 documentDepot.updateOpusSelector=function(myRegexp,rev){
140 //    if(! serviceAgent.currentRepository.opusList.updated){return;}
141     if(!(myRegexp instanceof RegExp)){ myRegexp = new RegExp(".+");}
142     if(!rev ) rev = false;
143 // ここで正規表現フィルタを引数にする
144     var myContents = "";
145 //    var myProducts = documentDepot.getProducts();
146     var myProducts = documentDepot.products;
147     var myResult   = [];
148     myContents += (myProducts.length)?
149     '<option value="==newTitle==" selected>(*-- no title selected --*)</option>':
150     '<option value="==newTitle==" selected>(*-- no titles --*)</option>';
151     for( var opid = 0 ; opid < myProducts.length ; opid ++){
152         var currentText = decodeURIComponent(myProducts[opid]);
153         var show = (currentText.match(myRegexp))? true:false;
154         if(rev) show = !show;
155         if(show){
156             myContents += '<option';
157             myContents += ' value="';
158             myContents += myProducts[opid];
159             if (documentDepot.currentProduct == myProducts[opid]){
160                 myContents += '" selected>';
161             }else{
162                 myContents += '">';
163                 documentDepot.currentProduct = null;
164             }
165             myContents += currentText;
166             myContents += '</option>';
167             myResult.push(myProducts[opid]);
168         }
169     }
170     if(document.getElementById( "opusSelect" ).innerHTML != myContents){
171         document.getElementById( "opusSelect" ).innerHTML = myContents;
172         document.getElementById( "opusSelect" ).disabled  = false;
173     }
174     return myResult;
175 }
176 /*  Documentセレクタを更新
177 引数:エントリフィルタ用正規表現
178 戻値:フィルタリング済のリスト配列
179 被選択ドキュメントが更新後のセレクタ内に存在する場合は、それを選択状態にする
180 ない場合は選択アイテムを空にする
181 
182 引数は正規表現よりも[開始番号,終了番号(表示個数?)]あたりにしたほうが何かと良いので順次変更
183 ドキュメントエントリは、ステータスを認識するように改修
184 Aborted ステータスのエントリは、制作管理モードでのみ表示
185  */
186  documentDepot.updateDocumentSelector=function(myRegexp){
187 // ここで正規表現フィルタを引数にする?
188     if(!(myRegexp instanceof RegExp)){ myRegexp = new RegExp(".+");}
189 // 選択済みタイトルで抽出
190     var myDocuments = documentDepot.getEntriesByOpusid(documentDepot.currentProduct);
191 //  正規表現フィルタで抽出してHTMLを組む
192     var myContents = "";
193     var myResult   = [];
194     myContents +=(myDocuments.length)? 
195     '<option value="==newDocument==" selected>(*-- no document selected--*)</option>':
196     '<option value="==newDocument==" selected>(*-- no documents --*)</option>';
197     for ( var dlid = 0 ; dlid < myDocuments.length ; dlid ++){
198 //全ドキュメント走査
199         var currentText = decodeURIComponent(myDocuments[dlid].toString(0).split('//')[1]);
200         var currentData = myDocuments[dlid];
201 //console.log(currentData.cut)
202        var currentStatus = currentData.getStatus();
203 //console.log(currentData);console.log(currentStatus)
204         if( (currentData.dataInfo.currentStatus.content.indexOf('Aborted') < 0) &&
205             (currentData.dataInfo.sci[0].cut.match(myRegexp))){
206             myContents += '<option';
207 
208             myContents += ' class="docStatus docStatus-';
209             myContents += currentStatus;
210 if((currentStatus=='Fixed')&&(currentStatus.assign)){
211             myContents += "-2";
212 }
213             myContents += '"';
214             myContents += ' value="';
215             myContents += myDocuments[dlid];
216             if(this.currentSelection == myDocuments[dlid]){
217                 myContents += '" selected >';
218             }else{
219                 myContents += '">';
220                 this.currentSelection = null;
221             };
222             myContents += currentText;
223             myContents += ' ['+currentStatus.content;
224             myContents += ']</option>';
225             myResult.push(myDocuments[dlid]);
226         }
227     }
228     if (document.getElementById( "cutList" ).innerHTML != myContents){
229         document.getElementById( "cutList" ).innerHTML = myContents;
230         document.getElementById( "cutList" ).disabled  = false;
231     }
232     return myResult;//抽出したリスト
233 }
234 
235 /*
236   現在の全エントリから プロダクトIDが一致するエントリを抽出してカット順にソートして返す
237 引数:プロダクト識別子
238  */
239 documentDepot.getEntriesByOpusid=function(myIdentifier){
240     if(! myIdentifier) myIdentifier=documentDepot.currentProduct;
241     myIdentifier+="//";
242 // タイトルIDで抽出
243     var myDocuments = [];
244     for ( var dcid = 0 ; dcid < documentDepot.documents.length ; dcid ++){
245 //console.log(documentDepot.documents[dcid].toString());console.log(myIdentifier);
246         if((documentDepot.currentProduct)&&(Xps.compareIdentifier(documentDepot.documents[dcid].toString(),myIdentifier) > -1)){
247             myDocuments.push(documentDepot.documents[dcid]);
248         }
249          continue;
250     }
251     myDocuments.sort(documentDepot.sortBySCi);
252     return myDocuments;    
253 }
254 
255 /**
256 listEntryのカット番号順にソートする 評価関数
257 */
258 documentDepot.sortBySCi = function(val1,val2){return (nas.parseNumber(val1.sci)-nas.parseNumber(val2.sci))};
259 /**
260     読み出して編集エリアに取り込む
261     識別子が指定されない場合は、セレクタの値を見る
262     ドキュメントリストに識別子が存在しない場合は、falseを返す
263     読み込み成功時はセレクタが開いていたら閉じる
264 */
265 documentDepot.getEntry =function(myIdentifier){
266     if(typeof myIdentifier == 'undefined'){
267         myIdentifier = documentDepot.currentSelection;
268     }
269     for (var did = 0;did < documentDepot.documents.length ; did ++){
270         if (documentDepot.documents[did].toString() == myIdentifier){
271             documentDepot.documents[did].parent.getEntry(myIdentifier);
272             return true;
273         }
274     }
275     return false
276 }
277 /**
278     現在のテキスト入力状態から識別子をビルドする。
279 */
280 documentDepot.buildIdentifier = function(addStatus){
281     var result="";
282     result += (document.getElementById('titleInput').value.match(/\(\*.*\*/)) ? "":
283         encodeURIComponent(document.getElementById('titleInput').value);
284     result += (document.getElementById('opusInput').value.match(/\(\*.*\*/)) ? "#":
285         '#'+encodeURIComponent(document.getElementById('opusInput').value);
286     result += (document.getElementById('subtitleInput').value.match(/\(\*.*\*/)) ? '':
287         '['+encodeURIComponent(document.getElementById('subtitleInput').value)+']';
288     result += '//';
289     var mySCi =Xps.parseSCi(((document.getElementById('cutInput').value.match(/\(\*.*\*\)/)) ? '':
290         document.getElementById('cutInput').value )+'('+document.getElementById('timeInput').value+')');
291 if(dbg) console.log(mySCi);
292     var myNames = Xps.parseCutIF(mySCi[0].cut);
293     result += (myNames.length > 1) ? 's'+encodeURIComponent(myNames[1])+'-c':'s-c';
294     result += (typeof myNames[0] == 'undefined')?"":encodeURIComponent(myNames[0]);
295     var timeSpc = parseInt(nas.FCT2Frm(String(mySCi[0].time)));
296   if(timeSpc > 0){
297     result += '( '+String(timeSpc)+' )';
298   }
299     if(addStatus){
300         result +='//';
301         result +=document.getElementById('issueSelector').value;
302     }
303 if(dbg) console.log("buildIdentifier::");
304 if(dbg) console.log(mySCi[0].time);
305 if(dbg) console.log(decodeURIComponent(result));
306     return result;
307 }
308 /**
309     ドキュメントリストを更新する
310     カレントリポジトリの内容を取得
311     得たリストをブラウザの保持リストとして更新する
312     先に存在するリストは破棄
313     この処理をカットのステータス変更の度に行うとレスポンスの低下が著しいので
314     要変更
315     当該のカットの状況のみをアップデートする手続が必要
316     実際は
317     LocalRepositoryの場合listEntryのアップデートのみでOK
318     NetworkRepositoryの場合はサーバのレスポンスからlistEntryをアップデートする
319 */
320 documentDepot.rebuildList=function(force,callback){
321     
322     documentDepot.currentProduct     =null;
323     documentDepot.currentSelection   =null;
324     documentDepot.products    =[];
325     documentDepot.getProducts();
326     documentDepot.documents   = serviceAgent.currentRepository.entryList;
327 //    documentDepot.currentDocument    =null;
328 //    documentDepot.currentReferenece  =null;
329 /*=============*/
330     if(typeof force == 'undefined') force = true;
331 //    serviceAgent.currentRepository.getProducts(force,callback);
332 //    serviceAgent.currentRepository.getList(force,callback);
333 //  テスト中はこれで良いが、その後はあまり良くない
334 //console.log(this);
335 //console.log(callback);
336 //    documentDepot.documentsUpdate();
337     
338 }
339 /**
340 読み出し・請求
341     明示的にリスト内のサーバにアクセスする場合は、その時点の最新リストを請求してリストを更新する
342     キャッシュを利用する場合は、リストの更新はなし。
343     
344 書き込み・更新
345     データの保存は、
346         アプリケーション終了(ウインドウクローズ)時の自動バックアップ
347         明示的なバックアップへの退避(↑上と同じ領域)
348 
349         保存先「リポジトリ」を指定して保存
350         上書き保存
351             「リポジトリ」の指定がない場合は、上書き保存
352         新規作成時
353             カレントリポジトリを使用
354             任意のリポジトリを指定するには保存前にカレントの変更が必要
355             
356 リポジトリについて
357     リポジトリは、このシステム上「データ保存場所」に識別用の名前を付けて管理対象としたもの。
358 
359     タイムシート・カット袋等の制作管理及びカット内容のメタデータ 及び将来的には、これらのデータに記載された制作データそのものを保存
360     ユーザのリクエストに従って読み書き可能なサービスとする。
361 
362     リポジトリには、基本的に制作管理DBの機能はない。
363     制作管理DBの機能は、一般のRDBMサービスを立ち上げそこで利用するものとする。
364     基本的にリポジトリとは別の接続を使用する
365     
366     簡易的なデータの解釈は、リポジトリから読み出したデータをアプリケーションがパースして行う。
367     簡易のパース結果を識別子としてリポジトリに送り、それをファイル名又はそれに類するメタ情報として保存して利用する
368     リポジトリにはデータの解釈(解析)を求めない。
369     
370         1>必要なデータを保存時に識別子としてデータにつけてアプリケーション側から送信する
371         2>リポジトリサーバは、その識別子を利用して保存を行う
372                 リスト要素を分解するか否かはサーバ側の事情で使い分けて良い
373                 階層管理する場合は、要素ごとに分解してディレクトリを分ける等の処理を行うとデータの管理が容易になる
374                  /(作品)/(話数)/(カット)/(ライン)/(ステージ)/(ジョブ)/(タイムシートデータ) 等のデータ配置にすると
375                  バックアップやレストア等の処理に利便性あり
376         
377     識別子の型式(埋め込み情報)は以下の様にする(仮仕様 2016/11/20)
378     
379 title#opus[subtitle]//SsceneCcut(seconds+frames) / SsceneCcut(seconds+frames) / SsceneCcut(seconds+frames) //lineID//stageID//jobID//
380 
381 例:
382     origData
383 かちかち山Max#おためし[サンプルカット] // S-C10(72) //0//0//0
384     encodeURIComponent
385 %E3%81%8B%E3%81%A1%E3%81%8B%E3%81%A1%E5%B1%B1Max#%E3%81%8A%E3%81%9F%E3%82%81%E3%81%97[%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%E3%82%AB%E3%83%83%E3%83%88] // S-C10(72) //0//0//0
386 
387 
388 タイトル・カット番号・サブタイトル等のデータにはセパレータ等の予約文字列が含まれるケースがあるので識別子を作成前にURI置換を行う必要あり
389 置き換え又はエスケープの必要な文字列(使用禁止のセンも考慮)
390 \n    改行            - 使用禁止
391 /     スラッシュ       - \###
392 ##No. ナンバーサイン   - 
393 [ ]   角括弧           - 
394 「 」  カギ括弧         - 
395 "'    引用符           - 
396 encodeURIComponent() を識別子組み立て前に通す
397 必要に従ってdecodeURIComponent()
398 
399    上記の型式で(今回実装のローカルリポジトリではこの方法を採用する)        
400     簡易パース手順
401         split("//")
402             5要素なら上書き可
403             6要素ならロック(fix)されて上書き不可
404             
405             第一要素 プロダクト識別子 パース手順あり
406             第二要素 SCi識別子
407                 split("/")
408                 第一要素代表カット番号 第二要素以降は兼用番号 第一要素と同じ番号が入る場合があるがその場合は無視
409                 各要素はカット番号とカット尺に分解して利用 カット尺は省略可能
410             第三要素    ラインID   (Int 通番)  各要素にname要素を付加しても良い 0:本線//1:レイアウト//0:打合せ 等
411             第四要素    ステージID (Int 通番)
412             第五要素    ジョブID   (Int 通番)
413             第六要素    ジョブステータス 値は文字列 Startup/Active/Hold/Fixed/Aborted いずれか
414 
415 *   作業ステージを閉じる処理は、ユーザがアプリケーション側で行う
416     その際、識別子にフィックスのサインを付加する(第六要素'Fixed')
417     フィックスされたデータが上書きされることはない データの請求は常に有効
418     将来的には、ステージ/ジョブを内部に備えたXps,xMap 等が利用されるが、その際もこの識別子はそのまま使用可能
419 
420 りまぴんで呼び出しの際は、基本的に既fixのデータはリファレンスに 未fixのデータは編集エリアに読み込む
421     
422     第一要素をパースしてタイトル/OPUS情報を取得可能
423     第二要素を split("/") で兼用情報が得られる 第一要素が当該のカット番号
424         各カット情報は カット番号(カット尺) *durationではない transition情報もない(この通信では不用)
425         プロトコル上は(カッコ内)は補助情報とする
426             duration,transition等の情報を追加することも可能?
427         
428 以上の機能をアプリケーション側で処理することで、RDBMのない状態で通常のストレージをリポジトリとして使用可能になる
429 とくにローカルファイルシステムを使う際は
430     URIエンコードを施しファイル名規則に抵触するのを避ける
431     長いファイル名を利用できる環境を使用すること
432     識別子は分解してディレクトリをわけて保存するか、又はエスケープしてスラッシュがファイル名に含まれるの避ける
433 
434     リポジトリに要求される機能は、
435         1.アプリケーションからの請求に従って、保存しているデータの識別子リストを送り返す
436         2.アプリケーションから送信された(識別子付き)データを受信して、
437             同じ識別子のエントリがあれば上書きする
438             エントリがない場合は新規に保存エントリを作成する
439         3.アプリケーションからの請求に従って、指定された識別子の保存データを送信する
440         
441     1.      list(filter)
442         あまりエントリ数が多いと待ち時間が増すので、フィルタ機能はあったほうが良い
443         (アプリケーション側でもフィルタするので無くても良い)
444     2.      write(identifier)
445         識別子のエントリがない場合は、新規エントリを登録
446     3.      read(identifier)
447         識別子のエントリがない場合は。操作失敗のレスポンスを返す
448 
449 * webStorage には一般的なリスト機能はないが 全キーを取得してリストを構築することは可能
450     リストオブジェクトをJSONパースしてストレージに一括で納める?
451 ただし、ブラウザ全体で5MB程度ととして、シートエディタのみでこれを専有するわけにもいかないので基本的にはドキュメントエントリ数を限って扱う。
452 試験的には複数エントリが扱えるように組む(ローカルファイルやDropBox/GoogleDrive等のネットストレージに対応するため)
453 
454 
455 */
456 /**
457     入力されたタイトルを評価してセレクタを切り替える
458 */
459 function selectBrowser(){
460     var myTitle     = document.getElementById('titleInput').value;
461     var myOpus      = document.getElementById('opusInput').value;
462     var mySubtitle  = document.getElementById('subtitleInput').value;
463     var myCutNo     = document.getElementById('cutInput').value;
464     var myTime      = document.getElementById('timeInput').value;
465 /*
466     セレクタの中から該当するエントリを検索して 存在すればそのエントリを選択状態にする
467     手続きは、セレクタ側の各要素を分解して下位から順に評価
468     明確に異なる値があった時点でエントリをリジェクト
469     すべてリジェクトされた場合フリーエントリを選択状態にする
470     サブタイトル・カット秒数は特に評価しない
471 */
472 
473 }
474 /**
475     タイトルを選択して入力エリア/カットセレクタを更新
476     productNameは以下の型式で分解する
477     (タイトル)[##№](番号)[(サブタイトル)]
478     
479     ももたろう#12 [キジ参戦!ももたろう地獄模様!!]
480     源氏物語 #23帖 [初音]
481     
482     タイトルと話数はナンバーサイン[##№]で区切る
483     サブタイトルが存在する場合は、[]角括弧,「」カギ括弧,""引用符で区切って記入する
484 */
485 function setProduct(productName){
486 console.log('setProduct####')
487 console.log(productName);
488 
489 //ドキュメント(カット)ブラウザの表示をリセット(クリア)
490     document.getElementById('cutList').innerHTML = "<option selected>(*-- no document --*)";
491     documentDepot.updateDocumentSelector();
492 //    selectSCi();
493 //ブラウザの選択を解除
494     documentDepot.currentSelection=null;
495     document.getElementById( "cutList" ).disabled=true;
496     
497     if(typeof productName == "undefined"){
498     //プロダクト名が引数で与えられない場合はセレクタの値をとる
499     //選択されたアイテムがない場合は、デフォルト値を使用してフリー要素を選択する
500         if ( document.getElementById("opusSelect").selectedIndex >= 0 ){
501             productName = ( document.getElementById("opusSelect").selectedIndex == 0 )?
502             "#[]":
503             document.getElementById("opusSelect").options[document.getElementById("opusSelect").selectedIndex].text;
504         }else{
505             document.getElementById("opusSelect").selectedIndex = 0;
506             productName = "#[]";
507         }
508     }else{
509 console.log("changeSelector")
510     //プロダクト名が与えられた場合は、セレクタの選択を更新する
511           //  document.getElementById('opusSelect').value=productName;
512         for(var pix=0;pix<documentDepot.products.length;pix++){
513             if(Xps.compareIdentifier(documentDepot.products[pix],productName)>=0){
514                 document.getElementById('opusSelect').value=documentDepot.products[pix];break;
515             }
516         }
517     }
518     productName=String(productName);//明示的にストリング変換する
519     var productInfo=Xps.parseProduct(productName);
520         var subTitle    = productInfo.subtitle;
521         var opus        = productInfo.opus;
522         var title       = productInfo.title;
523 /** パネルテキスト更新
524 リストに存在しないプロダクトの場合は、リスト側で'(* new product *)'を選択する
525 */ 
526     document.getElementById("titleInput").value    = (title.length)? title:"(*--title--*)";
527     document.getElementById("opusInput").value     = (opus.length)? opus:"(*--opus--*)";
528     document.getElementById("subtitleInput").value = (subTitle.length)? subTitle:"(*--subtitle--*)";
529 //    selectSCi();    
530 
531 // タイトルからカットのリストを構築して右ペインのリストを更新
532     documentDepot.currentProduct=document.getElementById("opusSelect").options[document.getElementById("opusSelect").selectedIndex].value;
533 
534     serviceAgent.currentRepository.getEpisodes(function(){
535 //        documentDepot.documentsUpdate();
536 //        documentDepot.updateOpusSelector();
537 // 選択したプロダクトが存在すればカットを取得
538 console.log(decodeURIComponent(documentDepot.currentProduct));
539         var currentOpus = serviceAgent.currentRepository.opus(documentDepot.currentProduct);
540         if(currentOpus){
541 // console.log(currentOpus.token);
542             serviceAgent.currentRepository.getSCi(function(){
543 // 更新したリストからリスト表示を更新
544             documentDepot.documentsUpdate();
545             documentDepot.updateDocumentSelector();
546             },false,currentOpus.token)
547         }else{
548            console.log("no opus exists ###");console.log(currentOpus);
549         }
550     },false,
551     documentDepot.buildIdentifier(),
552     documentDepot.buildIdentifier()
553     );
554 /*
555 // 選択したプロダクトが存在すればカットを取得
556     var currentOpus = serviceAgent.currentRepository.opus(documentDepot.currentProduct);
557 if(currentOpus){
558 // console.log(currentOpus.token);
559     serviceAgent.currentRepository.getSCi(function(){
560 // 更新したリストからリスト表示を更新
561         documentDepot.documentsUpdate();
562         documentDepot.updateDocumentSelector();
563     },false,currentOpus.token);
564   
565 }else{
566 //該当するプロダクトをコンソールへ
567 console.log(documentDepot.currentProduct);
568 }  */
569 //{        documentDepot.updateDocumentSelector();    }
570 /** パネルテキスト更新
571 リストに存在しないプロダクトの場合は、リスト側で'(* new product *)'を選択する
572 */ 
573 //    document.getElementById("titleInput").value    = (title.length)? title:"(*--title--*)";
574 //    document.getElementById("opusInput").value     = (opus.length)? opus:"(*--opus--*)";
575 //    document.getElementById("subtitleInput").value = (subTitle.length)? subTitle:"(*--subtitle--*)";
576     selectSCi();    
577 }
578 //setProduct("源氏物語#二十三帖「初音」");
579 /**
580 selectSCi
581 */
582 function selectSCi(sciName){
583     if(typeof sciName == "undefined"){
584     //カット名が引数で与えられない場合はセレクタの値をとる
585     //セレクタ値の場合は、ドキュメントリストの対応するエントリを取得
586     //選択されたアイテムがない場合は、デフォルト値を使用してフリー要素を選択する
587         if ( document.getElementById("cutList").selectedIndex > 0 ){
588             /*  セレクタで選択したカットのissuesをドロップダウンリストで閲覧可能にする
589                 デフォルト値は最終issue
590              */
591             var myEntry = serviceAgent.currentRepository.entry(document.getElementById("cutList").options[document.getElementById("cutList").selectedIndex].value);
592             if(myEntry){
593             var myContents="";
594             for (var ix=0;ix<myEntry.issues.length;ix++){
595                 myContents += '<option value="'+myEntry.issues[ix].join('//')+'"';
596                 myContents += (ix==(myEntry.issues.length-1))? ' selected >':' >';
597                 myContents += decodeURIComponent(decodeURIComponent(myEntry.issues[ix].join('//')))+"</option>";
598             }
599             document.getElementById("issueSelector").innerHTML=myContents;
600             if(xUI.uiMode!='management') document.getElementById("issueSelector").disabled=false;
601 
602             sciName = document.getElementById("cutList").options[document.getElementById("cutList").selectedIndex].text;
603             }else{console.log(myEntry)}
604         }else{
605             document.getElementById("issueSelector").innerHTML='<option value="" selected>#:---line//#:---stage//#:---job//(status)</option>';
606             document.getElementById("issueSelector").disabled=true;
607             document.getElementById("cutList").selectedIndex = 0;
608             sciName = "(*--c#--*)";
609             var myEntry = null;
610         }
611     }
612     sciName=String(sciName);//明示的にストリング変換する
613     if(sciName.length <= 0){return false;}
614     var sciArray=sciName.split( "/" );//セパレータ"/"で兼用カットを分離
615     //代表カット番号 はsciArray[0]
616     
617     if(sciArray[0].match(/^\s*(.+)\s*\(([^\)]+)\)\s*$/)){
618         var cutNumber = RegExp.$1;
619         var cutTime  = parseInt(nas.FCT2Frm(RegExp.$2)); 
620     }else{
621         var cutNumber = sciArray[0];
622         var cutTime   =  6*nas.FRATE;//6秒分フレーム
623     }
624 
625 //  状態更新
626 // パネルテキスト更新
627     document.getElementById("cutInput").value   = (cutNumber.length)? cutNumber:"(*--c#--*)";
628     document.getElementById("timeInput").value  = (cutTime)? nas.Frm2FCT(nas.FCT2Frm(cutTime),3):"6 + 00 .";
629 //UIボタンの更新
630     var myInputText=["titleInput","opusInput","subtitleInput","cutInput","timeInput"];
631 
632     if (document.getElementById("cutList").selectedIndex <= 0){}
633     if (! myEntry){
634 //選択されたドキュメントがリスト内に無い 
635         document.getElementById("ddp-readout").disabled     = true;
636         document.getElementById("ddp-reference").disabled   = true;
637         if(xUI.uiMode=='management')
638         for ( var tidx = 0 ; tidx < myInputText.length ; tidx ++ ){
639             document.getElementById(myInputText[tidx]).disabled = false;
640         }
641         documentDepot.currentSelection = documentDepot.buildIdentifier();//現在のテキスト入力状態から識別子をビルドする。
642     }else{
643 //リポジトリ内に指定データが存在する
644 var currentStatus = myEntry.issues[myEntry.issues.length-1][3];
645     
646         document.getElementById("ddp-readout").disabled     = ((xUI.onSite)&&(serviceAgent.currentStatus=='online-single'))? true:false;//シングルドキュメント拘束時読出抑制
647         document.getElementById("ddp-reference").disabled   = false;//参照は無条件読出可能
648         for ( var tidx = 0 ; tidx < myInputText.length ; tidx ++ ){
649             document.getElementById(myInputText[tidx]).disabled = true;
650         }
651         documentDepot.currentSelection = document.getElementById("cutList").options[document.getElementById("cutList").selectedIndex].value;
652     }
653     if((xUI.uiMode=='management')&&(!myEntry)){
654         document.getElementById('ddp-addentry').disabled    = false;
655     }else{
656         document.getElementById('ddp-addentry').disabled    = true;
657     }
658     if((myEntry)&&(serviceAgent.currentRepository===localRepository)){
659         document.getElementById('ddp-removeentry').disabled = false;
660     }else{
661         document.getElementById('ddp-removeentry').disabled = true;
662     }
663 
664 }
665 
666 
667 /**
668 プロダクト名 カット番号ともに編集可能とそうでないケースをグラフィックで表示する機能が必要
669 選択のみで編集不能な場合、文字をグレーアウトさせるか?
670 最初からグレーアウトで編集キーを押したときのみ編集可能(=新規作成)とするか 要調整
671 */