1 /** 2 * @auther kiyo@nekomataya.info (ねこまたや) 3 * @fileoverview ServiceAgent モジュール 4 5 サービスエージェント 6 一旦このモジュールを通すことで異なる種別のリポジトリの操作を統一する 7 サービスエージェントは、ログイン管理を行う 8 9 test data: 10 var username = kiyo@nekomataya.info 11 var password = 'devTest' 12 var client_id = "b115aead773388942473e77c1e014f4d7d38e4d4829ae4fd1fa0e48e1347b4cd"; 13 var client_secret = "54c0f02c38175436df16a058cc0c0e037038c82d3cc9ce4c212e3e4afe0449dd"; 14 15 http://remaping.scivone-dev.com/oauth/token? 16 Object ServiceAgent 17 .servers サーバコレクション 18 .repositories リポジトリコレクション 19 .currentRepository 現在選択されているリポジトリへの参照 20 21 22 サーバは複数のリポジトリを持つことができる 23 リポジトリは、いずれかのサーバに属しそのサーバへの参照を持つ 24 ローカルリポジトリはアプリケーション自身がサーバの代用をする 25 26 アプリケーションはリポジトリセレクタでリポジトリを選ぶ 27 28 ドキュメントリストにはリポジトリから取得した内容と、実際にオープンした内容の履歴を表示する 29 履歴は、ローカルリポジトリにするか? 30 そうする場合は、ローカルリポジトリはセレクタに入れずに表示にマーキングをする 31 特に現在開いている(又は開いていない)リポジトリのカットとカブっている場合 32 33 リポジトリ分類 34 以下のような段階的な差を付けてアカウントを取得してもらう+制作会社に対する有料サービスを販売しやすくしたい 35 36 ローカルリポジトリ 37 オフライン作業用のリポジトリ 38 常に使用可能、このリポジトリのデータは対応する作品を管理するサーバと同期可能にする? 39 作業中に認証を失ったり、ネットワーク接続が切れた作業はこのリポジトリに保存することが可能 40 サービスノード(サーバ)としてはダミーの値を持たせる 41 (作業バックアップ領域とは別 作業バックアップは常時使用可能) 42 ローカルリポジトリは容量が制限されるので保存できるカット数に制限がある(現在5カット 2016.11.15) 43 この部分は作業履歴や作業キャッシュとして扱うべきかも 44 履歴として扱う場合は、「最終5カットのリングバッファ」という風に 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 Repository.ouganization 75 Repository.pmdb.orgnizations 76 Repository.pmdb.users 当該リポジトリ内の基礎ユーザDB 77 Repository.pmdb.staff 同基礎スタッフDB(ここにユーザを含む必要はないツリー下位のDBが優先) 78 Repository.pmdb.lines 同ラインテンプレート(テンプレート ツリー下位のDB優先) 79 Repository.pmdb.stages 同ステージテンプレート(同上) 80 Repository.pmdb.jobNames 同ジョブテンプレート (同上) 81 Repository.pmdb.assets アセット定義テーブル 82 Repository.pmdb.medias 同メディアテンプレート 83 Repository.pmdb.workTitles 作品タイトルコレクション 84 Repository.pmdb.opuses プロダクトコレクション 85 86 Repository.users アクセスの可能性がある全ユーザのリスト 87 Repository.productsData.staff アクセス可否情報 リポジトリに対するユーザとその所属・役職のDB 88 Repository.productsData[px].staff アクセス可否情報 リポジトリに対するユーザとその所属・役職のDB 89 Repository.productsData[px].episodes[ex].staff アクセス可否情報 リポジトリに対するユーザとその所属・役職のDB 90 Repository.productsData[px].episodes[ex].cuts[cx].staff アクセス可否情報 リポジトリに対するユーザとその所属・役職のDB 91 92 エントリごとにスタッフに対して以下の権利を設定することができる 93 94 true (アクセス可) 95 false (アクセス不可) 96 97 内部状態として、以下の状態があるがユーザが設定可能なのはtrue/falseの2状態のみとする 98 X リスト 99 R 読出 100 W チェックイン 101 102 権利に対して レイヤー構造がある 103 リポジトリは組織として プロダクト(workTitle)を含む 104 プロダクト(workTitle)はエピソード(opus)に分割される 105 opusは制作話数であり、個々のドキュメント(pmunit)を含む 106 107 各ドキュメントはライン/ステージ/ジョブの構造を持つ 108 109 このアトリビュート毎・ユーザ毎に 権限が異なるケースがある 110 111 112 リポジトリ * 113 プロダクト * 114 各話 * 115 カット * 116 ライン * 117 ステージ * 118 ジョブ * 119 120 サーバごとに権限グループを設ける基本は作業部毎 121 制作管理部 122 演出部 123 撮影部 124 美術部 125 原画部 126 動画部 127 仕上部 128 129 等 130 131 グループ・ユーザの権限は、エントリ毎に設定可能に 132 基本はグループに対する権限設定 133 イレギュラー処理が必要なケースのみユーザごとの権限をエントリの設定に追記する 134 135 イレギュラーや変更がなければエントリの権限設定は上位のレイヤから継承するので記載は無くとも良い 136 137 グループ権限・作品データ・管理基礎データ等の保存管理 138 139 基本的なDBへの登録等は、リポジトリ内に設定データを置いてその読み書きで対処する 140 RDBMのサポートのないファイル(ストレージ)上でリポジトリを築く際に必要 141 サービスエージェントを介してのDBへの情報請求をここで解決 142 これらの権利関連を別紙にまとめる 143 144 サービスエージェントはこのまま拡張 pmdb,xMap,Xpstを統合する 145 146 */ 147 /** 148 @constractor 149 150 サービスノードオブジェクト 151 複数あるサーバ(ログイン先)の必要な情報を保持するオブジェクト 152 複数のサービス情報をプログラム内に保持しないようにドキュメント内の属性として監理する 153 同時に記録する認証は一つ、複数のログイン情報を抱える必要はない 154 最期に認証したノード一つで運用 トークンはログイン毎に再取得 155 */ 156 ServiceNode=function(serviceName,serviceURL){ 157 this.name = serviceName ;//識別名称 158 this.url = serviceURL ;//ベースになるURL localStorageの際は"localStorage:" 159 this.type = "scivon" ;//localStrage/scivon/localfilesystem/dropbox/googleDrive/oneDrive 等のキーワード(外部ストレージは未サポート2017.11) 160 // this.uid = '';//uid ログインユーザID パスワードは控えない 必要時に都度請求 161 // this.lastAuthorized = "";//最期に認証したタイミング 162 // this.accessToken="";//アクセストークン 163 // this.username = kiyo@nekomataya.info 164 // this.password = 'devTest' 165 // 以下の情報は、テスト用に埋め込み あとで分離処置 166 this.client_id = "b115aead773388942473e77c1e014f4d7d38e4d4829ae4fd1fa0e48e1347b4cd"; 167 this.client_secret = "54c0f02c38175436df16a058cc0c0e037038c82d3cc9ce4c212e3e4afe0449dd"; 168 } 169 /** 170 リクエストのヘッダにトークンを載せる 171 トークンの期限が切れていた場合は、再度のトークン取得(再ログイン)を促す 172 v1向けのコードは考慮しない 173 */ 174 ServiceNode.prototype.setHeader=function(xhr){ 175 // if (this.type=="sivon"){} 176 var oauth_token = (xUI.onSite)? 177 $('#backend_variables').attr('data-user_access_token'):$('#server-info').attr('oauth_token'); 178 //console.log("setHeader :: "); 179 //console.log(oauth_token); 180 //console.log(xhr); 181 var organizationToken = (typeof serviceAgent.currentRepository.token != 'undefined')? serviceAgent.currentRepository.token:''; 182 if(oauth_token.length==0) return false; 183 xhr.setRequestHeader('Access-Control-Allow-Origin', '*' ); 184 xhr.setRequestHeader('Authorization', ( "Bearer " + oauth_token)); 185 xhr.setRequestHeader('OrganizationToken', organizationToken ); 186 return true; 187 } 188 /** 189 @undocumented 190 データ取得 191 参考コード 実際にはコールされない 192 */ 193 ServiceNode.prototype.getFromServer=function getFromServer(url, msg){ 194 //V1 195 $.ajax({ 196 url: this.url + url, 197 type: 'GET', 198 dataType: 'json', 199 success: function(res) { 200 if(dbg) console.log(msg); 201 if(dbg) console.log(res); 202 }, 203 beforeSend: this.setHeader 204 }); 205 //V2 206 $.ajax({ 207 url: this.url + url, 208 type: 'GET', 209 dataType: 'json', 210 success: function(res) { 211 if(dbg) console.log(msg); 212 if(dbg) console.log(res); 213 214 if( url == '/api/v2/organizations.json' ){ 215 organization_token = res.data.organizations[0]["token"]; 216 $('#organization_needed').fadeIn("slow"); 217 $('#organization_name').text(res.data.organizations[0]["name"]); 218 }else if ( msg == '作品一覧取得'){ 219 product_token = res.data.products[0]["token"] 220 }else if (msg == 'エピソード一覧取得'){ 221 episode_token = res.data.episodes[0]["token"] 222 }else if (msg == 'カット一覧取得'){ 223 cut_token = res.data.cuts[0]["token"] 224 } 225 226 227 }, 228 beforeSend: setHeader 229 }); 230 } 231 232 /** 233 認証手続きはサービスノードのメソッド ノード自身が認証と必要なデータの記録を行う 234 パスワードは記録しない 235 認証毎にパスワードをユーザに要求する 236 myService.authorize() 237 パスワードとUIDは、ページ上のフォームから読む 238 */ 239 ServiceNode.prototype.authorize=function(callback){ 240 if(dbg) console.log("authorize::execute"); 241 var noW =new Date(); 242 var myUserId = document.getElementById('current_user_id').value; 243 var myPassword = document.getElementById('current_user_password').value; 244 if ((myUserId.length<1) || (myPassword.length<1)) return false; 245 var data = { 246 username: myUserId, 247 password: myPassword, 248 client_id: this.client_id, 249 client_secret: this.client_secret, 250 grant_type: 'password' 251 }; 252 var oauthURL=serviceAgent.currentServer.url+"/oauth/token.json";//.split('/').slice(0,3).join('/'); 253 if(dbg) console.log(oauthURL); 254 $.ajax({ 255 type: "POST", 256 url: oauthURL, 257 data: data, 258 success : function(result) { 259 //console.log(serviceAgent.currentServer.name + ": success") 260 //console.log(result.access_token) 261 $('#server-info').attr('oauth_token' , result.access_token); 262 $('#server-info').attr('last_authrized' , new Date().toString()); 263 serviceAgent.authorized('success'); 264 serviceAgent.currentServer.getRepositories(callback); 265 }, 266 error : function(result) { 267 /** 268 認証失敗 エラーメッセージ表示 トークンと必要情報をクリアして表示を変更する 269 */ 270 alert(localize(nas.uiMsg.dmAlertFailAuthorize)); 271 $('#server-info').attr('oauth_token' , ''); 272 $('#server-info').attr('last_authrized' , ''); 273 serviceAgent.authorized('false'); 274 } 275 }); 276 } 277 /** @undocumented 278 errorhandle 279 */ 280 ServiceNode.prototype.errorhandle=function(obj){ 281 console.log(obj); 282 return; 283 } 284 /** 285 リポジトリ(TEAM)一覧を取得してUIを更新する 286 287 */ 288 ServiceNode.prototype.getRepositories=function(callback){ 289 // console.log(serviceAgent.currentServer.setHeader); 290 var myURL = serviceAgent.currentServer.url + '/api/v2/organizations.json'; 291 //console.log(myURL); 292 $.ajax({ 293 url : myURL, 294 type : 'GET', 295 dataType : 'json', 296 success : function(result) { 297 // if(result.res != "200"){this.errorhandle(result);}else{}; 298 // result replace result.data 299 serviceAgent.repositories.splice(1); // ローカルリポジトリを残してクリア(要素数1) 300 //console.log(result); 301 for( var rix=0 ; rix<result.data.organizations.length ; rix ++){ 302 serviceAgent.repositories.push(new NetworkRepository( 303 result.data.organizations[rix].name, 304 serviceAgent.currentServer 305 )); 306 serviceAgent.repositories[serviceAgent.repositories.length - 1].token = result.data.organizations[rix].token; 307 if(result.data.organizations[rix].owner_name){;//オーナ情報が全てのサーバにに行き渡るまでは判定して避ける 308 serviceAgent.repositories[serviceAgent.repositories.length - 1].owner = new nas.UserInfo( 309 result.data.organizations[rix].owner_name, 310 {'token':result.data.organizations[rix].owner_token} 311 ); 312 }else{ 313 serviceAgent.repositories[serviceAgent.repositories.length - 1].owner = new nas.UserInfo(); 314 };// 315 }; 316 var myContents=""; 317 myContents += '<option selected value=0> = local Repository =</option>' ; 318 for(var idr=1; idr < serviceAgent.repositories.length;idr ++){ 319 myContents +='<option value="'+idr+'" >'+serviceAgent.repositories[idr].name+'</option>'; 320 }; 321 document.getElementById('repositorySelector').innerHTML = myContents; 322 document.getElementById('repositorySelector').disabled = false; 323 if(callback instanceof Function){setTimeout(callback,10)}; 324 }, 325 error : function(result){ 326 //console.log("getRepositories::fail"); 327 //console.log(JSON.stringify(result)); 328 }, 329 beforeSend: serviceAgent.currentServer.setHeader 330 }); 331 } 332 /* 333 履歴構造の実装には、XPSのデータを簡易パースする機能が必要 334 プロパティを取得するのみ? 335 336 サーバは自身でXPSをパースしない 337 338 アプリケーションがパースした情報を識別情報として記録してこれを送り返す 339 340 (タイトル)[##№](番号)[(サブタイトル)]//S##C####(##+##)/S##C####(##+##)/S##C####(##+##)/不定数…//lineID//stageID//jobID//documentStatus 341 例: 342 ももたろう#SP-1[鬼ヶ島の休日]//SC123 ( 3 + 12 .)//0//0//1//Hold 343 344 タイトル/話数/サブタイトル/カット番号等の文字列は、少なくともリポジトリ内/そのデータ階層でユニークであることが要求される 345 例えば現存のタイトルと同じと判別されるタイトルが指定された場合は、新規作品ではなく同作品として扱う 346 似ていても、別のタイトルと判別された場合は別作品として扱われるので注意 347 348 *判定時に 349 350 タイトル内のすべての空白を消去 351 半角範囲内の文字列を全角から半角へ変換 352 連続した数字はparseInt 353 354 等の処置をして人間の感覚に近づける操作を行う(比較関数必要) 355 356 357 ラインID ステージID 及びジョブIDはカット(管理単位)毎の通番 同じIDが必ずしも同種のステージやジョブを示さない。 358 管理工程の連続性のみが担保される 359 識別子に管理アイテム識別文字列を加えても良い 360 361 第4要素は作業状態を示す文字列 362 363 例: 364 0//0//0//Stratup 365 0:本線//1:レイアウト//2:演出検査//Active 366 367 ラインID 368 ラインが初期化される毎に通番で増加 整数 369 0 本線trunkライン 370 1 本線から最初に分岐したライン 371 1-1 ライン1から分岐したライン 372 2 本線から分岐した2番めのライン 373 374 ステージID 375 各ラインを結んで全通番になる作業ステージID 376 0//0 377 0//1 378 0//2 1//2 379 0//3 1//3 380 381 ジョブID 382 ステージごとに初期化される作業ID 383 0//0//0 384 0//0//1 385 0//0//2 386 0//1//0 387 0//1//1 388 389 ステータス 390 作業状態を表すキーワード 391 Startup/Active/Hold/Fixed/Aborted (開始/作業/保留/終了/削除) の5態 392 floating/Finished (浮動/完了) の2態を追加 393 394 エントリの識別子自体にドキュメントの情報を埋め込めばサーバ側のパースの必要がない。 395 ファイルシステムや一般的なネットワークストレージ、キー/値型のDBをリポジトリとして使う場合はそのほうが都合が良い 396 管理DBの支援は受けられないが、作業の管理情報が独立性を持ち、アプリケーションからの管理が容易 397 398 ステータスは それぞれのキーワードで始まり サブプロパティを含む 399 400 Startup:{asignment:yuid,message:text} 401 402 //現状 403 var myXps= XPS; 404 [encodeURIComponent(myXps.title)+"#"+encodeURIComponent(myXps.opus)+"["+encodeURIComponent(myXps.subtitle)+"]",encodeURIComponent("S"+((myXps.scene)?myXps.scene:"-")+"C"+myXps.cut)+"("+myXps.time()+")",myXps.xMap.currentLine,myXps.xMap.currentStage,myXps.xMap.currentJob].join(" // "); 405 //将来は以下で置き換え予定 CSオブジェクト未実装 406 myXps.sci.getIdentifier(); 407 //Xpsオブジェクトのクラスメソッドとして仮実装済み オブジェクトメソッドとして同名の機能の異なる関数があるので要注意 408 Xps.getIdentifier(myXps); 409 410 */ 411 /** 412 比較関数 管理情報 3要素の管理情報配列 issuesを比較して先行の管理ノード順位を評価する関数 413 ライン拡張時は追加処理が必要 414 */ 415 issuesSorter =function(val1,val2){ 416 if(typeof val1 == 'undefined'){ return -1 } 417 if(typeof val2 == 'undefined'){ return 1 } 418 419 return (parseInt(String(val1[0]).split(':')[0]) * 10000 + parseInt(String(val1[1]).split(':')[0]) * 100 + parseInt(String(val1[2]).split(':')[0])) - ( parseInt(String(val2[0]).split(':')[0]) * 10000 + parseInt(String(val2[1]).split(':')[0]) * 100 + parseInt(String(val2[2]).split(':')[0])); 420 }; 421 422 /** 423 ソート比較関数 424 カット番号(文字列内の最初の整数クラスタ)を整数化して比較 425 */ 426 numSorter =function(val1,val2){ return (nas.parseNumber(val1) - nas.parseNumber(val2))}; 427 428 /** 429 listEntry オブジェクト 430 初期化引数:カット識別子[タイトルID,話数ID,カットID] 431 432 タイトルID、話数IDは将来的にタイトル話数エントリへのアクセスキーを入力 433 カットIDは自身のDBエントリへのアクセスキーを設定する 434 現在は省略可だがDB整備され次第必須 435 436 ローカルリポジトリの場合はそれぞれのエントリのキーを省略なしに入力 437 ドキュメントリストにエントリされるオブジェクト 438 parent リポジトリへの参照 439 product 作品と話数 440 sci カット番号(兼用情報含む) 441 issues 管理情報 4要素一次元配列 [line,stage,job,status] 442 実際のデータファイルはissueごとに記録される 443 いずれも URIエンコードされた状態で格納されているので画面表示の際は、デコードが必要 444 issues には オリジナル(初期化時)の識別子を保存する 445 ネットワークリポジトリに接続する場合は以下のプロパティが設定される 446 listEntry.titleID /string token 447 listEntry.episodeID /string token 448 listEntry.issues[#].cutID /string token 449 listEntry.issues[#].versionID /string token 450 451 オブジェクトメソッド 452 listEntry.toString(Index) 453 listEntry.push(Identifier) 454 listEntry.getStatus() 455 456 listEntry は listEntryCollection に格納される 457 listEntryCollection はデフォルトで this.parent.entryListとして参照される。 458 */ 459 listEntry=function(myIdentifier){ 460 this.dataInfo = Xps.parseIdentifier(myIdentifier);//dataInfoそのものを拡張すればプロパティが不要となる? 461 this.parent;//初期化時にリポジトリへの参照を設定 462 this.product = encodeURIComponent(this.dataInfo.product.title)+"#"+encodeURIComponent(this.dataInfo.product.opus); 463 this.sci = encodeURIComponent(this.dataInfo.sci[0].cut); 464 if(typeof this.dataInfo.line == 'undefined'){ 465 //識別子にバージョン情報が含まれない場合は初期バーションで補填(nullとかのほうが良いかも) 466 this.issues = [[ 467 new XpsLine(nas.pmdb.pmTemplate.members[0].line).toString(true), 468 new XpsStage(nas.pmdb.pmTemplate.members[0].stages[0]).toString(true), 469 new XpsStage(nas.pmdb.jobNames.getTemplate(nas.pmdb.pmTemplate.members[0].stages[0],"init")[0]).toString(true), 470 "Startup" 471 ]]; 472 }else{ 473 this.issues = [[ 474 encodeURIComponent(this.dataInfo.line.toString(true)), 475 encodeURIComponent(this.dataInfo.stage.toString(true)), 476 encodeURIComponent(this.dataInfo.job.toString(true)), 477 this.dataInfo.currentStatus.toString(true) 478 ]]; 479 } 480 this.issues[0].identifier=myIdentifier; 481 this.issues[0].time=nas.FCT2Frm(this.dataInfo.sci[0].time); 482 if(arguments.length>1) { 483 this.titleID = arguments[1]; 484 this.episodeID = arguments[2]; 485 this.issues[0].cutID = arguments[3]; 486 this.issues[0].versionID = null; 487 } 488 } 489 /** 490 エントリは引数が指定されない場合、管理情報を除いたSCI情報分のみを返す 491 引数があれば引数分の管理履歴をさかのぼって識別子を戻す 492 このメソッド全体がIssues配列の並びが発行順であることを期待している 493 リスト取得の際にソートをかけることで解決 494 ライン拡張後はソートで解決できなくなるので要注意 495 方針としては、各ラインをまたがずに開始点まで遡れるように設定する 496 */ 497 listEntry.prototype.toString=function(myIndex){ 498 if(typeof myIndex == "undefined"){myIndex = -1;} 499 if(myIndex < 0){ 500 return [this.product,this.sci].join("//"); 501 }else{ 502 if(myIndex<this.issues.length){ 503 return this.issues[this.issues.length - 1 - myIndex].identifier; 504 // return [this.product,this.sci].join("//")+"//"+ this.issues[this.issues.length - 1 - myIndex].join("//"); 505 //この部分の手続はラインをまたぐと不正な値を戻すので要修正 11.23 506 }else{ 507 return this.issues[this.issues.length - 1].identifier; 508 // return [this.product,this.sci].join("//")+"//"+ this.issues[this.issues.length - 1].join("//"); 509 } 510 } 511 } 512 /** 513 */ 514 listEntry.prototype.dumpIssues=function(form){ 515 var myResult=""; 516 switch(form){ 517 case 'html': 518 break; 519 case 'dump': 520 default: 521 for (var idx=0;idx < this.issues.length ;idx++){ 522 myResult += decodeURIComponent(this.issues[idx].toString()); 523 myResult += '\n'; 524 } 525 } 526 return myResult; 527 } 528 /** 529 識別子を引数にして管理情報をサブリストにプッシュする 530 管理情報のみが与えられた場合は無条件で追加 531 フルサイズの識別子が与えられた場合は SCI部分までが一致しなければ操作失敗 532 追加成功時は管理情報部分を配列で返す 533 534 535 SCI部分のみでなく ラインとステージが一致しないケースも考慮すること(今回の実装では不用) 536 537 ネットワークリポジトリ・DB接続用にIDを増設 538 */ 539 listEntry.prototype.push=function(myIdentifier){ 540 if(Xps.compareIdentifier(this.issues[0].identifier,myIdentifier) < 1){return false;} 541 var dataInfo=Xps.parseIdentifier(myIdentifier); 542 if(dataInfo.currentStatus){ 543 var issueArray = [ 544 encodeURIComponent(dataInfo.line.toString(true)), 545 encodeURIComponent(dataInfo.stage.toString(true)), 546 encodeURIComponent(dataInfo.job.toString(true)), 547 dataInfo.currentStatus.toString(true) 548 ]; 549 }else{ 550 var issueArray = []; 551 } 552 issueArray.identifier=myIdentifier; 553 issueArray.time=nas.FCT2Frm(dataInfo.sci[0].time); 554 if(arguments.length>1) { 555 // this.titleID = arguments[1]; 556 // this.episodeID = arguments[2]; 557 issueArray.cutID = arguments[3]; 558 issueArray.versionID = arguments[4]; 559 } 560 for (var iid = 0 ; iid < this.issues.length ; iid ++ ){ 561 if(this.issues[iid].join('//')==issueArray.join('//')) return false; 562 } 563 this.issues.push(issueArray); 564 this.issues.sort(issuesSorter); 565 return this.issues; 566 } 567 /** 568 A=new listEntry("%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:trunk//1:layout//1://"); 569 A 570 */ 571 /** 572 エントリのステータスを取得する 573 記録位置は、最終ジョブ 574 エントリにステータスを設定する機能は設けない 575 と、思ったけどやはり設定機能を作る 576 新規の状況更新はすべてリポジトリ本体からの再読出で行う 577 リポジトリ本体からの読み出しは冗長にすぎる 578 戻り値をオブジェクトに変更 0809 579 */ 580 listEntry.prototype.getStatus=function(){ 581 var currentStatusDescription = this.issues[this.issues.length-1][3]; 582 if((! currentStatusDescription)&&(this.issues[this.issues.length-1].identifier)){ 583 var currenEntryInfo = Xps.parseIdentifier(this.issues[this.issues.length-1].identifier); 584 return currenEntryInfo.currentStatus; 585 } 586 return new JobStatus(currentStatusDescription); 587 } 588 /** 589 エントリのステータスを設定する 590 記録対象は最終ジョブのエントリ 591 先のデータによって設定可能データは制限される 592 管理権限がある場合はAbortedに変更可能 593 いったんAbortedになったエントリは基本的に変更不可 594 Startup > Active 595 Active > Hold/Fixed:assignment:comment 596 Hold > Active 597 Fixed > Active/Aborted(要権限) 598 599 フロート化・シンクの >> サインは状態の遷移ではなくコピーして登録であり。 600 逆方は、全てのステータスからの複製が可能 601 移行時にもともとのステータスは保存されない 602 603 現状 >> 遷移先 > 遷移後のサーバ上のデータのステータス 604 Float >> Startup:assignment:comment/Fixed:assignment:comment > (元データはサーバ上には無い) 605 Startup >>Float > 変わらず 606 Active >>Float > Hold 607 Hold >>Float > 変わらず 608 Fixed >>Float > 変わらず 609 610 ドキュメントはFloat化する際に必ず複製されて安定化遷移を行う。 611 リポジトリ上には決してFloat状態のエントリを持たない 612 エラー等により、Float状態のデータをリポジトリ上に確認した場合は、同ジョブのStartup、またはFixed状態に自動で遷移する? 613 614 戻り値は現在のステータス 615 ステータスオブジェクトが多分必要 616 あとswitch文でない方がヨサゲ 617 必要に従ってissuesを更新または追加する 618 Jobが進まないときは更新 619 Jobが進む際に追加 ただし追加時は listEntry.push(Idf)で追加なので注意 620 まだステータスの副次情報は実装しないので配列のまま保存しないように注意 621 ステータスを複合オブジェクト JobStatusとして実装0809 622 623 624 issues.identifier/.time の設定が抜けている 2017.0429 早急に要修正!!!!! 625 timeは基本的に変更が無いがidentifierは, 626 statusの変更に従って必ず変わる 627 setStatusの引数がJobStatus であれば変換は行わない 628 629 引数にFloatステータスが入った場合は不正引数とする 630 サーバ上のエントリのステータスがFloatになることは無い 631 */ 632 listEntry.prototype.setStatus=function(myStatus){ 633 var currentIssue = this.issues[this.issues.length-1]; 634 // var currentStatus = currentIssue[3].split(":"); 635 var currentStatus = new JobStatus(currentIssue[3]);//オブジェクト化 636 if(myStatus instanceof JobStatus){ 637 var newStatus = myStatus; 638 }else{ 639 var newStatus = new JobStatus(myStatus);//オブジェクト化 640 } 641 if (newStatus.content.indexOf("Float")>=0){return false;} 642 if (currentStatus.content=="Hold"){ 643 switch (newStatus.content){ 644 case "Active": 645 currentIssue[3] = newStatus.toString(true); 646 currentIssue.identifier=currentIssue.identifier.replace(/\/\/Hold.*$/,"//"+currentIssue[3]); 647 break; 648 case "Hold": 649 case "Fixed": 650 case "Aborted": 651 default: 652 return new JobStatus(currentIssue[3]); 653 } 654 } else if(currentStatus.content=="Startup"){ 655 switch (newStatus.content){ 656 case "Active": 657 this.push(currentIssue.slice(0,3).concat(newStatus.toString(true)).join("//")); 658 this.issues[this.issues.length-1].identifier=currentIssue.identifier.replace(/\/\/Startup.*$/,"//"+newStatus.toString(true)); 659 660 this.issues[this.issues.length-1].time=currentIssue.time; 661 break; 662 case "Hold": 663 case "Fixed": 664 case "Aborted": 665 default: 666 return new JobStatus(currentIssue[3]); 667 } 668 } else if(currentStatus.content=="Active"){ 669 switch (newStatus.content){ 670 case "Hold": 671 case "Fixed": 672 currentIssue[3] = newStatus.toString(true); 673 currentIssue.identifier=currentIssue.identifier.replace(/\/\/Active.*$/,"//"+currentIssue[3]); 674 break; 675 case "Active": 676 case "Aborted": 677 default: 678 return new JobStatus(currentIssue[3]); 679 } 680 } else if(currentStatus.content=="Aborted"){ 681 switch (newStatus.content){ 682 case "Hold": 683 case "Fixed": 684 case "Active": 685 case "Aborted": 686 default: 687 return currentStatus; 688 } 689 } else if(currentStatus.content=="Fixed"){ 690 switch (newStatus.content){ 691 case "Active": 692 currentIssue[3] = newStatus.toString(true); 693 currentIssue.identifier=currentIssue.identifier.replace(/\/\/Fixed.*$/,"//"+currentIssue[3]); 694 break; 695 case "Hold": 696 case "Fixed": 697 case "Aborted": 698 default: 699 return new JobStatus(currentIssue[3]); 700 } 701 } 702 if(dbg) console.log(currentIssue[3]); 703 return new JobStatus(currentIssue[3]); 704 } 705 706 /** 707 エントリが自分自身を削除する。 708 parentが存在しない場合は削除に失敗する 709 */ 710 listEntry.prototype.remove=function(){ 711 if(! this.parent) return false; 712 for (var ix=0;ix<this.parent.entryList.length;ix++){ 713 if(this.parent.entryList[ix].issues[0].cutID == this.issues[0].cutID){ 714 this.parent.entryList.splice(ix,1); 715 return true; 716 }; 717 } 718 //この下実行されない…はず されたらヤダ 719 //console.log(this); 720 //console.log(this.parent.entryList.length); 721 return false; 722 } 723 /** 724 listEntryから識別子を抽出するメソッド 725 自己の情報を組み上げて最も正しいと思われる識別子で戻す 726 */ 727 listEntry.prototype.getIdentifier=function(issueOffset){ 728 if(typeof issueOffset == 'undefined') issueOffset =-1; 729 var myTitle = this.parent.title (this.titleID); 730 var myOpus = this.parent.opus (this.episodeID); 731 732 var myResult = [ 733 encodeURIComponent(myTitle.name), 734 '#',encodeURIComponent(myOpus.name),'[',encodeURIComponent(myOpus.description),']//', 735 this.dataInfo.cut,'(',this.dataInfo.time,')' 736 ].join(''); 737 if(issueOffset>=0){ 738 if (issueOffset > (this.issues.length-1)) issueOffset = (this.issues.length-1); 739 var targetIssue = this.issues[this.issues.length-1-issueOffset]; 740 myResult+='//'+targetIssue.join('//'); 741 } 742 return myResult; 743 } 744 /** 745 エントリリストコレクション 746 配列ベースで以下のメソッドを持つ 747 748 .put(entry) ;エントリ追加 749 .remove(idf) ;idf指定でエントリ削除 750 .getByIdf(idf) ;idf指定でエントリを返す 751 .getByToken(token) ;ネットワークのみ 752 */ 753 function listEntryCollection (){ 754 /* 755 コレクションにエントリを追加する 756 同識別子のエントリが存在する場合は上書き(置換) 757 存在しなかった場合は新規に追加する 758 */ 759 this.put=function (myEntry){ 760 for (var ix = 0 ; ix < this.length ; ix ++){ 761 if(this[ix].toString().split('//')[0] != myEntry.toString().split('//')[0]) continue; 762 if (Xps.compareIdentifier(this[ix].toString(true),myEntry.toString(true)) >= 1 ) { 763 this[ix]=myEntry; 764 return myEntry; 765 } 766 } 767 return this.push(myEntry); 768 } 769 /* 770 識別子指定でコレクションからエントリを削除する 771 存在しなかった場合はfalse 772 */ 773 this.remove=function (myIdentifier){ 774 for (var ix = 0 ; ix < this.length ; ix ++){ 775 if(String(this[ix]).split('//')[0] != myIdentifier.split('//')[0]) continue; 776 if (Xps.compareIdentifier(this[ix].toString(true),myIdentifier) >= 1 ) { 777 return this.splice(ix,1); 778 } 779 } 780 return false; 781 } 782 /* 783 識別子指定でエントリを取得 784 第二引数で一致レベルを指定 785 指定がない場合は、カットNo一致 786 -2 <NO-match> 787 -1 title 788 0 opus (プロダクト一致) 789 1 カットNo 790 2 ライン 791 3 ステージ 792 4 ジョブ 793 Repository.entry の基底メソッド 794 */ 795 this.getByIdf=function (myIdentifier,opt){ 796 if(typeof opt == 'undefined') opt = 1; 797 for (var ix = 0 ; ix < this.length ; ix ++){ 798 // 高速化スキップは文字列比較だと取りこぼしが多いので禁止 それよりはcompareIdentifier自体を高速化すること 799 if (Xps.compareIdentifier(this[ix].toString(true),myIdentifier) >= opt ) return this[ix]; 800 } 801 return null; 802 } 803 /* 804 トークンでエントリを取得 805 バージョンの指定は不能 806 */ 807 this.getByToken=function (myToken){ 808 for (var ix = 0 ; ix < this.length ; ix ++){ 809 if (this[ix].issues[0].cutID == myToken) return this[ix]; 810 } 811 return null; 812 } 813 }; 814 listEntryCollection.prototype = Array.prototype; 815 /** 816 ローカルリポジトリ 817 主に最近の作業データをキャッシュする役目 818 カットのデータを履歴付きで保持できる 819 複数カットを扱う 制限カット数内のリングバッファ動作 820 xUIから見るとサーバの一種として働く 821 ローカルストレージを利用して稼働する 822 823 保存形式 824 info.nekomataya.remaping.dataStore 825 内部にオブジェクト保存 826 リポジトリのデータ取得メソッド 827 Repository.title(myIdentifier) 828 Repository.opus(myIdentifier) 829 Repository.cut(myIdentifier) 830 Repository.entry(myIdentifier) 831 832 productsData追加 833 プロダクトデータは DBに直接接続して情報ストアするオブジェクト 834 JSONで通信を行う場合に必須 835 entryList(listEntryコレクション)はこのデータから生成するように変更される? 836 またはentryListからproductsDataを生成する 同時か? 837 動作試験のため maxEntryを増やしてある 10>32 170705 838 */ 839 localRepository={ 840 name:'localStrageStore', 841 url:'localStorage:', 842 owner:new nas.UserInfo(), 843 // owner:xUI.currentUser, 844 // currentProduct:"", 845 // currentSC:"", 846 // currentLine:"", 847 // currentStage:"", 848 // currentJob:"", 849 productsData:[], 850 entryList:new listEntryCollection(), 851 keyPrefix:"info.nekomataya.remaping.dataStore.", 852 maxEntry:32 853 }; 854 /** 855 TITLE取得 856 引数: 857 myIdentifier 識別子またはトークン 858 searchDepth 検索深度 0:タイトルのみ 1:エピソードからもタイトルを探す 2:カットからも 859 860 エピソードやカットのトークンからもタイトルノードを返す 861 深度指定省略時は 0 862 該当するオブジェクトがない場合はnullを戻す 863 */ 864 _title=function(myIdentifier,searchDepth){ 865 if(! searchDepth) searchDepth = 0; 866 var myIdf= Xps.parseIdentifier(myIdentifier); 867 for ( var idx = 0 ;idx <this.productsData.length;idx ++){ 868 if( 869 (myIdf.title == this.productsData[idx].name)|| 870 (myIdentifier == this.productsData[idx].token) 871 ) return this.productsData[idx]; 872 if((searchDepth > 0)&&(this.productsData[idx].episodes)){ 873 for(var epx = 0 ;epx <this.productsData[idx].episodes[0].length;epx++){ 874 if( 875 (myIdf.opus == this.productsData[idx].episodes[0][epx].name)|| 876 (myIdentifier == this.productsData[idx].episodes[0][epx].token) 877 ) return this.productsData[idx]; 878 } 879 if(searchDepth >1){ 880 for(var ctx = 0 ;ctx <this.productsData[idx].episodes[0][epx].cuts[0].length;ctx++){ 881 if( 882 (myIdf.sci[0].cut == this.productsData[idx].episodes[0][epx].cuts[0][ctx].name)|| 883 (myIdentifier == this.productsData[idx].episodes[0][epx].cuts[0][ctx].token) 884 ) return this.productsData[idx]; 885 } 886 } 887 } 888 }; 889 return null; 890 } 891 892 localRepository.title=_title; 893 /** 894 OPUS取得 895 引数: 896 myIdentifier 識別子またはトークン 897 898 識別子またはトークンからエピソードノードを戻す 899 該当するオブジェクトがない場合はnullを戻す 900 */ 901 _opus=function(myIdentifier,searchDepth){ 902 //console.log([myIdentifier,searchDepth]) 903 if(! searchDepth) searchDepth = 0; 904 var currentOpus = Xps.parseProduct(myIdentifier); 905 var isTkn = ((currentOpus.opus =='')&&(currentOpus.title == myIdentifier))? true:false; 906 //console.log([searchDepth,currentOpus,isTkn]) 907 for ( var idx = 0 ;idx <this.productsData.length;idx ++){ 908 if( 909 ((! isTkn ) && 910 (String(currentOpus.title).indexOf(this.productsData[idx].name) < 0))|| 911 (! this.productsData[idx].episodes ) 912 ) continue; 913 for (var eid = 0 ;eid < this.productsData[idx].episodes[0].length; eid ++){ 914 if ( 915 (currentOpus.opus == this.productsData[idx].episodes[0][eid].name)|| 916 (myIdentifier == this.productsData[idx].episodes[0][eid].token) 917 ) return this.productsData[idx].episodes[0][eid]; 918 }; 919 }; 920 return null; 921 } 922 923 localRepository.opus=_opus; 924 /** 925 CUT取得 926 myIdentifier は識別子またはトークンからカットノードを戻す 927 */ 928 _cut=function(myIdentifier){ 929 var target = Xps.parseIdentifier(myIdentifier); 930 var isTkn = ((target.cut =='')&&(target.title == myIdentifier))? true:false; 931 //console.log([myIdentifier,target,isTkn]); 932 //console.log(this.productsData) 933 for ( var idx = 0 ;idx <this.productsData.length;idx ++){ 934 if( 935 (! this.productsData[idx].episodes )||( 936 (! isTkn )&& 937 (String(target.title).indexOf(this.productsData[idx].name) < 0) 938 ) 939 ) continue; 940 //console.log(this.productsData[idx].episodes[0]); 941 for (var eid = 0 ;eid < this.productsData[idx].episodes[0].length; eid ++){ 942 if ( 943 (! this.productsData[idx].episodes[0][eid].cuts )||( 944 (! isTkn ) && 945 (String(target.opus).indexOf(this.productsData[idx].episodes[0][eid].name) < 0) 946 ) 947 ) continue; 948 //console.log(this.productsData[idx].episodes[0][eid].cuts[0]); 949 for (var cid = 0 ; cid < this.productsData[idx].episodes[0][eid].cuts[0].length ; cid ++) { 950 if ( 951 (Xps.compareCutIdf(target.sci[0].cut,this.productsData[idx].episodes[0][eid].cuts[0][cid].name))|| 952 (myIdentifier == this.productsData[idx].episodes[0][eid].cuts[0][cid].token) 953 ) return this.productsData[idx].episodes[0][eid].cuts[0][cid]; 954 }; 955 }; 956 }; 957 return null; 958 } 959 960 localRepository.cut=_cut; 961 962 /** 963 プロダクト(タイトル)データを更新 964 タイトル一覧をクリアして更新する エピソード更新を呼び出す 965 受信したデータを複合させてサービス上のデータ構造を保持する単一のオブジェクトに 966 getXx で概要(一覧)を取得 967 xxUpdateが詳細を取得して this.productsData を上書きしてゆく 968 プロダクト詳細は、各個に取得するように変更 969 引き続きの処理を行う際はコールバック渡し 970 コールバックがない場合は、全プロダクトの詳細を取得? 971 プロダクトデータ取得のみの場合は 空動作のコールバックを渡す必要あり 972 myToken 引数がある場合はtokenが一致したエントリのみを処理する 973 myToken は配列でも良い 974 */ 975 localRepository.getProducts=function(callback,callback2,myToken){ 976 if(typeof myToken == 'undefined') myToken =[]; 977 if(!(myToken instanceof Array)) myToken = [myToken]; 978 try{ 979 var keyCount=localStorage.length; 980 for (var kid=0;kid<keyCount;kid++){ 981 if(localStorage.key(kid).indexOf(this.keyPrefix)==0){ 982 var currentIdentifier=localStorage.key(kid).slice(this.keyPrefix.length); 983 //タイトルリストにすでに登録されているか検査 未登録エントリをDBに追加 984 //token指定がある場合は、登録タイトルを抹消して新しい情報で上書き? 985 var currentTitle = this.title(currentIdentifier); 986 if(! currentTitle){ 987 // console.log(currentIdentifier); 988 if((myToken.indexOf(localStorage.key(kid)) >= 0)||(! myToken.length)){ 989 var myData=Xps.parseIdentifier(currentIdentifier); 990 localRepository.productsData.push({ 991 token:localStorage.key(kid), 992 name:myData.title, 993 description:"", 994 created_at:null, 995 updated_at:null, 996 episodes:[[]] 997 }); 998 }}; 999 }; 1000 }; 1001 if(callback instanceof Function){ 1002 callback(); 1003 }else{ 1004 //console.log('get Episodes###') 1005 for(var ix =0;ix < localRepository.productsData.length; ix ++){ 1006 //console.log(this.productsData[ix].token) 1007 this.getEpisodes(false,false,this.productsData[ix].token); 1008 } 1009 }; 1010 }catch(err){ 1011 if(callback2 instanceof Function){callback2();} 1012 } 1013 } 1014 /** 1015 opusデータ更新 1016 引数:成功時コールバック,失敗時コールバック,タイトルキー 1017 myOpusToken 引数がある場合は、引数で制限された処理を行う 1018 */ 1019 localRepository.getEpisodes=function(callback,callback2,myProductToken,myOpusToken){ 1020 var allOpus =false 1021 if(typeof myOpusToken == 'undefined'){ 1022 myOpusToken = []; 1023 allOpus = true; 1024 var myProduct=this.title(myProductToken); 1025 //console.log(myProduct); 1026 if(! myProduct){console.log('stop'); return false;} 1027 for (var px = 0 ;px < myProduct.episodes[0].length;px ++){myOpusToken.push(myProduct.episodes[0][px].token);} 1028 } 1029 if(!(myOpusToken instanceof Array)) myOpusToken = [myOpusToken]; 1030 //console.log(myOpusToken); 1031 //console.log(documentDepot.currentProduct); 1032 try{ 1033 var myProduct=localRepository.title(myProductToken); 1034 var keyCount = localStorage.length; 1035 for (var kid = 0;kid < keyCount; kid++){ 1036 //console.log(myProduct.name); 1037 if(localStorage.key(kid).indexOf(this.keyPrefix)==0){ 1038 var currentIdentifier=localStorage.key(kid).slice(this.keyPrefix.length); 1039 var myData = Xps.parseIdentifier(currentIdentifier); 1040 if(myData.title != myProduct.name) continue;//タイトル違いを排除 1041 //OPUSリストにすでに登録されているか検査 未登録エントリはDBに追加 tokenは初出のkey 1042 var currentOpus = localRepository.opus(currentIdentifier); 1043 if(! currentOpus){ 1044 if((! myOpusToken.length)||(myOpusToken.indexOf(localStorage.key(kid)) >= 0)){ 1045 var Ex = myProduct.episodes[0].push({ 1046 token:localStorage.key(kid), 1047 name:myData.opus, 1048 description:myData.subtitle, 1049 created_at:null, 1050 updated_at:null, 1051 cuts:[[]] 1052 }); 1053 currentOpus = myProduct.episodes[0][Ex-1]; 1054 if(!(callback instanceof Function)){ 1055 localRepository.getSCi(false,false,currentOpus.token); 1056 }; 1057 }}; 1058 }; 1059 }; 1060 //エピソード1取得毎に実行したほうが良いかも? 1061 //このままだと必ずタイトル内の全エピソード取得になる 1062 if(callback instanceof Function){ callback();} 1063 } catch(err) { 1064 if(callback2 instanceof Function){ callback2();} 1065 } 1066 } 1067 /** 1068 エピソード毎にカットリストを取得 1069 エピソード詳細の内部情報にコンバート 1070 引数 1071 myOpusToken ターゲットの話数キー(識別子で与える) 1072 pgNo リストのページID 1 origin 1073 ppg ページごとのエントリ数 1074 */ 1075 localRepository.getSCi=function (callback,callback2,myOpusToken,pgNo,ppg) { 1076 //現在、pgNo,ppgは意味を持たない引数 1077 try{ 1078 var myOpus = this.opus(myOpusToken); 1079 if(! myOpus){console.log('noOpus');return false;} 1080 //console.log('prcessing : '+myOpus.name); 1081 var keyCount=localStorage.length; 1082 for (var kid = 0; kid < keyCount; kid ++){ 1083 if(localStorage.key(kid).indexOf(this.keyPrefix)==0){ 1084 var currentIdentifier=localStorage.key(kid).slice(this.keyPrefix.length); 1085 var myData = Xps.parseIdentifier(currentIdentifier); 1086 if(myOpus.name != myData.opus) continue; 1087 var myCut = this.cut(currentIdentifier); 1088 var currentEntry= this.entry(currentIdentifier); 1089 if(myCut){ 1090 //登録済みカットなのでissues追加 1091 //console.log("push version :" + decodeURIComponent(currentIdentifier)); 1092 myCut.versions.push({ 1093 updated_at:null, 1094 description:currentIdentifier, 1095 version_token:localStorage.key(kid) 1096 }); 1097 if(currentEntry){ 1098 //登録済みプロダクトなのでエントリに管理情報を追加 1099 currentEntry.push(currentIdentifier); 1100 }else{ 1101 //情報不整合 1102 } 1103 }else{ 1104 //未登録カット 新規登録 1105 //エントリが既に登録済みなので不整合 消去 1106 if(currentEntry) currentEntry.remove(); 1107 //console.log("add :: "+decodeURIComponent(currentIdentifier)); 1108 var myCut = myOpus.cuts[0].push({ 1109 token:localStorage.key(kid), 1110 name:myData.cut, 1111 description:currentIdentifier, 1112 created_at:null, 1113 updated_at:null, 1114 versions:[{ 1115 updated_at:null, 1116 description:currentIdentifier, 1117 version_token:localStorage.key(kid) 1118 }] 1119 }); 1120 //未登録新規プロダクトなのでエントリ追加 1121 //ここにローカルストレージのキーIDを置く タイトルとエピソードの情報取得キーは現在エントリなし 1122 //初出エントリのキーか? 0524 1123 var newEntry = new listEntry(currentIdentifier,null,null,localStorage.key(kid)); 1124 newEntry.parent = this; 1125 this.entryList.push(newEntry); 1126 } 1127 }; 1128 }; 1129 if(callback instanceof Function){ callback();} 1130 } catch(err) { 1131 if(callback2 instanceof Function){ callback2();} 1132 } 1133 } 1134 /** 1135 getListメソッドは、entryList/productsData の更新を行う 1136 メンバー初期化を行わない 1137 ローカルストレージ内のデータを走査してリストを更新 1138 既に存在するエントリは上書き//新規のエントリは追加//存在しないエントリは削除する 1139 getList関数自体が非同期動作になるように調整 1140 引数: 1141 force /Bool 1142 callback /Function 1143 forceオプションは、引数の統一のために存在する NetworkRepositoryでのみ必要なオプション 1144 localStorageでは意味を持たないダミーオプションとなる 1145 callBack関数が指定された場合 処理終了直前に実行される 存在しない場合は ドキュメントセレクタの更新が行われる 1146 1147 戻値: なし 1148 実際のデータ・エントリリストが必要な場合は、localRepository.entryList を参照すること 1149 */ 1150 localRepository.getList=function(force,callback){ 1151 //console.log('localRepository getList'); 1152 // if(callback instanceof Function){callback();}else{documentDepot.documentsUpdate(this.entryList);} 1153 if(!(callback instanceof Function)){documentDepot.documentsUpdate(this.entryList);} 1154 return; 1155 var keyCount=localStorage.length;//ローカルストレージのキー数を取得 1156 this.entryList.length=0;//配列初期化 1157 for (var kid=0;kid<keyCount;kid++){ 1158 if(localStorage.key(kid).indexOf(this.keyPrefix)==0){ 1159 var currentIdentifier=localStorage.key(kid).slice(this.keyPrefix.length); 1160 //エントリリストにすでに登録されているか検査 1161 var currentEntry = this.entry(currentIdentifier); 1162 if(currentEntry){ 1163 if(dbg) console.log("push issues :" + decodeURIComponent(currentIdentifier)); 1164 //登録済みプロダクトなのでエントリに管理情報を追加 1165 currentEntry.push(currentIdentifier); 1166 }else{ 1167 if(dbg) console.log("add :: "+decodeURIComponent(currentIdentifier)); 1168 //未登録新規プロダクトなのでエントリ追加 1169 var newEntry = new listEntry(currentIdentifier); 1170 newEntry.parent = this; 1171 this.entryList.push(newEntry); 1172 } 1173 } 1174 } 1175 //コールバックがない場合はデフォルト動作としてエントリをドキュメントブラウザに送る 1176 if(callback instanceof Function){ 1177 callback(); 1178 }else{ 1179 documentDepot.documentsUpdate(this.entryList); 1180 } 1181 // return this.entryList.length;//no use 1182 } 1183 /** 1184 ローカルリポジトリにエントリを追加 1185 引数:Xpsオブジェクト 1186 与えられたXpsオブジェクトから識別子を自動生成 1187 識別子にkeyPrefixを追加してこれをキーにしてデータを格納する 1188 ここでステータスの解決を行う? 1189 キーが同名の場合は自動で上書きされるのでクリアは行わない 1190 エントリ数の制限を行う 1191 エントリ数は、キーの総数でなく識別子の第一、第二要素を結合してエントリとして認識する 1192 1193 Floating ステータスが新設 1194 Floating ステータスのドキュメントは書込み不可とする。 1195 リポジトリメソッドに渡す前にステータスの解決を行い適切なステータスを持たせること。 1196 このメソッドはステータス変更をサポートしない。 1197 */ 1198 localRepository.pushEntry=function(myXps,callback,callback2){ 1199 var msg=''; 1200 if(String(myXps.cut).match(/^\s*$/)){ 1201 msg += localize({ 1202 en:"you can't save entry without cutNo.", 1203 ja:"カット番号のないエントリは記録できません。" 1204 }); 1205 }; 1206 if(myXps.currentStatus.content.indexOf('Floating')>=0){ 1207 msg += '\n'+localize({ 1208 en:"you can't save entry of Flating status.", 1209 ja:"Floatingエントリは記録できません。" 1210 }); 1211 } 1212 if(msg.length){ 1213 alert(msg); 1214 return false; 1215 }; 1216 //クラスメソッドで識別子取得 1217 var myIdentifier=Xps.getIdentifier(myXps); 1218 //識別子に相当するアイテムがローカルストレージ内に存在するかどうかを比較メソッドで検査 1219 for (var pid=0;pid<this.entryList.length;pid++){ 1220 if(Xps.compareIdentifier(this.entryList[pid].toString(),myIdentifier) > 3){ 1221 //既存のエントリが有るのでストレージとリストにpushして終了 1222 try{ 1223 this.entryList[pid].push(myIdentifier); 1224 localStorage.setItem(this.keyPrefix+myIdentifier,myXps.toString()); 1225 if (xUI.XPS === myXps){ 1226 xUI.setStored('current'); 1227 sync(); 1228 } 1229 }catch(err){ 1230 if(callback2 instanceof Function){callback2();} 1231 } 1232 sync(); 1233 documentDepot.updateDocumentSelector(); 1234 if(callback instanceof Function){callback();} 1235 return this.entryList[pid]; 1236 }; 1237 }; 1238 // console.log(myXps) 1239 //console.log("既存エントリなし :追加処理"); 1240 //既存エントリが無いので新規エントリを追加 1241 //設定制限値をオーバーしたら、警告する。 OKならばローカルストレージから最も古いエントリを削除して実行 1242 try{ 1243 if ( this.entryList.length >= this.maxEntry ){ 1244 var msg=localize({en:"over limit!\n this entry will remove [%1]\n ok?",ja:"制限オーバーです!\nこのカットを登録するとかわりに[%1]が消去されます。\nよろしいですか?"},decodeURIComponent(this.entryList[0].toString())); 1245 if(confirm(msg)){ 1246 //console.log("removed Item !"); 1247 for (var iid=0; iid < this.entryList[0].issues.length ; iid++ ){ 1248 localStorage.removeItem( this.keyPrefix + this.entryList[0].issues[iid].identifier ); 1249 }; 1250 this.entryList[0].remove();//アイテムメソッドで削除 1251 localStorage.setItem(this.keyPrefix+myIdentifier,myXps.toString()); 1252 this.entryList.put(new listEntry(myIdentifier));//Collectionメソッドで追加 1253 //console.log(this.entryList.length +":entry/max: "+ this.maxEntry) 1254 } 1255 }else{ 1256 localStorage.setItem(this.keyPrefix+myIdentifier,myXps.toString()); 1257 // this.entryList.put(new listEntry(myIdentifier)); 1258 } 1259 }catch(err){ 1260 //console.log('localRepositoty.pushEntry'); 1261 //console.log(err); 1262 if(callback2 instanceof Function){callback2();} 1263 } 1264 sync(); 1265 documentDepot.updateDocumentSelector(); 1266 if(callback instanceof Function){callback();} 1267 return this.entryList[this.entryList.length-1]; 1268 } 1269 1270 /** 1271 識別子を引数にしてリスト内を検索 1272 一致したデータをローカルストレージから取得してXpsオブジェクトで戻す 1273 識別子に管理情報があればそれをポイントして、なければ最も最新のデータを返す 1274 コールバック渡し可能 1275 引数は、Object 1276 読み出し直後は必ず書き込み禁止のモードとなる 1277 */ 1278 localRepository.getEntry=function(myIdentifier,isReference,callback){ 1279 if(typeof isReference == 'undefined'){isReference = false;} 1280 //識別子をパース 1281 var targetInfo = Xps.parseIdentifier(myIdentifier);//根底としてここで解釈に問題が発生している 1282 1283 var myIssue = false; 1284 var refIssue = false; 1285 1286 var myEntry = this.entry(myIdentifier); 1287 if(! myEntry){ 1288 if(dbg) console.log("noProduct : "+ decodeURIComponent(myIdentifier));//プロダクトが無い 1289 return false; 1290 } 1291 if(! targetInfo.currentStatus){ 1292 //引数に管理部分がないので、最新のissueとして補う 1293 var cx = myEntry.issues.length-1;//最新のissue 1294 myIssue = myEntry.issues[cx];//配列で取得 1295 } else { 1296 //指定管理部分からissueを特定する 連結して文字列比較(後方から検索) リスト内に指定エントリがなければ失敗 1297 checkIssues:{ 1298 for (var cx = (myEntry.issues.length-1) ; cx >= 0 ;cx--){ 1299 if ( Xps.compareIdentifier(myEntry.issues[cx].identifier,myIdentifier) > 4){ 1300 myIssue = myEntry.issues[cx]; 1301 break checkIssues; 1302 } 1303 } 1304 if (! myIssue){ 1305 console.log( 'no target data :'+ decodeURIComponent(myIdentifier) );//ターゲットのデータが無い 1306 return false; 1307 } 1308 } 1309 } 1310 1311 // 構成済みの情報を判定 (リファレンス置換 or 新規セッションか) 1312 // ソースデータ取得 1313 if(dbg) console.log("readIn XPS"); 1314 if(dbg) console.log(decodeURIComponent(myIssue.identifier)); 1315 1316 var myXpsSource=localStorage.getItem(this.keyPrefix+myIssue.identifier); 1317 //識別子を再結合してもキーが得られない場合があるのでエントリから対応キーの引き出しを行う 1318 1319 if(myXpsSource){ 1320 if(isReference){ 1321 //データ単独で現在のセッションのリファレンスを置換 1322 documentDepot.currentReference = new Xps(); 1323 documentDepot.currentReference.readIN(myXpsSource); 1324 xUI.resetSheet(undefined,documentDepot.currentReference); 1325 }else{ 1326 //新規セッションを開始する 1327 documentDepot.currentDocument = new Xps(); 1328 documentDepot.currentDocument.readIN(myXpsSource); 1329 documentDepot.currentReference = new Xps(5,144);//カラオブジェクトをあらかじめ新規作成 1330 //自動設定されるリファレンスはあるか? 1331 //指定管理部分からissueを特定する 文字列化して比較 1332 if ( cx > 0 ){ 1333 if(parseInt(decodeURIComponent(myIssue[2]).split(':')[0]) > 0 ){ 1334 //ジョブIDが1以上なので 単純に一つ前のissueを選択する 1335 //必ず先行jobがある = 通常処理の場合は先行JOBが存在するが、単データをエントリした場合そうでないケースがあるので対処が必要 2016 12 29 1336 refIssue = myEntry.issues[cx-1]; 1337 }else if(decodeURIComponent(myIssue[1]).split(':')[0] > 0 ){ 1338 //第2ステージ以降前方に向かって検索 1339 //最初にステージIDが先行IDになった要素が参照すべき要素 1340 for(var xcx = cx-1 ;xcx >= 0 ; xcx --){ 1341 if (parseInt(decodeURIComponent(myEntry.issues[xcx][1]).split(':')[0]) == (parseInt(decodeURIComponent(myIssue[1]).split(':')[0])-1)){ 1342 refIssue = myEntry.issues[xcx]; 1343 break; 1344 } 1345 } 1346 };//cx==0 のケースでは、デフォルトで参照すべき先行ジョブは無い 1347 if(refIssue){ 1348 //if(dbg) console.log(this.keyPrefix + refIssue.identifier); 1349 myRefSource=localStorage.getItem(this.keyPrefix + refIssue.identifier);//リファレンスソースとる 1350 if(myRefSource){ 1351 //if(dbg) console.log('myRefSource:'); 1352 //if(dbg) console.log(myRefSource); 1353 documentDepot.currentReference.readIN(myRefSource); 1354 } 1355 } 1356 } 1357 // if(dbg) console.log(documentDepot.currentReference);//単エントリで直前のエントリ取得不能の可能性あり 1358 xUI.resetSheet(documentDepot.currentDocument,documentDepot.currentReference); 1359 xUI.sessionRetrace = myEntry.issues.length-cx-1; 1360 xUI.setUImode('browsing');sync("productStatus"); 1361 xUI.flushUndoBuf();sync('undo');sync('redo'); 1362 if(callback instanceof Function){setTimeout(callback,10)}; 1363 } 1364 } else { 1365 return false; 1366 } 1367 } 1368 /** 1369 DBにタイトルを作成する。 1370 confirmなし 呼び出し側で済ませること 1371 必要あれば編集UI追加 1372 引数 1373 タイトル(必須) 1374 備考テキスト 1375 Pmオブジェクト 1376 コールバック関数2種 1377 識別子は受け入れない 必要に従って前段で分解のこと 1378 */ 1379 localRepository.addTitle=function (myTitle,myDescription,myPm,callback,callback2){ 1380 //現在ローカルリポジトリ側で行う処理は存在しない コールバックの実行のみを行う 1381 //タイトルDBが実装された場合はDBにエントリを加える 1382 console.log(['localRepository.addTitle',myTitle,myDescription,myPm].join(':')); 1383 if(callback instanceof Function) callback(); 1384 return true; 1385 } 1386 /** 1387 DBにOPUS(エピソード)を作成する。 1388 引数 1389 タイトルを含む識別子 カット番号は求めない 1390 コールバック関数2種 1391 識別子のみ受け入れ 1392 このルーチンを呼び出す時点で、タイトルは存在すること 1393 */ 1394 localRepository.addOpus=function (myIdentifier,prodIdentifier,callback,callback2){ 1395 //console.log(['localRepository.addOpus',myIdentifier,prodIdentifier].join(':')); 1396 //現在ローカルリポジトリ側で行う処理は存在しない コールバックの実行のみを行う 1397 //タイトルDBに加えて、documetntDepotのプロダクト更新が必要 1398 //タイトルDB側のイベント処理とするか、または追加後にdocumentDepot側でのデータ要求処理に振替 1399 1400 if(callback instanceof Function) callback(); 1401 return true; 1402 } 1403 /** 1404 識別子を指定してローカルリポジトリから相当エントリを消去する 1405 リストは再構築 1406 ローカルリポジトリに関しては、各ユーザは編集権限を持つ 1407 1408 また、ステータス変更のため内部ルーチンがこのメソッドを呼ぶ 1409 直接要素編集をしても良い? 1410 */ 1411 localRepository.removeEntry=function(myIdentifier){ 1412 var myEntry = this.entry(myIdentifier); 1413 if(myEntry){ 1414 //エントリに関連するアイテムをすべて削除 1415 for (var iid=0;iid < myEntry.issues.length;iid++){ 1416 localStorage.removeItem(this.keyPrefix+myEntry.issues[iid].identifier); 1417 }; 1418 //エントリ自身を削除 1419 var res = myEntry.remove(); 1420 if(! res ){console.log('fail removed : ' + res)} 1421 //ドキュメントブラウザ更新 1422 documentDepot.updateDocumentSelector(); 1423 // documentDepot.rebuildList();//ドキュメントブラウザの再ビルド 1424 return true; 1425 }; 1426 return myEntry; 1427 }; 1428 /** 1429 識別子でエントリリストを検索して該当するリストエントリを返す操作をメソッド可 1430 issuesは受取先で評価 1431 NetroekRepositoryにも同メソッドを 1432 引数 opt を加えると プロダクトまで一致で最初のエントリを返す 1433 */ 1434 localRepository.entry=function(myIdentifier,opt){ 1435 if(! opt) {opt = 1}else{opt = 0}; 1436 return this.entryList.getByIdf(myIdentifier,opt); 1437 1438 if(! opt) {opt = 0}else{opt = -1}; 1439 for (var pid=0;pid<this.entryList.length;pid++){ 1440 if(Xps.compareIdentifier(this.entryList[pid].toString(),myIdentifier) > opt){ 1441 return this.entryList[pid] 1442 } 1443 } 1444 return null; 1445 } 1446 /** 1447 以下、ステータス操作コマンドメソッド 1448 serviceAgentの同名メソッドから呼び出す下位ファンクション 1449 1450 */ 1451 /** 1452 現在のドキュメントをアクティベートする 1453 */ 1454 localRepository.activateEntry=function(callback,callback2){ 1455 var currentEntry = this.entry(Xps.getIdentifier(xUI.XPS)); 1456 var currentCut = this.cut(currentEntry.toString()); 1457 // var currentCut = this.cut(currentEntry.issues[0].cutID); 1458 var newXps = new Xps(); 1459 var currentContents = localStorage.getItem(this.keyPrefix+currentEntry.toString(0)); 1460 if (currentContents) { newXps.readIN(currentContents); }else {return false;} 1461 //ここ判定違うけど保留 あとでフォーマット整備 USERNAME:uid@domain(mailAddress) 型式で暫定的に記述 1462 //':'が無い場合は、メールアドレスを使用 1463 if ((newXps)&&(xUI.currentUser.sameAs(newXps.update_user))){ 1464 //同内容でステータスを変更したエントリを作成 新規に保存して成功したら先のエントリを消す 1465 newXps.currentStatus = new JobStatus('Active'); 1466 localStorage.setItem(this.keyPrefix+Xps.getIdentifier(newXps),newXps.toString()); 1467 var result = (localStorage.getItem(this.keyPrefix+Xps.getIdentifier(newXps)) == newXps.toString())?true:false; 1468 if(result){ 1469 localStorage.removeItem (this.keyPrefix+currentEntry.toString(0)); 1470 currentEntry.setStatus(newXps.currentStatus); 1471 var myVersion=currentCut.versions[currentCut.versions.length-1]; 1472 myVersion.updated_at=new Date().toString(); 1473 myVersion.description=currentEntry.toString(0); 1474 myVersion.version_token=this.keyPrefix+myVersion.description; 1475 xUI.XPS.currentStatus=new JobStatus('Active');//ドキュメントステータスを更新 1476 xUI.setStored("current");//UI上の保存ステータスをセット 1477 sync();//保存ステータスを同期 1478 selectSCi();//カレントデータを再セレクトして情報更新 1479 sync('historySelector');//履歴セレクタ更新 1480 }else{ 1481 //console.log('ステータス変更失敗 :'); 1482 delete newXps ; 1483 if(callback2 instanceof Function) {setTimeout(callback2,10);} 1484 return false; 1485 } 1486 xUI.setUImode('production'); 1487 xUI.sWitchPanel();//パネルクリア 1488 if(callback instanceof Function){ setTimeout (callback,10);} 1489 return true; 1490 }else{ 1491 //console.log('ステータス変更不可 :'+ Xps.getIdentifier(newXps)); 1492 if(callback2 instanceof Function) {setTimeout(callback2,10);} 1493 return false 1494 } 1495 } 1496 //作業を保留する リポジトリ内のエントリを更新してステータスを変更 1497 localRepository.deactivateEntry=function(callback,callback2){ 1498 var currentEntry = this.entry(Xps.getIdentifier(xUI.XPS)); 1499 var currentCut = this.cut(currentEntry.toString()); 1500 // var currentCut = this.cut(currentEntry.issues[0].cutID); 1501 //Active > Holdへ 1502 var newXps = new Xps(); 1503 var currentContents = xUI.XPS.toString(); 1504 newXps.readIN(currentContents); 1505 //ユーザ判定は不用 1506 if (newXps){ 1507 //同内容でステータスを変更したエントリを作成 新規に保存して成功したら先のエントリを消す 1508 newXps.currentStatus = new JobStatus('Hold');//(ジョブID等)status以外の変更はない 1509 localStorage.setItem(this.keyPrefix+Xps.getIdentifier(newXps),newXps.toString()); 1510 var result = (localStorage.getItem(this.keyPrefix+Xps.getIdentifier(newXps)) == newXps.toString())?true:false; 1511 if(result){ 1512 if(dbg) console.log('deactivated'); 1513 localStorage.removeItem(this.keyPrefix+currentEntry.toString(0)); 1514 currentEntry.setStatus(newXps.currentStatus); 1515 var myVersion=currentCut.versions[currentCut.versions.length-1]; 1516 myVersion.updated_at=new Date().toString(); 1517 myVersion.description=currentEntry.toString(0); 1518 myVersion.version_token=this.keyPrefix+myVersion.description; 1519 documentDepot.rebuildList(); 1520 xUI.XPS.currentStatus=new JobStatus('Hold');//ドキュメントステータスを更新 1521 xUI.setStored("current");//UI上の保存ステータスをセット 1522 sync();//保存ステータスを同期 1523 selectSCi();//カレントデータを再セレクトして情報更新 1524 sync('historySelector');//履歴セレクタの更新 1525 }else{ 1526 //保存に失敗 1527 //console.log('保留失敗') 1528 delete newXps ; 1529 if(callback2 instanceof Function) setTimeout(callback2,10); 1530 return false; 1531 } 1532 //データをホールドしたので、リストを更新 編集対象をクリアしてUIを初期化 1533 xUI.setUImode('browsing'); 1534 xUI.sWitchPanel();//パネルクリア 1535 if(callback instanceof Function) setTimeout(callback,10); 1536 }else{ 1537 //console.log('保留可能エントリが無い :'+ Xps.getIdentifier(newXps)); 1538 if(callback2 instanceof Function) setTimeout(callback2,10); 1539 return false ; 1540 } 1541 } 1542 /** 1543 作業にチェックイン 1544 リポジトリ種別にかかわらないので 1545 このメソッドを呼ぶ前段でジョブ名称は確定しておくこと 1546 ジョブ名指定のない場合は操作失敗 1547 */ 1548 localRepository.checkinEntry=function(myJob,callback,callback2){ 1549 if( typeof myJob == 'undefined') return false; 1550 myJob = (myJob)? myJob:xUI.currentUser.handle; 1551 var currentEntry = this.entry(Xps.getIdentifier(xUI.XPS)); 1552 var currentCut = this.cut(currentEntry.toString()); 1553 // var currentCut = this.cut(currentEntry.issues[0].cutID); 1554 if(! currentEntry){ 1555 if(dbg) console.log ('noentry in repository :' + decodeURIComponent(currentEntry)) 1556 //当該リポジトリにエントリが無い 1557 return false; 1558 } 1559 //次のJobへチェックイン 読み出したデータでXpsを初期化 1560 var newXps = new Xps(); 1561 var currentContents = localStorage.getItem(this.keyPrefix+currentEntry.toString(0)); 1562 if (currentContents) { 1563 newXps.readIN(currentContents); 1564 } else { 1565 if(dbg) console.log('読み出し失敗') 1566 return false; 1567 } 1568 // ユーザ判定は不用(権利チェックは後ほど実装) 1569 if (newXps){ 1570 newXps.job.increment(myJob); 1571 newXps.update_user = xUI.currentUser; 1572 newXps.currentStatus = new JobStatus('Active'); 1573 //引数でステータスを変更したエントリを作成 新規に保存 JobIDは必ず繰り上る 1574 localStorage.setItem(this.keyPrefix+Xps.getIdentifier(newXps),newXps.toString()); 1575 var resultData = localStorage.getItem(this.keyPrefix+Xps.getIdentifier(newXps)); 1576 var result = ( resultData == newXps.toString()) ? true:false; 1577 if(result){ 1578 currentEntry.push(Xps.getIdentifier(newXps)); 1579 currentCut.versions.push({ 1580 updated_at:new Date().toString(), 1581 description:currentEntry.toString(0), 1582 version_token:this.keyPrefix+currentEntry.toString(0) 1583 }); 1584 xUI.setReferenceXPS(); 1585 xUI.XPS.job.increment(myJob); 1586 xUI.XPS.currentStatus=new JobStatus('Active');//ドキュメントステータスを更新 1587 xUI.XPS.update_user=xUI.currentUser;//ユーザ更新 1588 xUI.setStored("current");//UI上の保存ステータスをセット 1589 sync();//保存ステータスを同期 1590 selectSCi();//カレントデータを再セレクトして情報更新 1591 xUI.setUImode('production');//モードをproductionへ 1592 xUI.sWitchPanel();//ドキュメントパネルが表示されていたらパネルクリア 1593 sync('historySelector');//履歴セレクタ更新 1594 if(callback instanceof Function){ setTimeout(callback,10)}; 1595 return result; 1596 }else{ 1597 if(dbg) console.log(result); 1598 } 1599 } 1600 //console.log('編集権利取得失敗'); 1601 // すべてのトライに失敗 1602 if(callback2 instanceof Function){ setTimeout(callback2,10)}; 1603 return false ; 1604 } 1605 /** 1606 作業終了 1607 */ 1608 localRepository.checkoutEntry=function(assignData,callback,callback2){ 1609 var currentEntry = this.entry(Xps.getIdentifier(xUI.XPS)); 1610 var currentCut = this.cut(currentEntry.toString()); 1611 // var currentCut = this.cut(currentEntry.issues[0].cutID); 1612 if(! currentEntry) { 1613 //console.log ('noentry in repository :' + decodeURIComponent(currentEntry)) 1614 return false; 1615 } 1616 //Active > Fixed 1617 var newXps = new Xps(); 1618 var currentContents = xUI.XPS.toString(); 1619 newXps.readIN(currentContents); 1620 //ユーザ判定は不用 JobID変わらず 1621 if (newXps){ 1622 //同内容でステータスを変更したエントリを作成 新規に保存して成功したら先のエントリを消す 1623 // newXps.currentStatus = ['Fixed',assignData].join(":"); 1624 newXps.currentStatus = new JobStatus('Fixed'); 1625 newXps.currentStatus.assign = assignData; 1626 //いったん元に戻す assignData は宙に保留(ここで消失) 1627 localStorage.setItem(this.keyPrefix+Xps.getIdentifier(newXps),newXps.toString()); 1628 1629 var result = (localStorage.getItem(this.keyPrefix+Xps.getIdentifier(newXps))==newXps.toString())? true:false; 1630 if(result){ 1631 //console.log(result); 1632 //console.log(currentCut) 1633 localStorage.removeItem(this.keyPrefix+currentEntry.toString(0)); 1634 xUI.XPS.currentStatus=newXps.currentStatus;//ドキュメントステータスを更新 1635 currentEntry.setStatus(newXps.currentStatus); 1636 var myVersion=currentCut.versions[currentCut.versions.length-1]; 1637 myVersion.updated_at=new Date().toString(); 1638 myVersion.description=currentEntry.toString(0); 1639 myVersion.version_token=this.keyPrefix+myVersion.description; 1640 xUI.setStored("current");//UI上の保存ステータスをセット 1641 sync();//保存ステータスを同期 1642 selectSCi();//カレントデータを再セレクトして情報更新 1643 xUI.sWitchPanel();//ドキュメントパネルが表示されていたらパネルクリア 1644 xUI.setUImode('browsing');//モードをbrousingへ 1645 sync('historySelector');//履歴セレクタ更新 1646 if(callback instanceof Function){ setTimeout('callback()',10)}; 1647 return result; 1648 }else{ 1649 //console.log("fail checkout store") 1650 } 1651 } 1652 //console.log('終了更新失敗'); 1653 delete newXps ; 1654 if(callback2 instanceof Function){ setTimeout(callback2,10)}; 1655 return false ; 1656 } 1657 /** 1658 検収処理receiptEntry/receiptEntry 1659 */ 1660 localRepository.receiptEntry=function(stageName,jobName,callback,callback2){ 1661 if( typeof stageName == 'undefined') return false; 1662 var myStage = nas.pmdb.stages.getStage(stageName) ;//ステージDBと照合 エントリが無い場合はエントリ登録 1663 /* 2016-12 の実装では省略して エラー終了 1664 2017-07 最小限の処理を実装 ステージの存在を確認して続行 1665 */ 1666 if(! myStage) return false; 1667 var currentEntry = this.entry(Xps.getIdentifier(xUI.XPS)); 1668 if(! currentEntry){ 1669 console.log ('noentry in repository :' + decodeURIComponent(currentEntry)) 1670 //当該リポジトリにエントリが無い 1671 return false; 1672 } 1673 var currentCut = this.cut(currentEntry.toString());//= this.cut(currentEntry.issues[0].cutID); 1674 if(! currentCut) return false; 1675 //次のステージを立ち上げるため 読み出したデータでXpsを初期化 1676 var newXps = new Xps(); 1677 var currentContents = localStorage.getItem(this.keyPrefix+currentEntry.toString(0)); 1678 if (currentContents) { 1679 newXps.readIN(currentContents); 1680 } else { 1681 if(dbg) console.log('読み出し失敗') 1682 return false; 1683 } 1684 // ユーザ判定は不用(権利チェックは後ほど実装) 1685 if (newXps){ 1686 newXps.stage.increment(stageName); 1687 newXps.job.reset(jobName); 1688 newXps.update_user = xUI.currentUser; 1689 newXps.currentStatus = new JobStatus('Startup'); 1690 if(dbg) console.log(newXps.toString());// 1691 //引数でステータスを変更したエントリを作成 新規に保存 stageIDは必ず繰り上る jobは0リセット 1692 localStorage.setItem(this.keyPrefix+Xps.getIdentifier(newXps),newXps.toString()); 1693 var resultData = localStorage.getItem(this.keyPrefix+Xps.getIdentifier(newXps)); 1694 if(dbg) console.log(resultData); 1695 var result = ( resultData == newXps.toString()) ? true:false; 1696 if(result){ 1697 if(dbg) console.log('receipt'); 1698 //delete newXps ; 1699 if(dbg) console.log(newXps.currentStatus); 1700 // this.getList();//リストステータスを同期 1701 currentEntry.push(Xps.getIdentifier(newXps)); 1702 currentCut.versions.push({ 1703 updated_at:newXps.update_time, 1704 description:currentEntry.toString(0), 1705 version_token:this.keyPrefix+currentEntry.toString(0) 1706 }); 1707 xUI.XPS.stage.increment(stageName); 1708 xUI.XPS.job.reset(jobName); 1709 xUI.XPS.currentStatus=new JobStatus('Startup');//ドキュメントステータスを更新 1710 xUI.XPS.update_user=xUI.currentUser;//ユーザ更新 1711 xUI.setStored("current");//UI上の保存ステータスをセット 1712 sync();//保存ステータスを同期 1713 selectSCi();//カレントデータを再セレクトして情報更新 1714 // xUI.setUImode('browsing');//モードをbrowsingへ <<領収処理の後はモード遷移なし 1715 xUI.sWitchPanel();//ドキュメントパネルが表示されていたらパネルクリア 1716 sync('historySelector');//履歴セレクタ更新 1717 if(callback instanceof Function){ setTimeout(callback,10)}; 1718 return result; 1719 }else{ 1720 if(dbg) console.log(result); 1721 } 1722 } 1723 if(dbg) console.log('編集権利取得失敗'); 1724 // すべてのトライに失敗 1725 if(callback2 instanceof Function){ setTimeout(callback2,10)}; 1726 return false ; 1727 } 1728 /** 1729 作業中断処理 1730 */ 1731 localRepository.abortEntry=function(myIdentifier,callback,callback2){ 1732 var currentEntry = this.entry(myIdentifier); 1733 if(! currentEntry) return false; 1734 var currentStatus=currentEntry.getStatus(); 1735 1736 if(String(currentStatus.content).indexOf('Fixed')<0){return false;} 1737 var currentCut = this.cut(currentEntry.toString()); 1738 if(! currentCut) return false; 1739 1740 //中断エントリを作成するために、読み出したデータで新規Xpsを初期化 1741 var newXps = new Xps(); 1742 var currentContents = localStorage.getItem(this.keyPrefix+currentEntry.toString(0)); 1743 if (currentContents) { 1744 newXps.parseXps(currentContents); 1745 } else { 1746 //console.log('abort entry:読み出し失敗') 1747 return false; 1748 } 1749 // ユーザ判定は不用(権利チェックは後ほど実装) 1750 if (newXps){ 1751 newXps.job.increment('Abort'); 1752 newXps.update_user = xUI.currentUser; 1753 newXps.currentStatus = new JobStatus('Aborted'); 1754 //console.log('abort entry:'); 1755 //console.log(newXps.toString());// 1756 //引数でステータスを変更したエントリを作成 新規に保存 stageIDは変わらず、jobIDは繰り上る 1757 localStorage.setItem(this.keyPrefix+Xps.getIdentifier(newXps),newXps.toString()); 1758 var resultData = localStorage.getItem(this.keyPrefix+Xps.getIdentifier(newXps)); 1759 //console.log(resultData); 1760 var result = ( resultData == newXps.toString()) ? true:false; 1761 if(result){ 1762 //console.log('aborted'); 1763 //console.log(newXps.currentStatus); 1764 this.getList();//リストステータスを同期 1765 // currentEntry.push(Xps.getIdentifier(newXps)); 1766 currentEntry.remove(Xps.getIdentifier(newXps)); 1767 currentCut.versions.push({ 1768 updated_at:newXps.update_time, 1769 description:currentEntry.toString(0), 1770 version_token:this.keyPrefix+currentEntry.toString(0) 1771 }); 1772 // xUI.XPS.stage.increment(stageName); 1773 // xUI.XPS.job.reset(jobName); 1774 // xUI.XPS.currentStatus=new JobStatus('Startup');//ドキュメントステータスを更新 1775 // xUI.XPS.update_user=xUI.currentUser;//ユーザ更新 1776 // xUI.setStored("current");//UI上の保存ステータスをセット 1777 sync();//保存ステータスを同期 1778 selectSCi();//カレントデータを再セレクトして情報更新 1779 xUI.setUImode('floating');//モードをfloatingへ <<領収処理の後はモード遷移なし 1780 xUI.sWitchPanel();//ドキュメントパネルが表示されていたらパネルクリア 1781 sync('historySelector');//履歴セレクタ更新 1782 if(callback instanceof Function){ setTimeout(callback,10)}; 1783 return result; 1784 }else{ 1785 if(dbg) console.log(result); 1786 } 1787 } 1788 if(dbg) console.log('編集権利取得失敗'); 1789 // すべてのトライに失敗 1790 if(callback2 instanceof Function){ setTimeout(callback2,10)}; 1791 return false ; 1792 } 1793 /** 1794 リポジトリの情報をダイアログで表示 1795 1796 */ 1797 localRepository.showInformation=function (){ 1798 var ownerString = (xUI.currentUser)? xUI.currentUser.toString(): nas.localize({en:"(Could not acquire.)",ja:"(取得できません)"}); 1799 var title = nas.localize(nas.uiMsg.aboutOf,this.name); 1800 var msg = ""; 1801 msg += nas.localize(nas.uiMsg.serviceNode) +" : "+ "localRepository<br>"; 1802 msg += nas.localize(nas.uiMsg.repositoryName) +" : " + this.name +"<br>"; 1803 msg += nas.localize(nas.uiMsg.repositoryOwner) + " : " + ownerString + "<br>"; 1804 msg += nas.localize({ 1805 en:"<hr>** This is the area where temporary files are stored using local storage of the browser. Data can not be shared between users in this repository.<br>", 1806 ja:"<hr>** ブラウザのローカルストレージを使用した、一時ファイルを保存する領域です。<br>ユーザ間のデータ共有はできません。<br>" 1807 }); 1808 nas.showModalDialog("alert",msg,title); 1809 } 1810 /* test data 1811 localRepository.currentProduct = "ももたろう#12[キジ参戦!ももたろう地獄模様!!]"; 1812 localRepository.currentSC = "S-C005 (12+00)/011(3+00)/014(3+00)"; 1813 localRepository.currentLine = 0; 1814 localRepository.currentStage = 0; 1815 localRepository.currentJob = 0; 1816 1817 JSON.stringify(localRepository); 1818 1819 localRepository.pushStore(XPS); 1820 localRepository.getList(); 1821 //localRepository.entryList[0]; 1822 localRepository.getEntry(localRepository.entryList[0]); 1823 1824 localRepository.showInformation(); 1825 */ 1826 /** 1827 最終作業の破棄 1828 バックアップ作業これを呼び出す側で処理 1829 ここを直接コールした場合はバックアップは実行されない 1830 ユーザメッセージはここでは処理されない 1831 1832 */ 1833 localRepository.destroyJob=function(callback,callback2){ 1834 if(xUI.XPS.currentStatus.content != 'Active'){return false} 1835 // カレントの作業に対応するストレージ上のキーを消去 1836 // 成功すれば 1837 var currentEntry = this.entry(Xps.getIdentifier(xUI.XPS)); 1838 if(! currentEntry){ 1839 if(dbg) console.log ('noentry in repository :' + decodeURIComponent(currentEntry)) 1840 //当該リポジトリにエントリが無い 1841 return false; 1842 } 1843 try { 1844 localStorage.removeItem(this.keyPrefix+currentEntry.toString(0)); 1845 currentEntry.issues.pop(); 1846 // xUI.resetSheet(new Xps(5,144),new Xps(5,144)); 1847 xUI.resetSheet(); 1848 if(callback instanceof Function) callback(); 1849 }catch(er){ 1850 //console.log(er) 1851 if(callback2 instanceof Function) callback2(); 1852 } 1853 } 1854 1855 /** 1856 ネットワーク上のリポジトリオブジェクト 1857 識別名とサーバを与えて初期化する 1858 リポジトリとしての共通メソッド 1859 .getList() 1860 .title(myIdentifier) 1861 .opus(myIdentifier) 1862 .cut(myIdentifier) 1863 .entry(myIdentifier) 1864 1865 .push(myXps) 1866 1867 リポジトリに 相当する構造は Team 1868 チームごとにリポジトリが設定される 1869 Teamへアクセスするためのトークンは、アクセス毎に設定される 1870 リポジトリは、複数の同一名称のリポジトリが想定されるため、補助的にオーナー情報を保持する仕様を追加 1871 特に同作品の複製を見分けるために必須 APIに追加 1872 */ 1873 //NetworkRepository=function(repositoryName,repositoryOwner,myServer,repositoryURI){} 1874 NetworkRepository=function(repositoryName,myServer,repositoryURI){ 1875 this.name = repositoryName; 1876 // this.owner = new nas.UserInfo(repositoryOwner);//リポジトリオーナー情報 1877 this.service = myServer;//リポジトリの所属するサーバ 1878 this.url=(typeof repositoryURI == 'undefined')?this.service.url:repositoryURI;//サーバとurlが異なる場合は上書き 1879 this.token=null;//nullで初期化 1880 //サーバ内にTeamが実装 Teamをリポジトリとして扱うのでその切り分けを作成 12/13 1881 //リストは素早いリポジトリの切り替えやリポジトリ同士のマージ処理に不可欠なのでここで保持 1882 // this.currentProduct; 1883 // this.currentSC; 1884 // this.currentLine; 1885 // this.currentStage; 1886 // this.currentJob; 1887 // this.product_token = $('#server-info').attr('product_token'); 1888 // this.episode_token = $('#server-info').attr('episode_token'); 1889 // this.cut_token = $('#server-info').attr('cut_token'); 1890 // ?idの代替なので要らないか? 1891 this.pmd={};//制作管理データキャリア 機能クラスオブジェクト化? 1892 this.currentIssue; 1893 this.productsData=[];//workTitleCollectionで置換?タイトルキャリアでノードルートになる 1894 this.entryList = new listEntryCollection(); 1895 } 1896 /** 1897 リポジトリ情報表示メソッド 1898 引数:なし 1899 リポジトリのオーナー情報を表示してリポジトリ(共有・チーム)へのアクセスリンクを提供する 1900 リポジトリへのリンクはリポジトリ名を使用 1901 1902 */ 1903 NetworkRepository.prototype.showInformation = function(){ 1904 var ownerString = (this.owner.handle)? this.owner.handle: nas.localize({en:"(Could not acquire.)",ja:"(取得できません)"}); 1905 var title = nas.localize(nas.uiMsg.aboutOf,this.name); 1906 var msg = ""; 1907 msg += nas.localize(nas.uiMsg.serviceNode) +" : <a href='" +this.service.url+"' target='_blank'>"+ this.service.name + "("+this.service.url +")</a><br>"; 1908 msg += nas.localize(nas.uiMsg.repositoryName) +" : " + this.name +"<br>"; 1909 msg += nas.localize(nas.uiMsg.repositoryOwner) + " : " + ownerString + "<br>"; 1910 // msg += " アクセス先 : " + this.owner.token + "<br>"; 1911 nas.showModalDialog("alert",msg,title); 1912 } 1913 /** 1914 各層のエントリを識別子で取得 1915 TITLE取得 1916 */ 1917 NetworkRepository.prototype.title=_title; 1918 /** 1919 OPUS取得 1920 */ 1921 NetworkRepository.prototype.opus=_opus; 1922 /** 1923 CUT取得 1924 */ 1925 NetworkRepository.prototype.cut=_cut; 1926 /** 1927 タイトル一覧を取得して情報を更新する エピソード更新を呼び出す 1928 受信したデータを複合させてサービス上のデータ構造を保持する単一のthis.productsDataオブジェクトにする 1929 getXx で概要(一覧)を取得 1930 xxUpdateが詳細を取得して this.productsData を上書きしてゆく 1931 プロダクト詳細は、各個に取得できるように変更 1932 引き続きの処理を行う際はコールバック渡し 1933 トークン指定がない場合は、全プロダクトの詳細を取得 1934 プロダクトデータ取得のみの場合は 空動作のコールバックを渡す必要あり 1935 */ 1936 NetworkRepository.prototype.getProducts=function (callback,callback2,prdToken){ 1937 if(typeof prdToken == 'undefined'){prdToken = [];} 1938 if(!(prdToken instanceof Array)) prdToken=[prdToken]; 1939 $.ajax({ 1940 url: serviceAgent.currentRepository.url+'/api/v2/products.json', 1941 type: 'GET', 1942 dataType: 'json', 1943 success: function(result) { 1944 //resultにデータが無いケース{}があるので分離が必要 1945 //権限等で 1946 //この時点でタイトルに付属のメンバーシップをs同時に取得してオブジェクトに設定する(プロパティオブジェクト未実装20171116) 1947 serviceAgent.currentRepository.productsData = result.data.products; 1948 if(prdToken.length){ 1949 //引数があれば引数のプロダクトを順次処理 1950 for (var tId = 0 ; tId < prdToken.length ; tId ++ ){ 1951 serviceAgent.currentRepository.productsUpdate(callback,callback2,prdToken[tId]); 1952 } 1953 }else{ 1954 //引数がない場合はすべてのプロダクトの詳細を取得更新 1955 for (var tId = 0 ; tId < serviceAgent.currentRepository.productsData.length ; tId ++ ){ 1956 serviceAgent.currentRepository.productsUpdate(callback,callback2,serviceAgent.currentRepository.productsData[tId].token); 1957 } 1958 } 1959 }, 1960 error : function(result){ 1961 if(dbg) console.log('fail productsData::'); 1962 if(dbg) console.log(result); 1963 if(callback2 instanceof Function){callback2()} 1964 }, 1965 beforeSend: serviceAgent.currentRepository.service.setHeader 1966 }); 1967 } 1968 /** 1969 タイトルごとの詳細(エピソードリスト含む)を取得してタイトルに関連付ける 1970 myToken 引数がない場合はすべてのプロダクトを更新 1971 必要に従ってエピソードリストの更新を行う 1972 コールバック引数がない場合はタイトルのエピソード毎に情報を取得 1973 */ 1974 NetworkRepository.prototype.productsUpdate=function(callback,callback2,myToken){ 1975 if(typeof myToken == 'undefined'){ 1976 myToken = []; 1977 for(var tknId = 0 ;tknId < serviceAgent.currentRepository.productsData.length ;tknId ++){ 1978 myToken.push(serviceAgent.currentRepository.productsData[tknId].token); 1979 } 1980 }else{ 1981 if(!(myToken instanceof Array)) myToken=[myToken]; 1982 } 1983 for(var ix = 0 ;ix < myToken.length ;ix ++){ 1984 $.ajax({ 1985 url: serviceAgent.currentRepository.url+'/api/v2/products/'+myToken[ix]+'.json' , 1986 type: 'GET', 1987 dataType: 'json', 1988 success: function(result) { 1989 var productUpdated=false; 1990 for(var idx = 0 ;idx < serviceAgent.currentRepository.productsData.length ;idx ++){ 1991 if(result.data.product.token != serviceAgent.currentRepository.productsData[idx].token) continue; 1992 //プロダクトデータを詳細データに「入替」エピソードの概要を取得する 1993 if(dbg) console.log("update product data detail:"+serviceAgent.currentRepository.productsData[idx].name) ; 1994 //console.log(serviceAgent.currentRepository.productsData); 1995 serviceAgent.currentRepository.productsData[idx] = result.data.product ; 1996 if(! (serviceAgent.currentRepository.productsData[idx].episodes)){serviceAgent.currentRepository.productsData[idx].episodes=[[]];};//episodes/cutsの配列整理が終了したら変更 1997 serviceAgent.currentRepository.productsData[idx].episodes[0] = result.data.episodes ; 1998 productUpdated=true; 1999 break; 2000 }; 2001 //console.log("updated : "+serviceAgent.currentRepository.productsData[idx].name); 2002 if(productUpdated) { 2003 serviceAgent.currentRepository.updateEpisodes(callback,callback2,serviceAgent.currentRepository.productsData[idx].token); 2004 }else{ 2005 //console.log('fail productsData update no entry in Repository::'); 2006 //console.log(result); 2007 //指定されたトークンが ,リポジトリ内に存在しないのでエラー 2008 if(callback2 instanceof Function){callback2();} 2009 }; 2010 }, 2011 error : function(result){ 2012 //console.log('fail productsData update::'); 2013 //console.log(result); 2014 if(callback2 instanceof Function){callback2();} 2015 }, 2016 beforeSend: (serviceAgent.currentRepository.service.setHeader) 2017 }); 2018 } 2019 } 2020 /** 2021 プロダクトごとにエピソード一覧を再取得してデータ内のエピソード一覧を更新 2022 引数 product_tokenが存在する場合は、指定のプロダクト以外の処理をスキップ 2023 */ 2024 NetworkRepository.prototype.updateEpisodes=function (callback,callback2,prdToken) { 2025 // var myProduct = serviceAgent.currentRepository.getNodeElementByToken(prdToken); 2026 var myProduct = serviceAgent.currentRepository.title(prdToken); 2027 if(! myProduct) return false; 2028 //console.log("getEpisodeList : "+myProduct.token+' : '+myProduct.name) ; 2029 $.ajax({ 2030 url: serviceAgent.currentRepository.url+'/api/v2/episodes.json?product_token='+myProduct.token , 2031 type: 'GET', 2032 dataType: 'json', 2033 success: function(result) { 2034 //プロダクトデータのエピソード一覧を「入替」 2035 2036 if(result){ 2037 if(! myProduct.episodes) {myProduct.episodes=[[]];} 2038 //後ほどエピソードレベルのユーザ情報取得 2039 myProduct.episodes[0] = result.data.episodes; 2040 //console.log('success getting episodes :'+myProduct.name); 2041 //console.log(myProduct); 2042 if(callback instanceof Function){ 2043 callback(); 2044 }else{ 2045 serviceAgent.currentRepository.getEpisodes(callback,callback2,myProduct.token); 2046 // for(var eid=0;eid<myProduct.episodes[0].length;eid++){ 2047 // serviceAgent.currentRepository.getEpisodes(callback,callback2,myProduct.token,myProduct.episodes[0][eid].token); 2048 // } 2049 } 2050 }else{ 2051 //console.log('fail get no episodes::'); 2052 //console.log(result); 2053 if(callback2 instanceof Function){callback2();} 2054 } 2055 }, 2056 error : function(result){ 2057 //console.log('fail getting Episodes::'); 2058 //console.log(result); 2059 if(callback2 instanceof Function){callback2();} 2060 }, 2061 beforeSend: serviceAgent.currentRepository.service.setHeader 2062 }); 2063 } 2064 /** 2065 episode_token を指定して詳細を取得 内部リストにコンバート 2066 コールバックリンクのためこのあたりの機能は統合かける 2067 リポジトリ取得 server.getRepositories() 2068 サーバ指定=引数なしでサーバの管理するリポジトリの情報を取得 2069 2070 プロダクト取得 repositoriy.getProducts(識別子) 2071 2072 下位ファンクションを組み合わせてプロダクトレベルの情報取得を行う 2073 識別子でコントロール 2074 識別子を引数にするとその配下を取得 2075 2076 タイトル取得 repositoriy.getTitle(myTitel,callback,callback2) 2077 リポジトリ指定=引数なし で全タイトル 2078 タイトル指定で特定タイトルの情報を更新 2079 引数が配列の場合は配列内のタイトルを更新 2080 下位情報には踏み込まないコールバックリレーは行わない 2081 2082 エピソード取得 repository.getOpus(myTitle,myOpus,callback,callback2) 2083 タイトル指定で、そのタイトル配下のエピソード 2084 OPUS指定があれば、そのOPUSのみを更新 2085 カット取得 repository.getSCi(myOpus,pgNo,ppg,callback,callback2) 2086 プロダクト指定,エピソード指定,ページ数,単位 2087 エピソードの指定が存在する場合は、指定エピソードの処理を行う 配列OK 2088 それ以外は指定プロダクトのすべてを更新 2089 */ 2090 NetworkRepository.prototype.getEpisodes=function (callback,callback2,prdToken,epToken) { 2091 var allEpisodes=false; 2092 if(typeof epToken == 'undefined'){ 2093 epToken = []; 2094 allEpisodes = true; 2095 console.log(prdToken) 2096 var myProduct=this.title(prdToken); 2097 console.log(myProduct) 2098 if((! myProduct)||(! myProduct.episodes)||(myProduct.episodes[0].length == 0)){console.log('stop'); return false;} 2099 for (var px = 0 ;px < myProduct.episodes[0].length;px ++){epToken.push(myProduct.episodes[0][px].token);} 2100 } 2101 if(!(epToken instanceof Array)) epToken = [epToken]; 2102 for(var ex = 0;ex < epToken.length ;ex ++){ 2103 var myEpisode=this.opus(epToken[ex]); 2104 if(! myEpisode) continue; 2105 if((allEpisodes)&&(myEpisode.cuts)){console.log('skip'+myEpisode.name) ;continue;} 2106 //対象が全エピソードで、エピソードがすでにカット情報を持っているケースでは処理スキップ 2107 console.log("get episodes details for : "+myEpisode.name) ; 2108 console.log("Token : "+myEpisode.token) ; 2109 // /api/v2 2110 var targetURL = serviceAgent.currentRepository.url+ '/api/v2/episodes/'+myEpisode.token +'.json'; 2111 $.ajax({ 2112 url: targetURL, 2113 type: 'GET', 2114 dataType: 'json', 2115 success: function(result) { 2116 console.log('success : episode details for:'+result.data.episode.name);//リザルト不正 調整中20190129 2117 console.log(result); 2118 var updateTarget = serviceAgent.currentRepository.opus(result.data.episode.token); 2119 if(! updateTarget){console.log('erroe###');console.log(updateTarget);}; 2120 //非同期処理中に変数を共有するのでmyEpisodeが変動するためターゲットをリザルトから再キャプチャ 2121 //オブジェクト入れ替えでなくデータの追加アップデートに変更 2122 //内容は等価だがAPIの変更時は注意 2123 //この時点でカットの総数が取得されるのでカット一覧詳細取得時総数を参照して分割取得 2124 //console.log('update target episode###');console.log(updateTarget); 2125 if(!(updateTarget.cuts)){updateTarget.cuts=[[]];} 2126 updateTarget.cuts[0] = result.data.cuts; 2127 updateTarget.created_at = result.data.episode.created_at; 2128 updateTarget.updated_at = result.data.episode.updated_at; 2129 //console.log(updateTarget); 2130 if(callback instanceof Function){ 2131 callback(); 2132 }else{ 2133 //標準処理 2134 serviceAgent.currentRepository.getSCi(false,false,myEpisode.token); 2135 } 2136 }, 2137 error : function(result){ 2138 //console.log('fail getting episode details::'); 2139 //console.log(result); 2140 if(callback2 instanceof Function){callback2();} 2141 }, 2142 beforeSend: serviceAgent.currentRepository.service.setHeader 2143 }); 2144 } 2145 }; 2146 /** 2147 エピソード毎にカットリストを再取得 2148 エピソード詳細の内部情報にコンバート 2149 カット一覧にdescriptionを出してもらう 2150 取得時にentryListを同時更新する 2151 引数 2152 epToken ターゲットの話数キーまたは、カットトークン 2153 pgNo リストのページID 1 origin 2154 ppg ページごとのエントリ数 2155 2156 epToken のかわりにカットトークンが与えられた場合は、カット1つのみのリスト作成して高速に処理を完了する。 2157 2158 */ 2159 NetworkRepository.prototype.getSCi=function (callback,callback2,epToken,pgNo,ppg) { 2160 var myEpisode = this.opus(epToken); 2161 //console.log('getSCi :');console.log(myEpisode); 2162 if((! myEpisode)||(! myEpisode.cuts)) return false; 2163 /* 2164 if(! myEpisode){ 2165 if(myEpisode == null) { 2166 var targetURL='/api/v2/cuts/'+epToken+'.json';// epToken ascutToken 2167 $.ajax({ 2168 url: this.url + targetURL, 2169 type: 'GET', 2170 dataType: 'json', 2171 success: function(result) { 2172 console.log(result); 2173 }, 2174 beforeSend: this.service.setHeader 2175 }) 2176 }else{ 2177 return false; 2178 } 2179 return true; 2180 } 2181 */ 2182 if(typeof pgNo == 'undefined') pgNo = '1'; 2183 if(typeof ppg == 'undefined') ppg = myEpisode.cuts[0].length; 2184 //console.log(arguments); 2185 //console.log([pgNo,ppg]); 2186 var targetURL = serviceAgent.currentRepository.url+ '/api/v2/cuts.json?episode_token='+myEpisode.token+'&page_no='+parseInt(pgNo)+'&per_page='+parseInt(ppg); 2187 $.ajax({ 2188 url: targetURL, 2189 type: 'GET', 2190 dataType: 'json', 2191 success: function(result){ 2192 //console.log(result);console.log(myEpisode); 2193 myEpisode.cuts[0]=result.data.cuts; 2194 //カット登録数1以上の場合のみ処理 2195 if(myEpisode.cuts[0].length){ 2196 if (! myEpisode.cuts[0][0].description) console.log(myEpisode.token) 2197 var currentTitle = (! myEpisode.cuts[0].description)? 2198 serviceAgent.currentRepository.title(myEpisode.token,1): 2199 serviceAgent.currentRepository.title(myEpisode.cuts[0].description); 2200 if(! currentTitle){console.log(currentTitle)} 2201 /** 2202 エントリ取得タイミングで仮にcutのdescription を追加するcuts[1][cid].description を作成して調整に使用する 2203 本番ではデータ比較ありで、入替えを行う サーバ側のプロパティ優先 2204 */ 2205 var myIdentifier_opus = 2206 encodeURIComponent(currentTitle.name) + 2207 '#'+encodeURIComponent(myEpisode.name) + 2208 ((myEpisode.description)? 2209 '['+encodeURIComponent(myEpisode.description) +']':'' 2210 ); 2211 if(! myEpisode.cuts){console.log(myEpisode.cuts);} 2212 for ( var cid = 0 ; cid < result.data.cuts.length ; cid ++){ 2213 var myCut = myEpisode.cuts[0][cid]; 2214 if(myCut.name == null) myCut.name = "";//この状態は実際にはエラー 2215 var myIdentifier_cut = encodeURIComponent(myCut.name); 2216 // デスクリプションに識別子がない場合issuen部の無い識別子を補う 2217 // 他はDB側の識別子を優先して識別子を更新する 2218 if(! myCut.description){ 2219 myCut.description=[myIdentifier_opus,myIdentifier_cut].join('//'); 2220 } else { 2221 var currentIssue = myCut.description.split("//").slice(2); 2222 myCut.description=([myIdentifier_opus,myIdentifier_cut].concat(currentIssue)).join('//'); 2223 } 2224 //============エントリ更新 2225 /* 2226 管理情報は識別子から取得する 2227 APIの情報は、識別子と一致しているはずだが 照合の上異なる場合はAPIの情報で上書きを行う 2228 識別子として cut.description を使用 上位情報は、エントリから再作成 2229 サブタイトルは episode.discriptionを使用 2230 兼用カット情報はペンディング 2231 */ 2232 //console.log(myCut) 2233 var myCutToken = myCut.token; 2234 var myCutLine = (myCut.line_id)? 2235 myCut.line_id: 2236 (new XpsLine(nas.pmdb.pmTemplates.members[0].line.toString())).toString(true); 2237 var myCutStage = (myCut.stage_id)? 2238 myCut.stage_id: 2239 (new XpsStage(nas.pmdb.pmTemplates.members[0].stages.getStage())).toString(true); 2240 var myCutJob = (myCut.job_id)? 2241 myCut.job_id: 2242 (new XpsStage(nas.pmdb.jobNames.members[0].toString())).toString(true); 2243 var myCutStatus= (myCut.status)? 2244 myCut.status:new JobStatus('Startup'); 2245 // myCut.status new JobStatus('Startup'); 2246 //管理情報が不足の場合は初期値で補う description情報が未登録の場合は、APIの情報からビルドする? 2247 2248 var entryArray = ( 2249 String(myCut.description).split('//').concat([ 2250 encodeURIComponent(myCutLine), 2251 encodeURIComponent(myCutStage), 2252 encodeURIComponent(myCutJob), 2253 myCutStatus 2254 ]) 2255 ).slice(0,6);// 2256 var myEntry=entryArray.slice(0,2).join( "//" );//管理情報を外してSCi部のみ抽出 2257 var currentEntry=serviceAgent.currentRepository.entry(myCut.description);//既登録エントリを確認 2258 if(currentEntry) {console.log(decodeURIComponent(myCut.description));console.log(currentEntry);console.log(currentEntry.remove());console.log('current entry removed')} 2259 //登録されていた場合はあらかじめ削除しておく 2260 var newEntry = new listEntry(entryArray.join('//'),currentTitle.token,myEpisode.token,myCutToken); 2261 newEntry.parent = serviceAgent.currentRepository; 2262 serviceAgent.currentRepository.entryList.push(newEntry); 2263 // エントリ配下にversionsがあればそのままpush 2264 if(! myCut.versions) myCut.versions=[]; 2265 for (var vid = 0;vid<myCut.versions.length;vid++){ 2266 var myVersionString=(myCut.versions[vid].description)? 2267 myCut.versions[vid].description:entryArray.join("//"); 2268 var myVersionToken = myCut.versions[vid].version_token; 2269 newEntry.push(myVersionString,currentTitle.token,myEpisode.token,myCut.token,myVersionToken); 2270 } 2271 //============エントリ更新 2272 } 2273 } 2274 if(callback instanceof Function){ 2275 callback(); 2276 }else{ 2277 documentDepot.documentsUpdate(); 2278 } 2279 }, 2280 error : function(result){ 2281 if(dbg) console.log('getSCi ::'); 2282 if(dbg) console.log(result); 2283 if(callback2 instanceof Function){callback2();} 2284 }, 2285 beforeSend: serviceAgent.currentRepository.service.setHeader 2286 }); 2287 }; 2288 2289 /** 2290 リポジトリ内のentryListを更新する 2291 documentsDataの更新が必要なケースでは、force スイッチを置く 2292 force スイッチが与えられるかまたはプロダクトリストに値がない場合はプロダクトの取得から処理が開始され 2293 現在のリストはクリアされずに(バッファリストを作って比較)更新が行われる 2294 2295 このメソッド自体 サービス内のエントリを取得してentryListを更新するのが目的なので 2296 一括取得をやめるまたはこのメソッドの再帰的な呼び出しをやめるかいずれかの処置が必要 2297 getProductsからの再呼び出しは再クリアがあるのでOK 2298 それ以外のメソッドからの再呼び出しは厳禁 2299 代わりに entryListに編集メソッドを設けて出力はそちらにつなぐものとする 2300 entryList.put(entry) エントリを加える 同じidfのエントリは上書きする 2301 entryList.remove(idf) エントリを削除する idf指定 2302 entryList.get(idf) エントリを加える 同じトークンのエントリは上書きする 2303 2304 2305 documentDepot.documents は serviceAgent.currentRepository.entryList への参照 2306 2307 更新時点の新規データを常に参照可能 リポジトリを切り替える際に参照を切り替えれば、特に問題はない? 2308 2309 オブジェクトをクリアしなければ問題ないはず 2310 entryListの機能性を高めてスタティックオブジェクト化する 2311 2312 getList等のentryListを更新するメソッドはリストのメソッドを使ってリストを更新する 2313 2314 store(listEntry) 2315 2316 2317 */ 2318 NetworkRepository.prototype.getList_=function (force,callback){ 2319 //console.log("clear entryList \n rebuild entryList from documentsData"); console.log(this.productsData); console.log('++==%%'); 2320 2321 this.entryList.length=0;//エントリリスト初期化 2322 var newList = []; //新規配列作成 2323 if((force)||(serviceAgent.currentRepository.productsData.length==0)) { 2324 // forceオプションが指定されるかまたはプロダクトエントリがまだ無いケース 2325 //プロダクト取得を設定して手続を一旦終了 2326 serviceAgent.currentRepository.getProducts(); 2327 return;//一旦処理を中断 getProductsの最終工程でgetListが再度呼び出される 2328 }else{ 2329 //プロダクト情報更新 2330 for(var idx = 0 ;idx < serviceAgent.currentRepository.productsData.length ;idx ++){ 2331 var currentTitle = serviceAgent.currentRepository.productsData[idx];//Object取得 2332 if(typeof currentTitle.episodes == "undefined"){ 2333 if(! force){console.log('skip :'+ currentTitle.name) ;continue;} 2334 serviceAgent.currentRepository.productsUpdate(function(){ 2335 serviceAgent.currentRepository.getEpisodes(false,false,currentTitle.token); 2336 },false,currentTitle.token); 2337 return; 2338 } 2339 if( currentTitle.episodes[0].length == 0 ) continue; 2340 for(var eid = 0 ;eid < serviceAgent.currentRepository.productsData[idx].episodes[0].length ; eid ++){ 2341 var currentEpisode = currentTitle.episodes[0][eid]; 2342 if(typeof currentEpisode.cuts == "undefined"){ 2343 if(! force){console.log('skip :'+currentEpisode.name) ;continue;} 2344 serviceAgent.currentRepository.episodesUpdate(false,false,currentEpisode.token); 2345 return;//中断 2346 } 2347 //console.log('products check clear');console.log(currentEpisode); 2348 // if( currentEpisode.cuts.length==1){serviceAgent.currentRepository.getSCi(false,false,currentEpisode.token);return;} 2349 if( currentEpisode.cuts[0].length == 0 ) continue; 2350 for(var cid = 0 ; cid < currentEpisode.cuts[0].length ;cid ++){ 2351 /* 2352 管理情報は識別子から取得する 2353 APIの情報は、識別子と一致しているはずだが 照合の上異なる場合はAPIの情報で上書きを行う 2354 識別子として cut.description を使用 上位情報は、エントリから再作成 2355 サブタイトルは episode.discriptionを使用 2356 兼用カット情報はペンディング 2357 */ 2358 var myCutToken = currentEpisode.cuts[0][cid].token; 2359 var myCutLine = (currentEpisode.cuts[0][cid].line_id)? 2360 currentEpisode.cuts[0][cid].line_id: 2361 (new XpsLine(nas.pmdb.pmTemplate.members[0].line.toString())).toString(true); 2362 var myCutStage = (currentEpisode.cuts[0][cid].stage_id)? 2363 currentEpisode.cuts[0][cid].stage_id: 2364 (new XpsStage(nas.pmdb.pmTemplate.members[0].stages[0].toString())).toString(true); 2365 var myCutJob = (currentEpisode.cuts[0][cid].job_id)? 2366 currentEpisode.cuts[0][cid].job_id: 2367 (new XpsStage(nas.pmdb.jobNames.members[0].toString())).toString(true); 2368 var myCutStatus= (currentEpisode.cuts[0][cid].status)? 2369 currentEpisode.cuts[0][cid].status:'Startup'; 2370 2371 //管理情報が不足の場合は初期値で補う description情報が未登録の場合は、APIの情報からビルドする? 2372 if(! currentEpisode.cuts[0][cid].description){ 2373 currentEpisode.cuts[0][cid].description=""; 2374 if(dbg) console.log(currentEpisode.cuts[0][cid]); 2375 }; 2376 var entryArray = ( 2377 String(currentEpisode.cuts[0][cid].description).split('//').concat([ 2378 encodeURIComponent(myCutLine), 2379 encodeURIComponent(myCutStage), 2380 encodeURIComponent(myCutJob), 2381 myCutStatus 2382 ]) 2383 ).slice(0,6);// 2384 2385 var myEntry=entryArray.slice(0,2).join( "//" );//管理情報を外してSCi部のみ抽出 2386 var currentEntry=serviceAgent.currentRepository.entry(currentEpisode.cuts[0][cid].description);//既登録エントリを確認 2387 if(currentEntry){ 2388 //データ構造上このパートが実行されるケースは無い…はず versionIDがつかない=エラーエントリになる 2389 currentEntry.push(entryArray.slice(2).join("//"),currentTitle.token,currentEpisode.token,myCutToken); 2390 }else{ 2391 var newEntry = new listEntry(entryArray.join('//'),currentTitle.token,currentEpisode.token,myCutToken); 2392 newEntry.parent = serviceAgent.currentRepository; 2393 serviceAgent.currentRepository.entryList.push(newEntry); 2394 // エントリ配下にversionsがあればそのままpush 2395 if(! currentEpisode.cuts[0][cid].versions){ 2396 currentEpisode.cuts[0][cid].versions=[];// 2397 // console.log(currentEpisode.cuts[0][cid]); 2398 }; 2399 for (var vid = 0;vid<currentEpisode.cuts[0][cid].versions.length;vid++){ 2400 var myVersionString=(currentEpisode.cuts[0][cid].versions[vid].description)? 2401 currentEpisode.cuts[0][cid].versions[vid].description:entryArray.join("//"); 2402 var myVersionToken = currentEpisode.cuts[0][cid].versions[vid].version_token; 2403 if(dbg) console.log("push entry : "+ myVersionString); 2404 newEntry.push(myVersionString,currentTitle.token,currentEpisode.token,myCutToken,myVersionToken); 2405 } 2406 } 2407 };//エピソード更新ループ終了 2408 };//プロダクト更新ループ終了 2409 } 2410 } 2411 documentDepot.documentsUpdate(); 2412 //現在すべてのデータを取得後にドキュメントブラウザの更新を行っているためレスポンスが途絶える 2413 //これを解消するためにドキュメントブラウザが逐次更新を行えるように改装を行う 2414 if(callback instanceof Function) callback(); 2415 // return serviceAgent.currentRepository.entryList.length; 2416 } 2417 /* 2418 サーバから情報を取得してproductsDataを更新する 2419 entryListの更新は行わない 2420 */ 2421 NetworkRepository.prototype.getList=function (force,callback){ 2422 //console.log('networkRepository getList'); 2423 alert('getList');return false; 2424 if(callback instanceof Function){callback();}else{documentDepot.documentsUpdate(this.entryList);} 2425 return; 2426 2427 if((force)||(serviceAgent.currentRepository.productsData.length==0)) { 2428 // forceオプションが指定されるかまたはプロダクトエントリがまだ無いケース 2429 //プロダクト取得を呼び出して手続を一旦終了 2430 setTimeout(function (){serviceAgent.currentRepository.getProducts(callback)},10); 2431 return; 2432 }else{ 2433 //プロダクト情報更新 2434 //getProductsメソッドの一部として同様の処理が行わるれる? 2435 for(var idx = 0 ;idx < serviceAgent.currentRepository.productsData.length ;idx ++){ 2436 var currentTitle = serviceAgent.currentRepository.productsData[idx];//Object取得 2437 if(typeof currentTitle.episodes == "undefined"){ 2438 if(! force){console.log('skip :'+ currentTitle.name) ;continue;} 2439 serviceAgent.currentRepository.productsUpdate(function(){ 2440 serviceAgent.currentRepository.getEpisodes(false,false,currentTitle.token); 2441 },false,currentTitle.token); 2442 return; 2443 } 2444 if( currentTitle.episodes[0].length == 0 ) continue; 2445 for(var eid = 0 ;eid < serviceAgent.currentRepository.productsData[idx].episodes[0].length ; eid ++){ 2446 var currentEpisode = currentTitle.episodes[0][eid]; 2447 if(typeof currentEpisode.cuts == "undefined"){ 2448 if(! force){console.log('skip :'+currentEpisode.name) ;continue;} 2449 serviceAgent.currentRepository.episodesUpdate(false,false,currentEpisode.token); 2450 return;//中断 2451 } 2452 //console.log('products check clear');console.log(currentEpisode); 2453 // if( currentEpisode.cuts.length==1){serviceAgent.currentRepository.getSCi(false,false,currentEpisode.token);return;} 2454 if( currentEpisode.cuts[0].length == 0 ) continue; 2455 for(var cid = 0 ; cid < currentEpisode.cuts[0].length ;cid ++){ 2456 } 2457 };//エピソード更新ループ終了 2458 documentDepot.updateOpusSelector(); 2459 };//プロダクト更新ループ終了 2460 } 2461 //現在すべてのデータを取得後にドキュメントブラウザの更新を行っているためレスポンスが途絶える 2462 //これを解消するためにドキュメントブラウザが逐次更新を行えるように改装を行う 2463 if(callback instanceof Function){ 2464 callback(); 2465 }else{ 2466 documentDepot.documentsUpdate(); 2467 }; 2468 } 2469 /** 2470 productsDataをentryListに変換するプロシジャ 2471 独立してなるべく高速に処理 2472 変換のみリスト取得は試みない 2473 */ 2474 NetworkRepository.prototype.convertPDEL=function (){ 2475 console.log("clear entryList \n rebuild entryList from documentsData"); console.log(this.productsData); console.log('++==%%'); 2476 this.entryList.length=0;//エントリリスト初期化 2477 var newList = []; //新規配列作成 2478 //プロダクト情報構築 2479 for(var idx = 0 ;idx < serviceAgent.currentRepository.productsData.length ;idx ++){ 2480 var currentTitle = serviceAgent.currentRepository.productsData[idx];//Object取得 2481 console.log(currentTitle); 2482 if((typeof currentTitle.episodes == "undefined")||( currentTitle.episodes[0].length == 0 )) continue; 2483 //エピソード未登録タイトルはカットが存在しないので処理スキップ 2484 for(var eid = 0 ;eid < serviceAgent.currentRepository.productsData[idx].episodes[0].length ; eid ++){ 2485 console.log(serviceAgent.currentRepository.productsData[idx].episodes[0][eid]); 2486 var currentEpisode = currentTitle.episodes[0][eid]; 2487 if((typeof currentEpisode.cuts == "undefined")||( currentEpisode.cuts[0].length == 0 )) continue; 2488 for(var cid = 0 ; cid < currentEpisode.cuts[0].length ;cid ++){ 2489 /* 2490 管理情報をビルド 2491 APIの情報は、識別子と一致しているはずだが 照合の上異なる場合はAPIの情報で上書きを行う 2492 識別子として cut.description を使用 上位情報は、エントリから再作成 2493 サブタイトルは episode.discriptionを使用 2494 兼用カット情報はペンディング 2495 */ 2496 2497 var myCut = currentEpisode.cuts[0][cid]; 2498 console.log(myCut); 2499 console.log(xUI.XPS.currentStatus); 2500 if((! myCut.currentStatus)&&(myCut.description)){ 2501 console.log('no currentStatus'); 2502 myCut.line_id="0:trunk"; 2503 myCut.stage_id="0:noname"; 2504 myCut.job_id="0:init"; 2505 myCut.status="Startup"; 2506 } 2507 //管理情報が不足の場合は初期値で補う 初期値の設定はダミー 2508 2509 if (myCut.description){ 2510 console.log(decodeURIComponent(myCut.description)); 2511 var myIdentifier = myCut.description; 2512 2513 2514 2515 }else{ 2516 2517 if(! myCut.line_id) myCut.line_id =(new XpsLine(nas.pmdb.pmTemplate.members[0])).toString(true); 2518 if(! myCut.stage_id) myCut.stage_id =(new XpsStage(nas.pmdb.pmTemplate.members[0].stages.getStage())).toString(true); 2519 if(! myCut.job_id) myCut.job_id =(new XpsStage(nas.pmdb.jobNames.getTemplate(nas.pmdb.pmTemplate.members[0].stages.getStage(),"init")[0])).toString(true); 2520 if(! myCut.status) myCut.status =(new JobStatus("Startup")).toString(true); 2521 2522 var myIdentifier = encodeURIComponent(currentTitle.name); 2523 myIdentifier += '#' + encodeURIComponent(currentEpisode.name); 2524 myIdentifier += (currentEpisode.description)? '['+encodeURIComponent(currentEpisode.description) + ']':''; 2525 myIdentifier += '//'+encodeURIComponent(myCut.name); 2526 myIdentifier += '//'+([ 2527 encodeURIComponent(myCut.line_id), 2528 encodeURIComponent(myCut.stage_id), 2529 encodeURIComponent(myCut.job_id), 2530 encodeURIComponent(myCut.status) 2531 ]).join('//'); 2532 myCut.description=myIdentifier;//description情報が未登録の場合は、APIの情報からビルドした識別子を登録 2533 } 2534 console.log(myCut.description); 2535 console.log(decodeURIComponent(myCut.description)); 2536 2537 var entryArray = myIdentifier.split('//').slice(0,6);// 2538 var myEntry=entryArray.slice(0,2).join( "//" );//管理情報を外してSCi部のみ抽出 2539 var currentEntry=serviceAgent.currentRepository.entry(currentEpisode.cuts[0][cid].description);//既登録エントリを確認 2540 console.log(currentEntry); 2541 console.log(entryArray.slice(2).join("//"),currentTitle.token,currentEpisode.token,myCut.token); 2542 if(currentEntry){ 2543 /* 2544 ネットワークリポジトリの場合は、同カットが二重にプロダクトデータに存在することはない。 2545 存在した場合はエラーを記録してNOP 2546 */ 2547 console.log('error : エントリ重複検出');console.log(currentEntry); 2548 }else{ 2549 //当該カットが無いので新規にエントリ 2550 console.log([entryArray.join('//'),currentTitle.token,currentEpisode.token,myCut.token]); 2551 // var newEntry = new listEntry(entryArray.slice(0,2).join('//'),currentTitle.token,currentEpisode.token,myCut.token); 2552 var newEntry = new listEntry(myCut.description,currentTitle.token,currentEpisode.token,myCut.token); 2553 newEntry.parent = serviceAgent.currentRepository; 2554 serviceAgent.currentRepository.entryList.put(newEntry); 2555 console.log(newEntry.issues[0].toString()); 2556 console.log(serviceAgent.currentRepository.entryList); 2557 }; 2558 // エントリ配下にversionsがあるはずなのでissuesをクリアしてデータをpush 2559 // versionsが存在しない場合のみissuesに規定値が残る 2560 if(! myCut.versions){ myCut.versions=[]}; 2561 for (var vid = 0;vid < myCut.versions.length;vid++){ 2562 var myVersionString=(myCut.versions[vid].description)? 2563 myCut.versions[vid].description:entryArray.join("//"); 2564 var myVersionToken = myCut.versions[vid].version_token; 2565 if(vid == 0){ 2566 //第一要素のみ 上書き処理 2567 console.log('既存のissuesを上書き'); 2568 console.log(entryArray); 2569 console.log(myCut); 2570 console.log(newEntry.issues[0]); 2571 // newEntry.issues[0][0]=''; 2572 // newEntry.issues[0][1]=''; 2573 // newEntry.issues[0][2]=''; 2574 // newEntry.issues[0][3]=''; 2575 // newEntry.issues[0].time=''; 2576 newEntry.issues[0].cutID=myCut.token; 2577 newEntry.issues[0].identifier=myVersionString; 2578 newEntry.issues[0].versionID=myVersionToken; 2579 }else{ 2580 console.log("push entry : "+ myVersionString); 2581 newEntry.push( 2582 myVersionString, 2583 currentTitle.token, 2584 currentEpisode.token, 2585 myCut.token, 2586 myVersionToken 2587 ); 2588 }; 2589 };//バージョンループ 2590 };//カットループ 2591 };//エピソードループ 2592 };//プロダクトループ 2593 console.log('XXXXXX'); 2594 console.log(serviceAgent.currentRepository.entryList) 2595 documentDepot.documentsUpdate(); 2596 } 2597 /** 2598 online-sigleモード用にエントリを一つだけ(高速に)作って固定する 2599 2600 以下の構造の productsDataを組む 2601 2602 タイトル/詳細は、該当タイトル一つのみ 2603 エピソード/詳細も当該カットの親一つのみ 2604 カットも当該カット一つのみ 2605 2606 NetworkRepository.prototype.buildProducts=function(){ 2607 serviceAgent.currentServer.getRepositories(function(){ 2608 serviceAgent.currentRepository.getEntry(); 2609 }); 2610 } 2611 */ 2612 /** 2613 識別子(ユーザの選択)を引数にして実際のデータを取得 2614 識別子に管理情報が付いている場合はそれを呼ぶ 2615 管理情報なしの場合は、当該エントリの最新ジョブの内容を呼ぶ 2616 管理情報が未fixの場合は編集エリア、既fixの場合はリファレンスエリアに読み込む 2617 2618 ターゲットジョブに先行するジョブがある場合は、そのジョブをリファレンスとしてコールバック内で呼ぶ 2619 2620 動作仕様調整 2621 識別子引数は同じだが、完全型式の引数+動作を渡してここでは判定を行わないように変更 2622 判定はブラウザ又はサービスエージェントの同名関数が行う 2623 引数の自動補完もしない 2624 2625 サーバからの読み出し後に、データ照合を行ってデータから生成される識別子がサーバの識別子と一致するように調整 2626 サーバ側指定を優先してデータは自動更新される 2627 詳細情報を受け取った際に補助情報又は受け取ったオブジェクトそのものをバックアップすること 2628 2629 UATサーバに対する請求の際に、識別子のかわりにtokenを使用可能にする。 2630 (targetInfo.title == myIdentifier)であった場合のみcutTokenとして扱う? 2631 2632 */ 2633 NetworkRepository.prototype.getEntry=function (myIdentifier,isReference,callback,callback2){ 2634 if(typeof isReference == 'undefined'){isReference = false;} 2635 //識別子をパース 2636 var targetInfo = Xps.parseIdentifier(myIdentifier);//? 2637 var myIssue = false; 2638 var refIssue = false; 2639 /* 2640 if (targetInfo.title == myIdentifier){ 2641 //トークンが直接与えられたものと判断する 2642 var targetURL='/api/v2/cuts/'+myIdentifier+'.json'; 2643 } else {} 2644 */ 2645 //識別子からトークンを得る 2646 var myEntry = this.entry(myIdentifier); 2647 var myCut = this.cut(myEntry.issues[0].cutID); 2648 console.log(myEntry); 2649 if((! myEntry)||(! myCut)){ 2650 var msg=localize({en:"no entry %1 in DB",ja:"DBからエントリ%1の取得に失敗しました"},decodeURIComponent(myIdentifier)); 2651 alert(msg); 2652 console.log(myEntry); 2653 console.log(myCut); 2654 console.log(serviceAgent.currentRepository); 2655 console.log("noEntry : "+ decodeURIComponent(myIdentifier));//プロダクトが無い 2656 return false; 2657 } 2658 if(! targetInfo.currentStatus){ 2659 //ターゲットに管理部分がないので、最新のissueとして補う 2660 var cx = myEntry.issues.length-1; 2661 myIssue = myEntry.issues[cx]; 2662 }else{ 2663 //指定管理部分からissueを特定する 連結して比較(後方から検索)リスト内に指定エントリがなければ失敗 2664 checkIssues:{ 2665 for (var cx = (myEntry.issues.length-1) ; cx >= 0 ;cx--){ 2666 if ( Xps.compareIdentifier(myEntry.issues[cx].identifier,myIdentifier) > 4){ 2667 myIssue = myEntry.issues[cx]; 2668 break checkIssues; 2669 } 2670 } 2671 if (! myIssue){ 2672 if(dbg) console.log( 'no target data :'+ decodeURIComponent(myIdentifier) );//ターゲットのデータが無い 2673 return false; 2674 } 2675 } 2676 } 2677 // 構成済みの情報を判定 (リファレンス置換 or 新規セッションか) 2678 // myIssue; これがカットへのポインタ episode.cuts配列のエントリ myIssue.url にアドレスあり 2679 // urlプロパティが無い場合はid があるのでidからurlを作成する 2680 if(! myIssue.versionID){ 2681 var targetURL=(myIssue.url)? myIssue.url: '/api/v2/cuts/'+myIssue.cutID.toString()+'.json'; 2682 }else{ 2683 var targetURL=(myIssue.url)? myIssue.url: '/api/v2/cuts/'+myIssue.cutID.toString()+'/'+String(myIssue.versionID)+'.json'; 2684 if(dbg) console.log(targetURL); 2685 } 2686 2687 if(! isReference){ 2688 /** 2689 暫定補助情報フォーマット 2690 product.name 2691 decoded name 2692 product.description 2693 episode.name 2694 decoded name 2695 episode.description 2696 decoded subtitle 2697 cut.name 2698 decoded name 2699 cut.description 2700 identifier-fullformat 2701 */ 2702 $.ajax({ 2703 url: this.url + targetURL, 2704 type: 'GET', 2705 dataType: 'json', 2706 success: function(result) { 2707 //console.log(result); 2708 //データ請求に成功したので、現在のデータを判定して処理の必要があれば処理 2709 var myContent=result.data.cut.content;//XPSソーステキストをセット 2710 var currentXps = new Xps(); 2711 if(myContent){ 2712 currentXps.parseXps(myContent); 2713 }else{ 2714 /* 2715 サーバリザルトにタイムシートの内容が含まれない場合は、登録直後の空白データ 2716 以下の情報を取得して空のタイムシートをビルドする 2717 タイトル、エピソード 2718 タイトルのフレームレート(ない場合はシステムデフォルト) 2719 識別子に含まれるカット番号 あれば カット尺(ない場合はシステムデフォルト) 2720 */ 2721 //console.log('contents :'+ myContent); 2722 var myParseData = Xps.parseSCi(result.data.cut.name); 2723 currentXps.cut = myParseData.cut; 2724 currentXps.setDuration(nas.FCT2Frm(String(myParseData.time))); 2725 } 2726 //myContent==nullのケースは、サーバに空コンテンツが登録されている場合なので単純にエラー排除してはならない 2727 //currentXpsのプロパティをリザルトに同期させる 2728 //エラーではなく初期化時点の初期状態のXpsのままで処理を継続する 2729 //xUI.userPermissions=result.data.cut.permissions; 2730 //読み込んだXPSが識別子と異なっていた場合識別子優先で同期する 2731 xUI.resetSheet(currentXps); 2732 var durationChange=xUI.XPS.duration(); 2733 //console.log(xUI.XPS); 2734 //console.log(myIssue.identifier); 2735 // xUI.XPS.syncIdentifier(myIssue.identifier,false); 2736 xUI.XPS.syncIdentifier(myIssue.identifier,true); 2737 durationChange = (durationChange == xUI.XPS.duration())? false:true; 2738 if(myEntry.issues.length>1){ 2739 documentDepot.currentReference = new Xps(5,144);//空オブジェクトをあらかじめ新規作成 2740 //自動設定されるリファレンスはあるか? 2741 //指定管理部分からissueを特定する 文字列化して比較 2742 if ( cx > 0 ){ 2743 if(parseInt(decodeURIComponent(myIssue[2]).split(':')[0]) > 0 ){ 2744 //ジョブIDが1以上なので 単純に一つ前のissueを選択する 2745 //必ず先行jobがある = 通常処理の場合は先行JOBが存在するが、単データをエントリした場合 そうではないケースがあるので対処が必要 2016 12 29 2746 refIssue = myEntry.issues[cx-1]; 2747 }else if(decodeURIComponent(myIssue[1]).split(':')[0] > 0 ){ 2748 //第2ステージ以降前方に向かって検索 2749 //最初にステージIDが先行IDになった要素が参照すべき要素 2750 for(var xcx = cx-1 ;xcx >= 0 ; xcx --){ 2751 if (parseInt(decodeURIComponent(myEntry.issues[xcx][1]).split(':')[0]) == (parseInt(decodeURIComponent(myIssue[1]).split(':')[0])-1)){ 2752 refIssue = myEntry.issues[xcx]; 2753 break; 2754 } 2755 } 2756 };//cx==0 のケースでは、デフォルトで参照すべき先行ジョブは無い 2757 } 2758 if(refIssue) serviceAgent.currentRepository.getEntry(refIssue.identifier,true); 2759 } 2760 //xUI.resetSheet(XPS); 2761 xUI.sessionRetrace = myEntry.issues.length-cx-1; 2762 xUI.setUImode('browsing');sync("productStatus"); 2763 xUI.flushUndoBuf();sync('undo');sync('redo'); 2764 if(durationChange) xUI.resetSheet(); 2765 if(callback instanceof Function) callback(); 2766 }, 2767 error:function(result){ 2768 if(dbg) console.log(result); 2769 if(callback2 instanceof Function) callback2(); 2770 }, 2771 beforeSend: this.service.setHeader 2772 }); 2773 2774 }else{ 2775 //データ単独で現在のセッションのリファレンスを置換 2776 $.ajax({ 2777 url: this.url + targetURL, 2778 type: 'GET', 2779 dataType: 'json', 2780 success: function(result) { 2781 var myContent=result.data.cut.content;//XPSソーステキストをセット 2782 if(dbg) console.log('import Reference'+myContent); 2783 documentDepot.currentReference=new Xps(); 2784 documentDepot.currentReference.readIN(myContent); 2785 xUI.setReferenceXPS(documentDepot.currentReference); 2786 if(callback instanceof Function) callback(); 2787 }, 2788 error: function(result){ 2789 if(dbg) console.log(result); 2790 if(callback2 instanceof Function) callback2(); 2791 }, 2792 beforeSend: this.service.setHeader 2793 }); 2794 } 2795 return null; 2796 } 2797 /** 2798 標準コールバックを作る 2799 コールバック関数が引数で与えられなかった場合は xUIに新規Xpsとして与えて読み込ませる 2800 読み出したエントリに前方のジョブがあれば、それをリファレンスとして与えるルーチンも必要 2801 2802 function(result){ 2803 var myContent=result.data.cut.content;//XPSソーステキストをセット 2804 //以下が標準の読み込み時の初期化 2805 if(xUI.XPS.readIN(myContent)){xUI.resetSheet(xUI.XPS);} 2806 if(that. 2807 } 2808 function(result){ 2809 var myContent=result.data.cut.content;//XPSソーステキストをセット 2810 myXps=new Xps(); 2811 xUI.setReferenceXPS(myXps) 2812 } 2813 外部からコールバックを与える場合は、以下のようなケース 2814 未fixのXPSをリファレンスペインに読み込む操作(これに関してはオプションをつけたほうが良さそう?) 2815 */ 2816 /** 2817 DBにタイトルを作成する。 2818 confirmなし 呼び出し側で済ませること 2819 必要あれば編集UI追加 2820 引数: 2821 タイトル(必須) 2822 備考テキスト 2823 Pmオブジェクト 2824 コールバック関数2種 2825 戻値: 2826 なし 2827 2828 識別子は受け入れない 必要に従って前段で分解のこと 2829 */ 2830 NetworkRepository.prototype.addTitle=function (myTitle,myDescription,myPm,callback,callback2){ 2831 /* 2832 識別子を検出(呼び出し側で)このルーチンまで来た場合は、引数を分解しておくこと 2833 2017.01.28時点でAPIにtemplateが出ていないのでpmの処理は省略 遅延で詳細編集を行っても良い 2834 serviceAgent.currentRepository.addTitle("tST2","testTitlewith API") 2835 作成時に検査を行い、既存タイトルならば処理を中断する(呼び出し側で) 2836 タイトル作成前に確認メッセージを出す(これも呼び出し側) 2837 現在はPmオブジェクトは機能していない 2/9 2017 2838 */ 2839 if(! myTitle) return false; 2840 if(! myDescription) myDescription=""; 2841 // var parseData = Xps.parseIdentifier(myTitle); 2842 // if(parseData){myTitle=parseData.title}; 2843 var data = { 2844 product: { 2845 name : myTitle, 2846 description : myDescription, 2847 framerate : nas.FRATE, 2848 } 2849 }; 2850 2851 $.ajax({ 2852 type : 'POST', 2853 url : serviceAgent.currentRepository.url+"/api/v2/products.json", 2854 data : data, 2855 success : function(result) { 2856 if(dbg) console.log('success'); 2857 if(dbg) console.log(result); 2858 if(callback instanceof Function) callback(); 2859 }, 2860 error:function(result) { 2861 if(dbg) console.log('error'); 2862 if(dbg) console.log(result); 2863 if(callback2 instanceof Function) callback2(); 2864 }, 2865 beforeSend: serviceAgent.currentRepository.service.setHeader 2866 }); 2867 } 2868 /** 2869 DBにOPUS(エピソード)を作成する。 2870 引数 2871 タイトルを含む識別子 カット番号は求めない 2872 コールバック関数2種 2873 識別子のみ受け入れ 2874 このルーチンを呼び出す時点で、タイトルは存在すること 2875 手続的には、カット作成を主眼にして 2876 Title/Opus 等の上位のオブジェクトが存在しない時点で自動でコールされるように調整する? 2877 2878 */ 2879 NetworkRepository.prototype.addOpus=function (myIdentifier,prodIdentifier,callback,callback2){ 2880 /* 2881 listEntry.titleID 2882 */ 2883 var parseData = Xps.parseIdentifier(myIdentifier); 2884 if(! parseData){ 2885 if(callback2 instanceof Function) callback2; 2886 return; 2887 } 2888 var myProduct = parseData.product; 2889 2890 var myEntry=false; 2891 if(typeof prodIdentifier == 'undefined'){ 2892 for (var pid=0;pid<documentDepot.products.length;pid ++){ 2893 //productsのメンバをオブジェクト化したほうが良いかも 2894 var prdInfo=Xps.parseProduct(documentDepot.products[pid]); 2895 if(prdInfo.title==myProduct.title) { 2896 myEntry = serviceAgent.currentRepository.entry(documentDepot.products[pid]); 2897 break; 2898 } 2899 }; 2900 }else{ 2901 myEntry = serviceAgent.currentRepository.entry(prodIdentifier+"//",true); 2902 } 2903 if(!myEntry){ 2904 if(callback2 instanceof Function) callback2; 2905 return; 2906 } 2907 var data = { 2908 episode: { 2909 product_token : myEntry.productID, 2910 name : myProduct.opus, 2911 description : myProduct.subtitle 2912 } 2913 }; 2914 2915 $.ajax({ 2916 type : 'POST', 2917 url : serviceAgent.currentRepository.url+"/api/v2/episodes.json", 2918 data : JSON.stringify(data), 2919 success : function(result) { 2920 if( callback instanceof Function) callback(); 2921 }, 2922 error:function(result) { 2923 if( callback2 instanceof Function) callback2(); 2924 }, 2925 beforeSend: serviceAgent.currentRepository.service.setHeader 2926 }); 2927 } 2928 /** 2929 データオブジェクトを渡してリポジトリにプッシュする 2930 一致エントリがあれば上書き 2931 一致エントリで先行の管理情報がロックされている場合はリジェクト 2932 管理情報の世代が上がっていれば追加の管理情報を添えて保存 2933 タイトルがDBに登録されていない場合は、ユーザの確認をとってタイトルを作成 2934 エピソードがDBに登録されていない場合も同様 2935 2936 これは保存系のAPIが出てから調整 2937 */ 2938 2939 NetworkRepository.prototype.pushEntry=function (myXps,callback,callback2){ 2940 //識別子取得(全要素で取得) 2941 var myIdentifier=Xps.getIdentifier(myXps,true); 2942 //識別子に相当するアイテムがリポジトリに存在するかどうかをチェック 2943 var currentEntry = this.entry(myIdentifier); 2944 // var currentCut = this.cut(myIdentifier); 2945 var currentCut = this.cut(currentEntry.issues[0].cutID); 2946 if(currentEntry){ 2947 //既存のエントリが有るのでストレージとリストにpushして処理終了 2948 this.pushData('PUT',currentEntry,myXps,callback,callback2) 2949 }else{ 2950 /** 2951 currentEntry==null なので、ターゲットのエピソードtokenを再取得して引数で渡す必要あり 12・21 2952 */ 2953 //新規エントリなので新たにPOSTする (空エントリを引数に付ける) 2954 // var tmpEntry= new listEntry(Xps.getIdentifier(myXps)); 2955 var tmpEntry= this.entry(Xps.getIdentifier(myXps),true); 2956 this.pushData('POST',tmpEntry,myXps,callback,callback2) 2957 } 2958 }; 2959 /** 2960 サーバにデータを送信する(メンテナンスメソッド) 2961 引数: 2962 メソッド 2963 myProduct 2964 Xpsオブジェクト 2965 成功時コールバック関数 2966 失敗時コールバック関数 2967 2968 リポジトリ上に既存エントリはPUT 新規エントリはPOSTで 送信 2969 タイトルや、エピソードが存在しないデータはリジェクト 2970 オンサイト時は 各種データをbackend_variablesから取得 2971 それ以外の場合は、documentDepotから取得をトライする 2972 取得に失敗した場合は送信失敗 2973 2974 エントリリスト等の内部操作は行わない 2975 2976 <span id="backend_variables" data-user_access_token="4dcb5a249c94aa21529a522e23de730f176d032d8e1e1bf621c8f09b0d733566" 2977 data-user_token="aWWMWNKW2HAfuRHWANZKbETy" 2978 data-user_name="ねこまたや" 2979 data-user_email="kiyo@nekomataya.info" 2980 data-episode_id="17" 2981 data-cut_id="24" 2982 data-episode_token="mfjVjBUuG6Q8GHu7u6nzJTa2" 2983 data-cut_token="73o16nRYK7oqNNmeGDHWizLV" 2984 data-line_id="0:(trunk)" 2985 data-stage_id="0:Startup" 2986 data-job_id="1:work" 2987 data-status="Active" 2988 ></span> 2989 myEntry を myProduct に換装 2990 listEntry > productsData.episodes[0] 2991 */ 2992 NetworkRepository.prototype.pushData=function (myMethod,myEntry,myXps,callback,callback2){ 2993 //console.log(myEntry); 2994 if (myEntry instanceof listEntry){ 2995 //エントリオブジェクト渡し 2996 var lastIssue = myEntry.issues[myEntry.issues.length-1]; 2997 2998 var title_name = myEntry.product.split('#')[0]; 2999 var episode_name = myEntry.product.split('#')[1]; 3000 var cut_name = (myMethod == 'PUT')? myEntry.sci:'s'+((myXps.scene)? myXps.scene:'-')+'c'+myXps.cut+"("+nas.Frm2FCT(myXps.time(),3,0,myXps.framerate)+")"; 3001 var line_id = myXps.line.toString(true); 3002 var stage_id = myXps.stage.toString(true); 3003 var job_id = myXps.job.toString(true); 3004 var status = myXps.currentStatus.toString(true); 3005 /* 3006 var line_id = lastIssue[0]; 3007 var stage_id = lastIssue[1]; 3008 var job_id = lastIssue[2]; 3009 var status = lastIssue[3]; 3010 */ 3011 }else{ 3012 //プロダクト(該当カットはなし) 3013 var lastIssue = ['0:','0:','0:','Startup']; 3014 3015 var title_name = myEntry.product.split('#')[1]; 3016 var episode_name = encodeURIComponent(myEntry.name); 3017 var cut_name = (myMethod == 'PUT')? myEntry.sci:'s'+((myXps.scene)? myXps.scene:'-')+'c'+myXps.cut+"("+nas.Frm2FCT(myXps.time(),30,myXps.framerate)+")"; 3018 var line_id = myXps.line.toString(true); 3019 var stage_id = myXps.stage.toString(true); 3020 var job_id = myXps.job.toString(true); 3021 var status = myXps.currentStatus.toString(true); 3022 /* 3023 var line_id = lastIssue[0]; 3024 var stage_id = lastIssue[1]; 3025 var job_id = lastIssue[2]; 3026 var status = lastIssue[3]; 3027 */ 3028 3029 } 3030 //オンサイト・シングルドキュメントバインドの場合はbackend_variablesから情報を取得 3031 if(serviceAgent.currentStatus=="online-single"){ 3032 // if(document.getElementById('backend_variables')){} 3033 var episode_token = $('#backend_variables').attr('data-episode_token'); 3034 var cut_token = $('#backend_variables').attr('data-cut_token'); 3035 }else{ 3036 var episode_token = myEntry.episodeID; 3037 var cut_token = (myMethod == 'PUT')? lastIssue.cutID:false; 3038 } 3039 //console.log(serviceAgent.currentStatus); 3040 //console.log("epToken : "+episode_token); 3041 //console.log("ctToken : "+cut_token +" :: "+ lastIssue.cutID); 3042 //console.log("ctName : "+decodeURIComponent(cut_name)); 3043 //return 3044 /** 3045 保存時に送り出すデータに 3046 タイトル・エピソード番号(文字列)・サブタイトル 3047 カット番号+カット尺 3048 を加えて送出する 3049 型式をきめこむ 3050 サーバ側では、これが保存状態と異なる場合は、エラーを返すか又は新規タイトルとして保存する必要がある。 3051 アプリケーション側は、この文字列が異なる送出を抑制して警告を出す? 3052 このメソッドは、既存のエピソードに対しての追加機能のみ 3053 タイトル作成及びエピソード作成は別に用意する 3054 */ 3055 if(myMethod=='POST'){ 3056 //新規エントリ作成 POST 3057 json_data = {cut:{ 3058 episode_token : episode_token, 3059 name : decodeURIComponent(cut_name), 3060 description : Xps.getIdentifier(myXps,true), 3061 status : myXps.currentStatus.toString(true), 3062 job_id : decodeURIComponent(myXps.job.toString(true)), 3063 stage_id : decodeURIComponent(myXps.stage.toString(true)), 3064 line_id : decodeURIComponent(myXps.line.toString(true)), 3065 content : myXps.toString() 3066 }}; 3067 method_type = 'POST'; 3068 target_url = '/api/v2/cuts.json'; 3069 }else{ 3070 //エントリ更新 PUT 3071 json_data = { 3072 token: cut_token, 3073 cut:{ 3074 name : decodeURIComponent(cut_name), 3075 // description : myEntry.toString(true), 3076 description : Xps.getIdentifier(myXps,true), 3077 content : myXps.toString(), 3078 // cut_token : cut_id, 3079 // title_name : title_name, 3080 // episode_name: episode_name, 3081 // cut_name : cut_name, 3082 line_id : decodeURIComponent(line_id), 3083 stage_id : decodeURIComponent(stage_id), 3084 job_id : decodeURIComponent(job_id), 3085 status : status 3086 }}; 3087 method_type = 'PUT'; 3088 target_url = '/api/v2/cuts/' + cut_token + '.json' 3089 } 3090 if((typeof cut_token == 'undefined')||(cut_token == 'undefined')){console.log(myXps);console.log(myEntry);} 3091 /* 3092 開発中の 制作管理DB/MAP/XPS で共通で使用可能なnas.SCInfoオブジェクトを作成中 3093 これに一意のIDを持たせる予定です。 3094 */ 3095 if(dbg) console.log(method_type+' :'+serviceAgent.currentRepository.url+target_url +'\n' +JSON.stringify(json_data)); 3096 $.ajax({ 3097 type : method_type, 3098 url : serviceAgent.currentRepository.url+target_url, 3099 data : JSON.stringify(json_data), 3100 contentType: 'application/JSON', 3101 dataType : 'JSON', 3102 scriptCharset: 'utf-8', 3103 success : function(result) { 3104 if (xUI.XPS === myXps) xUI.setStored('current'); 3105 sync();//保存ステータスを同期 3106 if( method_type == 'POST'){ 3107 if(dbg) console.log("new cut!"); 3108 //console.log(result); 3109 $('#backend_variables').data('cut_token', result.data.cut['token']); 3110 }else{ 3111 if(dbg) console.log('existing cut!'); 3112 } 3113 // リストプッシュ 等の内部 DB操作は前段で適用を済ませるかまたはコールバック渡しにする 3114 if(callback instanceof Function){callback();} 3115 }, 3116 error : function(result) { 3117 if(callback2 instanceof Function){callback2();} 3118 // Error 3119 //console.log("error"); 3120 //console.log(result); 3121 }, 3122 beforeSend: serviceAgent.currentRepository.service.setHeader 3123 }); 3124 }; 3125 /** 3126 ネットワークリポジトリのエントリをアプリケーションから削除することは無いので以下のメソッドは不用? 3127 APIにハードデリートとソフトデリートを出してもらう? 3128 削除が可能な条件は 3129 自分自身が開始した作業セッションであること && 最終の作業セッションであること 3130 エントリをすべて削除するにはオプションが必要 3131 識別子がフル() 3132 */ 3133 NetworkRepository.prototype.removeEntry=function (myIdentifier){ 3134 // 3135 //識別子 からエントリを特定して削除する? 3136 }; 3137 /** 3138 エントリリストを検索して該当するリストエントリを返す操作をメソッド可 3139 引数: 3140 識別子 3141 プロダクト検索オプション 3142 戻値: 3143 識別子に該当するlistEntry 3144 または episode情報 3145 データ照合に失敗した場合はnull 3146 3147 issues他のプロパティは受取先で評価 3148 指定の識別子との比較は 3149 title,opus,scene,cut の4点の比較で行う(秒数とサブタイトルは比較しない) 3150 optを加えるとtitle,opus(= product)のみを比較 3151 現在カットが0(未登録)の登録済みプロダクトの場合 true/-1 false/0 を戻す 3152 */ 3153 NetworkRepository.prototype.entry=function(myIdentifier,opt){ 3154 // if(! opt) {opt = 1}else{opt = 0}; 3155 // return this.entryList.getByIdf(myIdentifier,opt); 3156 /*--以下検証要 3157 --*/ 3158 opt = (opt)? -1 : 0; 3159 if(serviceAgent.currentRepository.entryList.length){ 3160 for (var pid=0;pid<serviceAgent.currentRepository.entryList.length;pid++){ 3161 if(Xps.compareIdentifier(serviceAgent.currentRepository.entryList[pid].toString(),myIdentifier) > opt){ 3162 return serviceAgent.currentRepository.entryList[pid] 3163 } 3164 } 3165 }else if(opt){ 3166 for (var pid=0;pid<serviceAgent.currentRepository.productsData.length;pid++){ 3167 for (var oid=0;oid<serviceAgent.currentRepository.productsData[pid].episodes[0].length;oid++){ 3168 var checkTitle = serviceAgent.currentRepository.productsData[pid].name; 3169 var checkOpus = serviceAgent.currentRepository.productsData[pid].episodes[0][oid].name; 3170 if( 3171 Xps.compareIdentifier([decodeURIComponent(checkTitle),decodeURIComponent(checkOpus)].join('#')+'//',myIdentifier) > opt 3172 ){ 3173 return opt; 3174 } 3175 } 3176 } 3177 } 3178 return null; 3179 } 3180 /** 3181 カットトークン又はエピソードトークンから識別子を取得する 3182 エピソードトークンで得られた識別子はカット番号を自動で補う 3183 タイトル等の文字列が必要な場合はダミーのカット番号を捨てる必要あり 3184 */ 3185 NetworkRepository.prototype.getIdentifierByToken=function(myToken){ 3186 search_loop: 3187 for (var pid=0;pid<this.productsData.length;pid++){ 3188 //先にカットの照合を行う 3189 //要素内に情報の不足がある場合はそのブロックをスキップする 3190 if(! this.productsData[pid].episodes) continue; 3191 for (var eid=0;eid<this.productsData[pid].episodes[0].length;eid++){ 3192 if(! this.productsData[pid].episodes[0][eid].cuts) continue; 3193 for (var cid=0;cid<this.productsData[pid].episodes[0][eid].cuts[0].length;cid++){ 3194 if(this.productsData[pid].episodes[0][eid].cuts[0][cid].token==myToken){ 3195 return this.productsData[pid].episodes[0][eid].cuts[0][cid].description; 3196 } 3197 if(this.productsData[pid].episodes[0][eid].token==myToken){ 3198 var lastName = (this.productsData[pid].episodes[0][eid].cuts[0].length)? 3199 this.productsData[pid].episodes[0][eid].cuts[0][this.productsData[pid].episodes[0][eid].cuts[0].length-1].name:'0'; 3200 var myIdentifier = encodeURIComponent(this.productsData[pid].name)+'#'+ 3201 encodeURIComponent(this.productsData[pid].episodes[0][eid].name)+ 3202 ((this.productsData[pid].episodes[0][eid].description)? 3203 '['+encodeURIComponent(this.productsData[pid].episodes[0][eid].description)+']':'' 3204 )+'//'+nas.incrStr(lastName); 3205 return myIdentifier; 3206 } 3207 } 3208 } 3209 } 3210 return null; 3211 } 3212 /** 3213 tokenの一致するproductsData内のノードエレメントを戻す 3214 product>episodes>cut の順で検索 種別指定があればそのエレメントを先に検索 3215 */ 3216 NetworkRepository.prototype.getNodeElementByToken=function(myToken,myKind){ 3217 if(! myToken) return null; 3218 if(! myKind) myKind = '*'; 3219 products: 3220 for (var pid=0;pid<this.productsData.length;pid++){ 3221 if(((myKind=="product")||(myKind=="*"))&&(this.productsData[pid].token == myToken)) 3222 return this.productsData[pid]; 3223 episodes: 3224 if(this.productsData[pid].episodes){ 3225 for (var eid=0;eid<this.productsData[pid].episodes[0].length;eid++){ 3226 // episodes[0]がトレーラー配列なので注意 3227 if(((myKind=="episode")||(myKind=="*"))&&(this.productsData[pid].episodes[0][eid].token == myToken)) 3228 return this.productsData[pid].episodes[0][eid]; 3229 cuts: 3230 if(this.productsData[pid].episodes[0][eid].cuts){ 3231 for (var cid=0;cid<this.productsData[pid].episodes[0][eid].cuts[0].length;cid++){ 3232 // if(this.productsData[pid].episodes[0][eid].cuts[0].token == myToken) return this.productsData[pid].episodes[0][eid].cuts[0]; 3233 if(((myKind=="cut")||(myKind=="*"))&&(this.productsData[pid].episodes[0][eid].cuts[0].token == myToken)) 3234 return this.productsData[pid].episodes[0][eid].cuts[0]; 3235 //cuts[0]がトレーラーオブジェクト cuts[1] を廃止する準備中 3236 }} 3237 }} 3238 } 3239 return null; 3240 } 3241 /** 3242 エントリステータス操作コマンドメソッド群 3243 ServiceAgentの同名メソッドから呼び出す下位ファンクション 3244 3245 caller側のルーチンで判定基準にしたデータが最新である保証が無いので 3246 各メソッドの書込み前にステータスの再確認が必要 3247 読み出しを前段に置いて成功時の関数内で再判定か? 3248 または、サービス側で変更要求に対する処理基準を明確にしてリジェクトを実装してもらう 2016.12.23 3249 */ 3250 /** 3251 現在のドキュメント XPS に対応するリポジトリ上のエントリをアクティベートする 3252 アクティベート前に、データの現状を取得してコールバックでアクティベート処理を渡す 3253 3254 引数:処理成功時と失敗時のコールバック関数 3255 */ 3256 NetworkRepository.prototype.activateEntry=function(callback,callback2){ 3257 var currentEntry = this.entry(Xps.getIdentifier(xUI.XPS)); 3258 // var currentCut = this.cut(currentEntry.toString()); 3259 var currentCut = this.cut(currentEntry.issues[0].cutID); 3260 if((!currentEntry)||(!currentCut)){ 3261 //console.log('noentry'); 3262 //console.log(serviceAgent.currentRepository); 3263 return false; 3264 } 3265 /* 3266 サーバからデータの最新状況を取得する 3267 ステータスを確認してから、新規のステータスを設定する 3268 */ 3269 $.ajax({ 3270 type : 'GET', 3271 url : this.url+'/api/v2/cuts/'+currentEntry.issues[0].cutID+'.json', 3272 success : function(result){ 3273 //console.log(result); 3274 /* 3275 手順 GET serverURL(token).json 3276 サーバリザルトのdescriptionから状態と内容を確認して 3277 Activate可能な場合は新しいコンテンツとdescriptionを送信 3278 それ以外は失敗 3279 */ 3280 currentCut.versions = result.data.versions; 3281 var currentServerXps=new Xps(); 3282 currentServerXps.parseXps(result.data.cut.content); 3283 //cut.description にidentifierがセットされないケースがある(サービス的には正常) 3284 //cut.descriptionがヌルまたはundefinedの際はXps本体から情報を構築する 3285 3286 var currentDataInfo=Xps.parseIdentifier(result.data.cut.description); 3287 //ディスクリプションがcutに付属していないのは APIの変更によるので 調整 0211 3288 if(! currentDataInfo) currentDataInfo = Xps.parseIdentifier(Xps.getIdentifier(currentServerXps)); 3289 //書き込み権限の判定からスタッフの判定になる 3290 // (result.data.permissions.write)&& 3291 // (result.data.permissions.read)&& 3292 if( 3293 ((currentDataInfo.currentStatus.content == "Fixed")|| (currentDataInfo.currentStatus.content == "Hold"))&& 3294 (xUI.currentUser.sameAs(currentServerXps.update_user)) 3295 ){ 3296 //同内容でステータスを変更したエントリを作成 新規に保存して成功したら先のエントリを消す 3297 var newXps = Object.create(xUI.XPS);//現在のデータの複製をとる 3298 //console.log('activate : '+decodeURIComponent(Xps.getIdentifier(newXps))); 3299 newXps.currentStatus = new JobStatus('Active'); 3300 newXps.update_time = new Date().toNASString(); 3301 var data = { 3302 token: currentCut.token, 3303 cut: { 3304 name: decodeURIComponent(currentEntry.toString().split('//')[1]), 3305 content: newXps.toString(), 3306 description: Xps.getIdentifier(newXps) 3307 } 3308 }; 3309 if(dbg) console.log(data); 3310 $.ajax({ 3311 type : 'PUT', 3312 url : serviceAgent.currentRepository.url+'/api/v2/cuts/'+currentEntry.issues[0].cutID+'.json', 3313 data : data, 3314 success : function(result){ 3315 //console.log('success activated :' + decodeURIComponent(currentEntry.toString())); 3316 //console.log(result) 3317 currentEntry.setStatus(newXps.currentStatus); 3318 3319 currentCut.versions[currentCut.versions.length-1].description = Xps.getIdentifier(newXps); 3320 currentCut.versions[currentCut.versions.length-1].updated_at = newXps.update_time; 3321 //PUTのリザルトは200コードのみ 3322 //PUT時点でアサイン可能リスト等をとったほうが良いか? 3323 xUI.XPS.currentStatus=newXps.currentStatus;//ドキュメントステータスを更新 3324 xUI.setStored("current");//UI上の保存ステータスをセット 3325 sync();//保存ステータスを同期 3326 selectSCi();//カレントデータを再セレクトして情報更新 3327 sync('historySelector');//履歴セレクタ更新 3328 3329 xUI.setUImode('production'); 3330 xUI.sWitchPanel();//パネルクリア 3331 if(callback instanceof Function) {setTimeout(callback,10);} 3332 }, 3333 error : function(result){ 3334 //console.log('fail activate :'+ decodeURIComponent(currentEntry.toString())); 3335 //console.log(result); 3336 //console.log('ステータス変更失敗 :'); 3337 if(callback2 instanceof Function) {setTimeout(callback2,10);} 3338 return false; 3339 }, 3340 beforeSend: serviceAgent.currentRepository.service.setHeader 3341 }); 3342 }else{ 3343 //console.log('fail activate :'+ decodeURIComponent(currentEntry.toString())); 3344 //console.log(result); 3345 //console.log('ステータス変更できません :'); 3346 if(callback2 instanceof Function) {setTimeout(callback2,10);} 3347 return false; 3348 } 3349 }, 3350 error : function(result) { 3351 // Error 3352 if(dbg) console.log("error"); 3353 if(dbg) console.log(result); 3354 if(dbg) console.log('ステータス変更不可 :'+ Xps.getIdentifier(newXps)); 3355 if(callback2 instanceof Function) {setTimeout(callback2,10);} 3356 }, 3357 beforeSend: this.service.setHeader 3358 }); 3359 /** 3360 サービス側での排他が完了したら下の簡単な処理でOKのはず 3361 var data = { 3362 token: currentEntry.issues[0].cutID, 3363 cut: { 3364 name: decodeURIComponent(currentEntry.toString().split('//')[1]), 3365 description: Xps.getIdentifier(newXps) 3366 } 3367 }; 3368 if(dbg) console.log(data); 3369 $.ajax({ 3370 type : 'PUT', 3371 url : this.url+'/api/v2/cuts/'+currentEntry.issues[0].cutID+'.json', 3372 data : data, 3373 success : function(result) { 3374 //console.log('network repository activated :'+ decodeURIComponent(currentEntry.toString())); 3375 //console.log(result); 3376 currentEntry.setStatus(newXps.currentStatus); 3377 currentCut.versions[currentCut.versions.length-1]=result.data.versions[currentCut.versions.length-1]; 3378 3379 xUI.XPS.currentStatus=newXps.currentStatus;//ドキュメントステータスを更新 3380 xUI.setStored("current");//UI上の保存ステータスをセット 3381 sync();//保存ステータスを同期 3382 selectSCi();//カレントデータを再セレクトして情報更新 3383 sync('historySelector');//履歴セレクタ更新 3384 3385 xUI.setUImode('production'); 3386 xUI.sWitchPanel();//パネルクリア 3387 if(callback instanceof Function){ setTimeout (callback,10);} 3388 }, 3389 error : function(result) { 3390 // Error 3391 if(dbg) console.log("error"); 3392 if(dbg) console.log(result); 3393 if(dbg) console.log('ステータス変更不可 :'+ Xps.getIdentifier(newXps)); 3394 if(callback2 instanceof Function) {setTimeout(callback2,10);} 3395 }, 3396 beforeSend: this.service.setHeader 3397 }); 3398 */ 3399 } 3400 /** 3401 作業を保留する リポジトリ内の対応エントリデータを更新してステータスを変更 3402 基本的にデータはActiveなので、変更権利は取得済みとみなして操作を行う 3403 失敗の可能性はあり 3404 */ 3405 NetworkRepository.prototype.deactivateEntry=function(callback,callback2){ 3406 var currentEntry = this.entry(Xps.getIdentifier(xUI.XPS)); 3407 // var currentCut = this.cut(currentEntry.toString()); 3408 var currentCut = this.cut(currentEntry.issues[0].cutID); 3409 //Active > Holdへ 3410 var newXps = Object.create(xUI.XPS);//現在のデータの複製をとる 3411 //ユーザ判定は不用 3412 if (newXps){ 3413 //同内容でステータスを変更したエントリを作成 新規に上書き保存(先行データは上書きされる) 3414 newXps.currentStatus = new JobStatus('Hold');//(ジョブID等)status以外の変更はない 3415 //ここでサーバに現在のエントリへのステータス変更要求を送信する 成功時と失敗時の処理を渡し、かつcallback を再度中継 3416 //カットの name,description のみを送信してステータスを変更 3417 var data = { 3418 token: currentCut.token, 3419 cut: { 3420 name : decodeURIComponent(currentEntry.toString().split('//')[1]), 3421 description : Xps.getIdentifier(newXps), 3422 content : newXps.toString(), 3423 line_id : newXps.line.toString(true), 3424 stage_id : newXps.stage.toString(true), 3425 job_id : newXps.job.toString(true), 3426 status : newXps.currentStatus.toString(true) 3427 } 3428 }; 3429 if(dbg) console.log(data); 3430 $.ajax({ 3431 type : 'PUT', 3432 url : this.url+'/api/v2/cuts/'+currentEntry.issues[0].cutID+'.json', 3433 data : data, 3434 success : function(result) { 3435 //console.log('network repository deactivated :'+decodeURIComponent(currentEntry.toString().split('//')[1])); 3436 //console.log(result); 3437 currentEntry.setStatus(newXps.currentStatus); 3438 // currentCut.versions[currentCut.versions.length-1]=result.data.versions[currentCut.versions.length-1]; 3439 currentCut.versions[currentCut.versions.length-1].description = Xps.getIdentifier(newXps); 3440 currentCut.versions[currentCut.versions.length-1].updated_at= newXps.update_time; 3441 xUI.XPS.currentStatus=newXps.currentStatus;//ドキュメントステータスを更新 3442 xUI.setStored("current");//UI上の保存ステータスをセット 3443 sync();//保存ステータスを同期 3444 selectSCi();//カレントデータを再セレクトして情報更新 3445 sync('historySelector');//履歴セレクタ更新 3446 3447 xUI.setUImode('browsing'); 3448 xUI.sWitchPanel();//パネルクリア 3449 if(callback instanceof Function){ setTimeout (callback,10);} 3450 }, 3451 error : function(result) { 3452 // Error 3453 //console.log("error"); 3454 //console.log(result); 3455 //console.log('保留失敗 :'+ Xps.getIdentifier(newXps)); 3456 if(callback2 instanceof Function) {setTimeout(callback2,10);} 3457 delete newXps; 3458 }, 3459 beforeSend: this.service.setHeader 3460 }); 3461 }else{ 3462 //console.log('保留可能エントリ無し :'+ decodeURIComponent(Xps.getIdentifier(newXps))); 3463 return false ; 3464 } 3465 } 3466 /** 3467 作業にチェックイン 3468 リポジトリ種別にかかわらないので 3469 このメソッドを呼ぶ前段でジョブ名称は確定しておくこと 3470 ジョブ名指定のない場合は操作失敗 3471 */ 3472 NetworkRepository.prototype.checkinEntry=function(myJob,callback,callback2){ 3473 if( typeof myJob == 'undefined') return false; 3474 var currentEntry = this.entry(Xps.getIdentifier(xUI.XPS)); 3475 var currentCut = this.cut(currentEntry.issues[0].cutID); 3476 if(! currentEntry){ 3477 if(dbg) console.log ('noentry in repository :' + decodeURIComponent(currentEntry)) 3478 //当該リポジトリにエントリが無い 3479 return false; 3480 } 3481 //次のJobへチェックイン 3482 //リポジトリのステータスを変更する XPSの内容は変更不用 3483 var newXps = new Xps(); 3484 var currentContents = xUI.XPS.toString(); 3485 newXps.readIN(currentContents); 3486 // ユーザ判定は不用(権利チェックは後ほど実装) 3487 if (newXps){ 3488 newXps.job.increment(myJob); 3489 newXps.update_user = xUI.currentUser; 3490 newXps.currentStatus = new JobStatus('Active'); 3491 if(dbg) console.log(newXps.toString());// 3492 //引数でステータスを変更したエントリを作成 新規に保存 JobIDは必ず繰り上げる 3493 //ここでサーバに現在のエントリへのステータス変更要求を送信する 3494 //成功時と失敗時の処理を渡し、かつcallback を再度中継 3495 //カットを送信してステータスを変更(ステータスのみの変更要求は意味が無い・内部データと不整合を起こすので却下) 3496 //descriptionのステータスを優先するならその方法も可能だが、バックアップタイミングを逃す? 3497 3498 var data = { 3499 token: currentEntry.issues[0].cutID, 3500 cut: { 3501 name: decodeURIComponent(currentEntry.toString(true).split('//')[1]), 3502 description: Xps.getIdentifier(newXps), 3503 content: newXps.toString() 3504 } 3505 }; 3506 //console.log('networkRepository checkinEntry') 3507 //console.log(data); 3508 $.ajax({ 3509 type : 'PUT', 3510 url : this.url+'/api/v2/cuts/'+currentEntry.issues[0].cutID+'.json', 3511 data : data, 3512 success : function(result) { 3513 //console.log('check-in :'+decodeURIComponent(currentEntry.toString())); 3514 //console.log(result);//PUTなので200番のみ 3515 //リザルトに含まれるカットのデータでリストを更新する(ムリ) 3516 3517 // currentEntry.push(result.cut.description,currentEntry.titleID,currentEntry.episodeID,result.cut.token); 3518 currentEntry.push(Xps.getIdentifier(newXps),currentEntry.titleID,currentEntry.episodeID,currentEntry.issues[0].cutID); 3519 3520 if(! currentCut.versions) currentCut.versions = []; 3521 currentCut.versions.push({ 3522 updated_at:newXps.updated_time, 3523 description:Xps.getIdentifier(newXps), 3524 version_token:null 3525 }); 3526 3527 xUI.setReferenceXPS() 3528 xUI.XPS.job.increment(myJob); 3529 3530 xUI.XPS.currentStatus=newXps.currentStatus;//ドキュメントステータスを更新 3531 xUI.XPS.update_user=xUI.currentUser;//ユーザ更新 3532 xUI.setStored("current");//UI上の保存ステータスをセット 3533 sync();//保存ステータスを同期 3534 selectSCi();//カレントデータを再セレクトして情報更新 3535 sync('historySelector');//履歴セレクタ更新 3536 3537 xUI.setUImode('production'); 3538 xUI.sWitchPanel();//パネルクリア 3539 if(callback instanceof Function){ setTimeout (callback,10);} 3540 }, 3541 error : function(result) { 3542 // Error 3543 if(dbg) console.log("error"); 3544 if(dbg) console.log(result); 3545 if(dbg) console.log('ステータス変更不可 :'+ Xps.getIdentifier(newXps)); 3546 if(callback2 instanceof Function) {setTimeout(callback2,10);} 3547 }, 3548 beforeSend: this.service.setHeader 3549 }); 3550 } 3551 } 3552 /** 3553 作業終了 3554 */ 3555 NetworkRepository.prototype.checkoutEntry=function(assignData,callback,callback2){ 3556 var currentEntry = this.entry(Xps.getIdentifier(xUI.XPS)); 3557 // var currentCut = this.cut(currentEntry.toString()); 3558 var currentCut = this.cut(currentEntry.issues[0].cutID); 3559 if(! currentEntry) { 3560 if(dbg) console.log ('noentry in repository :' + decodeURIComponent(currentEntry)) 3561 return false; 3562 } 3563 //Active > Fixed 3564 if(true){ 3565 var newXps = Object.create(xUI.XPS);//現在のデータの複製をとる 3566 }else{ 3567 var newXps = new Xps(); 3568 var currentContents = xUI.XPS.toString(); 3569 newXps.readIN(currentContents); 3570 };//下の複製のほうが安全? 3571 //ユーザ判定は不用 JobID変わらず 3572 if (newXps){ 3573 //同内容でステータスを変更したエントリを作成 新規に保存して成功したら先のエントリを消す 3574 newXps.currentStatus = new JobStatus('Fixed');//(ジョブID等)status以外の変更はない 3575 3576 // newXps.currentStatus = ['Fixed',assignData].join(":"); アサインデータはまだUIのみでペンディング 3577 3578 //ここでサーバに現在のエントリへのステータス変更要求を送信する 成功時と失敗時の処理を渡し、かつcallback を再度中継 3579 //カットの name,description のみを送信してステータスを変更 3580 var data = { 3581 token: currentEntry.issues[0].cutID, 3582 cut: { 3583 name : decodeURIComponent(currentEntry.toString().split('//')[1]), 3584 description : Xps.getIdentifier(newXps), 3585 content : newXps.toString(), 3586 line_id : newXps.line.toString(), 3587 stage_id : newXps.stage.toString(), 3588 job_id : newXps.job.toString(), 3589 status : newXps.currentStatus.toString(true) 3590 } 3591 }; 3592 if(dbg) console.log(data); 3593 $.ajax({ 3594 type : 'PUT', 3595 url : this.url+'/api/v2/cuts/'+currentEntry.issues[0].cutID+'.json', 3596 data : data, 3597 success : function(result) { 3598 //console.log('check out entry :' + decodeURIComponent(currentEntry.toString())); 3599 //console.log(result); 3600 currentEntry.setStatus(newXps.currentStatus);//result.data.cut.status も可 3601 if(result.data.versions) 3602 currentCut.versions[currentCut.versions.length-1] = result.data.versions[currentCut.versions.length-1]; 3603 //? 3604 xUI.XPS.currentStatus=newXps.currentStatus;//ドキュメントステータスを更新 3605 xUI.setStored("current");//UI上の保存ステータスをセット 3606 sync();//保存ステータスを同期 3607 selectSCi();//カレントデータを再セレクトして情報更新 3608 sync('historySelector');//履歴セレクタ更新 3609 3610 xUI.setUImode('browsing'); 3611 xUI.sWitchPanel();//パネルクリア 3612 // if(serviceAgent.currentStatus=="online-single"){backToDocumentList('cut');} ;//コレだ! ダメだ!! 3613 if(callback instanceof Function){ setTimeout (callback,10);} 3614 }, 3615 error :function(result) { 3616 // Error 3617 if(dbg) console.log("error"); 3618 if(dbg) console.log(result); 3619 if(dbg) console.log('終了更新失敗 :'+ Xps.getIdentifier(newXps)); 3620 if(callback2 instanceof Function) {setTimeout(callback2,10);} 3621 delete newXps; 3622 }, 3623 beforeSend: this.service.setHeader 3624 }); 3625 } 3626 if(dbg) console.log('終了更新失敗'); 3627 delete newXps ; 3628 if(callback2 instanceof Function){ setTimeout('callback2()',10)}; 3629 return false ; 3630 } 3631 /** 3632 検収処理 3633 引数: 3634 nas.Pm.ProductionStageオブジェクト 3635 Xps.Stage 3636 または 3637 Stage名文字列("layout"等) 3638 *上二つのオブジェクトからの処理は未実装2016-1230 3639 初期化用Job名文字列 3640 現在の工程(作業は既Fixed)を閉じて次の工程を開始する手続き 3641 現在のデータのステータスを変更 3642 ステージを新規オブジェクトでincrement = Jobは初期状態にリセット 3643 3644 3645 */ 3646 NetworkRepository.prototype.receiptEntry=function(stageName,jobName,callback,callback2){ 3647 if( typeof stageName == 'undefined') return false; 3648 var myStage = nas.pmdb.stages.getStage(stageName) ;//ステージDBと照合 エントリが無い場合はエントリ登録 3649 /* 2106-12 の実装では省略して エラー終了 3650 2017-07 最小限の処理を実装 ステージの存在を確認して続行 3651 */ 3652 if(! myStage) return false; 3653 var currentEntry = this.entry(Xps.getIdentifier(xUI.XPS)); 3654 // var currentCut = this.cut(currentEntry.toString()); 3655 var currentCut = this.cut(currentEntry.issues[0].cutID); 3656 if((!currentEntry)||(!currentCut)){ 3657 //console.log('noentry'); 3658 //console.log(serviceAgent.currentRepository); 3659 console.log('noentry in repository :' + decodeURIComponent(currentEntry)) 3660 //当該リポジトリにエントリが無い 3661 return false; 3662 } 3663 //次のステージを立ち上げるため 読み出したデータでXpsを初期化 3664 if(false){ 3665 var newXps = Object.create(xUI.XPS);//現在のデータの複製をとる 3666 }else{ 3667 var newXps = new Xps(); 3668 var currentContents = xUI.XPS.toString(); 3669 newXps.parseXps(currentContents); 3670 };//下の複製のほうが安全? 3671 // ユーザ判定は不用(権利チェックは後ほど実装) 3672 if (newXps){ 3673 newXps.stage.increment(stageName); 3674 newXps.job.reset(jobName); 3675 newXps.update_user = xUI.currentUser; 3676 newXps.currentStatus = new JobStatus('Startup'); 3677 if(dbg) console.log(newXps.toString());// 3678 //引数でステータスを変更したエントリを作成 新規に保存 stageIDは必ず繰り上る jobは0リセット 3679 //ここでサーバに現在のエントリへのステータス変更要求を送信する 成功時と失敗時の処理を渡し、かつcallback を再度中継 3680 //カットの name,description のみを送信してステータスを変更 3681 //明示的なエントリ変更の要求が必要ならば処理 3682 var data = { 3683 token: currentEntry.issues[0].cutID, 3684 cut: { 3685 name: decodeURIComponent(currentEntry.toString().split('//')[1]), 3686 description: Xps.getIdentifier(newXps), 3687 content: newXps.toString() 3688 } 3689 }; 3690 if(dbg) console.log(data); 3691 $.ajax({ 3692 type : 'PUT', 3693 url : this.url+'/api/v2/cuts/'+currentEntry.issues[0].cutID+'.json', 3694 data : data, 3695 success : function(result) { 3696 //console.log('check-in'); 3697 //console.log(result); 3698 currentEntry.push(result.data.cut.description); 3699 documentDepot.documentsUpdate(); 3700 // serviceAgent.currentRepository.getList(true);//リストステータスを同期 3701 // currentEntry.push(Xps.getIdentifier(newXps)); 3702 // documentDepot.updateDocumentSelector(); 3703 // documentDepot.rebuildList(); 3704 xUI.XPS.stage.increment(stageName); 3705 xUI.XPS.job.reset(jobName); 3706 xUI.XPS.currentStatus= new JobStatus('Startup');//ドキュメントステータスを更新 3707 xUI.XPS.update_user=xUI.currentUser;//ユーザ更新 3708 xUI.setStored("current");//UI上の保存ステータスをセット 3709 sync();//保存ステータスを同期 3710 xUI.setUImode('browsing'); 3711 xUI.sWitchPanel();//パネルクリア 3712 if(callback instanceof Function){ setTimeout (callback,10);} 3713 }, 3714 error : function(result) { 3715 // Error 3716 if(dbg) console.log("error"); 3717 if(dbg) console.log(result); 3718 if(dbg) console.log('ステータス変更不可 :'+ Xps.getIdentifier(newXps)); 3719 if(callback2 instanceof Function) {setTimeout(callback2,10);} 3720 }, 3721 beforeSend: this.service.setHeader 3722 }); 3723 } 3724 } 3725 /** 3726 作業中断処理 3727 */ 3728 NetworkRepository.prototype.abortEntry=function(myIdentifier){ 3729 var currentEntry = this.entry(myIdentifier); 3730 if(! currentEntry) return false; 3731 var currentStatus=currentEntry.getStatus(); 3732 3733 if(String(currentStatus.content).indexOf('Fixed')<0){return false;} 3734 3735 switch (currentStatus.content){ 3736 case 'Startup': 3737 case 'Hold': 3738 case 'Fixed': 3739 case 'Active': 3740 //管理モード下でのみ処理 このメソッドのコール自体が管理モード下でのみ可能にする 3741 //リポジトリに対して 3742 break; 3743 } 3744 } 3745 3746 /** 3747 最終作業の破棄 3748 バックアップ作業これを呼び出す側で処理 3749 ここを直接コールした場合はバックアップは実行されない 3750 ユーザメッセージはここでは処理されない 3751 3752 */ 3753 NetworkRepository.prototype.destroyJob=function(callback,callback2){ 3754 if(xUI.XPS.currentStatus.content != 'Active'){return false} 3755 // カレントのtokenを添えてdestroyコマンドを発行する 3756 var currentEntry = this.entry(Xps.getIdentifier(xUI.XPS)); 3757 if(! currentEntry){ 3758 if(dbg) console.log ('noentry in repository :' + decodeURIComponent(currentEntry)) 3759 //当該リポジトリにエントリが無い 3760 return false; 3761 } 3762 3763 //currentEntry.issues[0].cutID 3764 // debug : change PATCH to PUT 3765 if(dbg) console.log(currentEntry.issues[0].cutID); 3766 $.ajax({ 3767 type : 'PUT', 3768 url : this.url+'/api/v2/cuts/'+currentEntry.issues[0].cutID+'/discard', 3769 success : function(result) { 3770 currentEntry.issues.pop(); 3771 xUI.resetSheet(new Xps(5,144),new Xps(5,144)) ; 3772 documentDepot.updateDocumentSelector(); 3773 // documentDepot.rebuildList(); 3774 xUI.setStored("current");//UI上の保存ステータスをセット 3775 sync();//保存ステータスを同期 3776 xUI.setUImode('browsing'); 3777 if(callback instanceof Function){ setTimeout (callback,10);} 3778 }, 3779 error : function(result) { 3780 // Error 3781 if(dbg) console.log("error"); 3782 if(dbg) console.log(result); 3783 if(callback2 instanceof Function) {setTimeout(callback2,10);} 3784 }, 3785 beforeSend: this.service.setHeader 3786 }); 3787 3788 } 3789 //serviceAgent.currentRepository.destroyJob(); 3790 /** 3791 サービスエージェントオブエジェクト 3792 3793 ログインするサーバを選んでログイン処理をする 3794 ログイン情報を保持して 3795 状態は offline/onnline/online-single の3状態 3796 モードによっては機能が制限される 3797 UI上モードを表示するシンボルが必要 3798 3799 servers ServiceNode 3800 */ 3801 3802 3803 serviceAgent = { 3804 servers :[], 3805 repositories:[], 3806 currentStatus :'offlline', 3807 currentServer :null, 3808 currentRepository :null 3809 }; 3810 /** 3811 サービスエージェントの初期化(テスト版) 3812 リポジトリの初期化は 最終的には作業記録とサーバからの受信情報でアプリケーション初期化のタイミングで組む 3813 */ 3814 serviceAgent.init= function(){ 3815 this.servers=[]; //サーバコレクション初期化 3816 this.repositories=[localRepository]; //ローカルリポジトリを0番として加える 3817 if(document.getElementById('backend_variables')){ 3818 ;//本番用 3819 if($("#backend_variables").attr("data-server_url")){ 3820 //ローカルテスト時はこちらで 3821 var myUrl = $("#backend_variables").attr("data-server_url"); 3822 }else{ 3823 var loc = String(window.location).split('/');// 3824 var locOffset = (loc[loc.length-1]=="edit")? 3:2; 3825 var myUrl = loc.splice(0,loc.length-locOffset).join('/'); 3826 // var myUrl = 'http://remaping.scivone-dev.com';//テスト用決め打ち 3827 // var myUrl = 'https://remaping-stg.u-at.net';//テスト用に決め打ち 3828 // var myUrl = 'https://u-at.net';//テスト用決め打ち 3829 } 3830 this.servers.push(new ServiceNode("CURRENT",myUrl)); 3831 }else{ 3832 var myServers={ 3833 UAT: {name:'U-AT',url:'https://u-at.net'}, 3834 Srage:{name:'Stage',url:'https://remaping-stg.u-at.net'}, 3835 devFront:{name:'devFront',url:'https://remaping.scivone-dev.com'} 3836 }; 3837 for(svs in myServers){this.servers.push(new ServiceNode(myServers[svs].name,myServers[svs].url));} 3838 } 3839 /* 3840 仮のサーバセレクタを設定 3841 */ 3842 var mylistContents=""; 3843 mylistContents +='<option selected value="-1" > +no server selected+'; 3844 for(var ids=0; ids < this.servers.length;ids ++){ 3845 mylistContents +='<option value="'+ids+((ids==0)? '" selected >':'" >')+this.servers[ids].name; 3846 } 3847 document.getElementById('serverSelector').innerHTML = mylistContents; 3848 3849 // var Home=new NetworkRepository("HOME",serviceA); 3850 // this.repositories.push(Home); 3851 /** 3852 組んだリポジトリでリポジトリリストを更新する 3853 ローカルリポジトリはすべての状況で利用可能 3854 */ 3855 var myContents=""; 3856 myContents +='<option selected value=0> = local Repository ='; 3857 for(var idr=1; idr < this.repositories.length;idr ++){ 3858 myContents +='<option value="'+idr+'" >'+this.repositories[idr].name; 3859 } 3860 document.getElementById('repositorySelector').innerHTML = myContents; 3861 3862 // this.switchRepository(0); 3863 this.switchService(0); 3864 // this.currentServer = this.severs[0];//初期化時点のサーバは 最初のサーバ(U-AT); 3865 } 3866 /** 3867 ユーザ認証 3868 カレントサービスを認証又は解除する 3869 3870 カレントサービスが"0:=no selected="の場合は, 3871 単純にすべてのサービスからログアウトする 3872 3873 */ 3874 serviceAgent.authorize=function(){ 3875 if(dbg) console.log("authorize!::"); 3876 switch (this.currentStatus){ 3877 case 'online-single': 3878 return false; 3879 break; 3880 case 'online': 3881 if(xUI.onSite){return 'online'}; 3882 // this.currentServer = null; 3883 // this.currentRepository = null; 3884 this.authorized(false); 3885 return 'offline'; 3886 break; 3887 case 'offline': 3888 default: 3889 if(this.currentServer) this.currentServer.authorize(); 3890 return 'online'; 3891 } 3892 } 3893 /** 3894 認証/解除時の画面処理 3895 */ 3896 serviceAgent.authorized=function(status){ 3897 if (status == 'success'){ 3898 this.currentStatus = 'online'; 3899 //二回目以降のUI初期化時は ローカルリポジトリにフォーカスが移ってカレントサーバがないケースがあるので注意 3900 if(serviceAgent.currentServer){ 3901 document.getElementById('serverurl').innerHTML = serviceAgent.currentServer.url.split('/').slice(0,3).join('/');//? 3902 document.getElementById('loginuser').innerHTML = document.getElementById('current_user_id').value; 3903 document.getElementById('loginstatus_button').innerHTML = "=ONLINE="; 3904 document.getElementById('login_button').innerHTML = "SIGNOUT"; 3905 document.getElementById('serverSelector').disabled = true; 3906 };//二度目以降の表示更新はサーバの切り替えが無い限り特に不用 3907 }else{ 3908 this.currentStatus = 'offline'; 3909 document.getElementById('serverurl').innerHTML = localize(nas.uiMsg.noSigninService);//? 3910 document.getElementById('loginuser').innerHTML = ''; 3911 document.getElementById('loginstatus_button').innerHTML = "=OFFLINE="; 3912 document.getElementById('login_button').innerHTML = "SIGNIN"; 3913 document.getElementById('serverSelector').disabled = false; 3914 3915 serviceAgent.switchRepository(0);//ローカルレポジトリセット 3916 serviceAgent.switchService(); 3917 serviceAgent.init(); 3918 } 3919 } 3920 /** 3921 サーバを切り替える 3922 引数: myServer / Object ServiceNode 3923 サーバ名・URL・ID またはキーワードで指定 3924 キーワードと同名のサーバは基本的に禁止? 3925 サーバにログインしていない場合は、各サーバごとの認証を呼ぶ 3926 既にサービスにログインしている場合は、その認証を解除してから次のサービスを認証する 3927 3928 内部的にはともかくユーザ視点での情報の輻輳を避けるため サーバ/リポジトリを多層構造にせず 3929 リポジトリに対する認証のみをUIで扱う 3930 リポジトリの切り替えに対してログイン/ログアウトを行うUI仕様とする。 3931 サービスの切り替えは内部での呼び出しのみになるので引数は整理する 3932 */ 3933 serviceAgent.switchService=function(myServer){ 3934 var newServer = null; 3935 //引数とカレントのサービスが一致 切替不能(不用) 3936 if (myServer === this.currentServer){ 3937 return myServer; 3938 } 3939 3940 if((myServer instanceof ServiceNode )&&(myServer !== this.currentServer)) { 3941 //引数がノードオブジェクト 3942 newServer = myServer; 3943 }else if((myServer >= 0)&&(myServer<this.servers.length)){ 3944 //引数がサーバID 3945 newServer = this.servers[myServer]; 3946 }else if(myServer instanceof String){ 3947 //引数が文字列 3948 for (var ix = 0 ;ix < this.servers.length ; ix ++){ 3949 if((myServer == this.servers[ix].url)||(myServer == this.servers[ix].name)){ 3950 newServer = this.servers[ix];break; 3951 } 3952 } 3953 } 3954 //オンラインであった場合は切替前にオフライン化して 3955 //エントリリスト クリア ドキュメントセレクタ リセット 3956 this.switchRepository(0); 3957 this.currentServer = newServer; 3958 sync(); 3959 3960 return this.currentServer; 3961 }; 3962 /** 3963 リポジトリを切り替える 3964 UIから直接呼び出されるのはこちら 3965 カレントのリポジトリを切り替え、 3966 リポジトリに関連付けられたサービスをカレントにする 3967 サービスが現在のログイン先と異なる場合も認証は実際のアクセスまで保留 3968 (解除前にもとのサービスに戻った際に再ログインを行わないため) 3969 引数は、現在のリポジトリID 3970 リポジトリIDは以下のように決定 3971 3972 0:ローカルリポジトリ固定 3973 1~ 以降登録順 現在同時に処理できるサーバは1つ サーバ内のリポジトリは複数 3974 3975 リポジトリ切替時にドキュメントリストの更新をバックグラウンドで行う 3976 3977 */ 3978 serviceAgent.switchRepository=function(myRepositoryID,callback){ 3979 if(this.currentRepository === this.repositories[myRepositoryID]){ 3980 //同オブエジェクトに切り替える必要はないのでそのままリターン 3981 return this.currentRepository; 3982 }else{ 3983 if(typeof myRepositoryID == 'undefined') myRepositoryID = 0; 3984 //切り替え前に現在のデータの状態を確認して必要ならば編集状態を解除 その後自身を再度呼び出し 3985 if((xUI.uiMode=='production')&&(xUI.XPS.currentStatus.content=='Active')){ 3986 //console.log("deactivate current document"); 3987 if(xUI.edchg) xUI.put(document.getElementById('iNputbOx').value); 3988 serviceAgent.currentRepository.deactivateEntry(function(){ 3989 serviceAgent.switchRepository(myRepositoryID,callback); 3990 }); 3991 return; 3992 }else{ 3993 serviceAgent.currentRepository = serviceAgent.repositories[myRepositoryID]; 3994 if((myRepositoryID > 0)&&(myRepositoryID<this.repositories.length)){ 3995 // serviceAgent.currentServer=serviceAgent.currentRepository.service; 3996 serviceAgent.switchService(serviceAgent.currentRepository.service); 3997 } else { 3998 // serviceAgent.currentServer = null; 3999 //console.log('reset');console.log(serviceAgent.currentServer); 4000 //serviceAgent.switchService(); 4001 }; 4002 } 4003 if(document.getElementById('repositorySelector').value != myRepositoryID){ 4004 document.getElementById('repositorySelector').value = myRepositoryID; 4005 } 4006 if(callback instanceof Function){ callback(); }else{ 4007 //OPUSセレクタを停止 4008 document.getElementById( "opusSelect" ).disabled=true; 4009 //ドキュメントセレクタを停止 4010 document.getElementById( "cutList" ).disabled=true; 4011 /*== ドキュメントリスト更新 ==*/ 4012 //console.log("change repository :"+ myRepositoryID); 4013 serviceAgent.currentRepository.getProducts(function(){ 4014 4015 documentDepot.getProducts(); 4016 documentDepot.currentProduct=null; 4017 documentDepot.currentSelection=null; 4018 documentDepot.updateOpusSelector(); 4019 documentDepot.updateDocumentSelector(); 4020 /* for(var ix=0;ix<serviceAgent.currentRepository.productsData.length;ix ++){ 4021 var myProduct = serviceAgent.currentRepository.productsData[ix]; 4022 serviceAgent.currentRepository.getEpisodes(function(){ 4023 // documentDepot.documentsUpdate();//クリア 4024 // for(var ex =0 ;ex < myProduct.episodes[0].length;ex++){ 4025 // var myEpisode = myProduct.episodes[0][ex]; 4026 // serviceAgent.currentRepository.getSCi(function(){},false,myEpisode.token); 4027 // } 4028 // console.log(myEpisode.name); 4029 documentDepot.getProducts(); 4030 documentDepot.currentProduct=null; 4031 documentDepot.currentSelection=null; 4032 documentDepot.updateOpusSelector(); 4033 documentDepot.updateDocumentSelector(); 4034 4035 },false,myProduct.token);//getEpisode 4036 } 4037 */ 4038 },false);//getProduct 4039 4040 // this.currentRepository.getList() 4041 // documentDepot.updateDocumentSelector(); 4042 // documentDepot.rebuildList(callback); 4043 } 4044 }; 4045 sync('server-info') 4046 return this.currentRepository; 4047 }; 4048 /** 4049 title-token 又は episode-token が含まれるRepositoryをカレントに切り替えて返す 4050 */ 4051 serviceAgent.getRepsitoryIdByToken=function(myToken){ 4052 var RIX=0; 4053 search_loop: 4054 for (var rix=1;rix<this.repositories.length;rix++){ 4055 if(myToken==this.repositories[rix].token){ 4056 RIX=rix; 4057 break search_loop; 4058 } 4059 //リポジトリ内のプロダクトデータを検索(エントリ総当りはしない) 4060 for (var pix=0;pix<this.repositories[rix].productsData.length;pix++){ 4061 if(myToken==this.repositories[rix].productsData[pix].token){ 4062 RIX=rix; 4063 break search_loop; 4064 }; 4065 for (var eix=0;eix<this.repositories[rix].productsData[pix].episodes[0].length;eix++){ 4066 if(myToken == this.repositories[rix].productsData[pix].episodes[0][eix].token){ 4067 RIX=rix; 4068 break search_loop; 4069 }; 4070 }; 4071 }; 4072 }; 4073 if(RIX) {return RIX}else{return false} 4074 4075 }; 4076 4077 /** 4078 引数を判定して動作を決定 カレントリポジトリの操作を呼び出す 4079 myIdentifier カット識別子 完全状態で指定されなかった場合は、検索で補う 4080 isReference リファレンスとして呼び込むか否かのフラグ 指定がなければ自動判定 4081 callback コールバック関数指定が可能 コールバックは以下の型式で 4082 コールバックの指定がない場合は指定データをアプリケーションに読み込む 4083 コールバック関数以降の引数はコールバックに渡される 4084 リファレンス取得の際にアプリケーションステータスをリセットする場合があるので注意 4085 4086 ネットワークリポジトリからエントリを取得の際コンテンツが空のケースがある。 4087 これはエントリ登録直後のデータで、アプリケーション上でタイトル/エピソードに従ったデータをさくせいる必要があるので注意 4088 4089 リポジトリ共通の機能としてタイトル/エピソードからデフォルトプロパティの取得を行い、その後、各リポジトリごとに記述子による指定データのパースを行って新規データのビルドを行う。 4090 */ 4091 serviceAgent.getEntry=function(myIdentifier,isReference,callback,callback2){ 4092 if(dbg) console.log('getEntry ::' + decodeURIComponent(myIdentifier)); 4093 if(typeof isReference == 'undefined'){isReference = false;} 4094 //識別子をパース 4095 var targetInfo = Xps.parseIdentifier(myIdentifier); 4096 var myIssue = false; 4097 var refIssue = false; 4098 4099 var myEntry = serviceAgent.currentRepository.entry(myIdentifier); 4100 if(! myEntry){ 4101 if(dbg) console.log("noProduct : "+ decodeURIComponent(myIdentifier));//プロダクトが無い 4102 return false; 4103 }else{ 4104 //pmdbからプロダクトごとのデフォルト値を取得する 4105 4106 } 4107 if(! targetInfo.currentStatus){ 4108 //引数に管理部分がないので、最新のissueとして補う 4109 var cx = myEntry.issues.length-1;//最新のissue 4110 myIssue = myEntry.issues[cx];//配列で取得 4111 } else { 4112 //指定管理部分からissueを特定する 連結して文字列比較(後方から検索) リスト内に指定エントリがなければ失敗 4113 checkIssues:{ 4114 for (var cx = (myEntry.issues.length-1) ; cx >= 0 ;cx--){ 4115 //if(dbg) console.log ( String(myEntry.issues[cx].identifier)+'\n'+String(myIdentifier)); 4116 //if(dbg) console.log ( Xps.compareIdentifier(myEntry.issues[cx].identifier,myIdentifier)) 4117 if ( Xps.compareIdentifier(myEntry.issues[cx].identifier,myIdentifier) > 4){ 4118 myIssue = myEntry.issues[cx]; 4119 break checkIssues; 4120 } 4121 } 4122 if (! myIssue){ 4123 if(dbg) console.log( 'no target data :'+ decodeURIComponent(myIdentifier) );//ターゲットのデータが無い 4124 return false; 4125 } 4126 } 4127 } 4128 //console.log(decodeURIComponent(myEntry.issues[cx].identifier)); 4129 if((! isReference)&&(Xps.compareIdentifier(myEntry.issues[cx].identifier,Xps.getIdentifier(xUI.XPS)) > 3)){ 4130 //console.log(decodeURIComponent(Xps.getIdentifier(xUI.XPS))) 4131 //console.log('ジョブ一致 ロードスキップ'); 4132 } 4133 //読み込み前に現在のデータの状態を確認して必要ならば編集状態を解除 4134 //その後読み込み 4135 //読込の前にカーソル位置を 1_0 にリセット 4136 //参照読み込みに際しては、編集状態を維持 4137 if((! isReference ) && ( xUI.uiMode=='production' )&&( xUI.XPS.currentStatus.content=='Active' )){ 4138 //console.log("need deactivate"); 4139 if(xUI.edchg) xUI.put(document.getElementById('iNputbOx').value); 4140 serviceAgent.currentRepository.deactivateEntry(function(){ 4141 serviceAgent.currentRepository.getEntry(myIdentifier,isReference,callback,callback2) 4142 return; 4143 /* 4144 serviceAgent.currentRepository.getEntry(myIdentifier,isReference,function(){ 4145 //console.log("get "); 4146 sync('historySelector'); 4147 if (callback instanceof Function) callback(); 4148 } 4149 */ 4150 },function(){ 4151 //console.log("fail getting "); 4152 if (callback2 instanceof Function) callback2(); 4153 }); 4154 }else{ 4155 xUI.selectCell([1,0]); 4156 this.currentRepository.getEntry(myIdentifier,isReference,function(){ 4157 sync('historySelector'); 4158 if (callback instanceof Function) callback(); 4159 },function(){ 4160 //console.log("fail getting "); 4161 if (callback2 instanceof Function) callback2(); 4162 }); 4163 } 4164 if($("#optionPanelFile").is(':visible')) xUI.sWitchPanel('File'); 4165 }; 4166 4167 /** 4168 ドキュメント操作メソッド群 4169 実行時に実際の各リポジトリに対してコマンドを発行して エントリのステータスを更新する 4170 ステータスによっては、ジョブ名引数を必要とする 4171 変更をトライして成功時/失敗時に指定のコールバック関数を実行する 4172 4173 操作対象ドキュメントは、必ずUI上でオープンされている (xUI.XPS が対象) 4174 引数で識別子を与えることは無い 4175 4176 activate(callback,callback2) 4177 Active > Active 例外操作 作業セッションの回復時のみ実行 データにチェック機能が必要 4178 ステータス変更なし 4179 Hold > Active 4180 Fixed > Active (Fixedの取り消し操作) 4181 ステータスのみ変更(カレントユーザのみが可能) 4182 4183 deactivate(callback,callback2) 4184 Active > Hold 4185 現データをpush 4186 ステータス変更(カレントユーザのみが可能) 4187 4188 checkin(ジョブ名,callback,callback2) 4189 Startup > Active 4190 Fixed > Active 4191 4192 checkout/fix/close(callback,callback2) 4193 Active > Fixed 4194 現データをpush 4195 ステータス変更(カレントユーザのみが可能) 4196 4197 4198 引数としてJob名が必要 4199 4200 Abort > 最終JobのステータスをAbortに変更して保存する 4201 ストレージタイプの場合、同内容でステータスの異なるデータを保存して成功時に先行データを削除して更新する 4202 サービス型の場合は変更リクエストを発行して終了 4203 4204 この場合の違いを吸収するためにRepositry.changeStatus() メソッドを実装する 4205 エントリステータスの変更は単純な変更にならない かつ リポジトリ通信先のデータ更新にかかわるのでエントリのメソッドにはしない 4206 4207 checkin(開く) 4208 Startup/Fixed/(Active) > Active 4209 新規ジョブを開始 4210 4211 checkout(fix)(閉じる) 4212 Active > Fixed 4213 カレントジョブを終了 4214 4215 activate(再開) 4216 Hold/Fixed > Active 4217 カレントジョブの状態を変更 4218 データをActiveにできるのは、updateユーザのみ 4219 4220 deactivate(保留) 4221 Acive > Hold 4222 カレントジョブの状態を変更 4223 4224 =================== ここまでproductionMode での操作 4225 ドキュメントブラウザパネルの表示は 4226 [ CHECKIN][CHECKOUT][ACTIVATE][DEACTIVATE] 4227 [作業開始][作業終了][作業保留][作業再開] 4228 となる 4229 =================== 4230 4231 receipt(検収) 4232 fixed > Startup 4233 新規ステージを開始(管理者権限) 4234 4235 *管理者権限での作業時はステータスの遷移を抑制する 4236 =読み出してもactiveにならない? 4237 4238 abort(中断) 4239 * > Aborted 4240 エントリの制作を中断(管理者権限) 4241 すべての状態から移行可能性あり 4242 4243 状況遷移を単純化するために、読み込まれていないデータの状況遷移を抑制する。 4244 基本的にユーザのドキュメント操作の際に状況の遷移が自動で発生する。 4245 4246 プログラム上の手続きとして 4247 4248 リポジトリのステータス更新 4249 ドキュメントリスト上のステータスを同期 4250 バッファ上のデータのステータス同期 4251 を上の順序で行う必要があるので注意 4252 4253 */ 4254 /** 4255 現在のドキュメントをアクティベートする 4256 4257 */ 4258 serviceAgent.activateEntry=function(callback,callback2){ 4259 var currentEntry = this.currentRepository.entry(Xps.getIdentifier(xUI.XPS)); 4260 // var currentCut = this.currentRepository.cut(currentEntry.toString()); 4261 var currentCut = this.currentRepository.cut(currentEntry.issues[0].cutID); 4262 if(! currentEntry) { 4263 //console.log ('noentry in this repository :' + decodeURIComponent(currentEntry)) 4264 return false; 4265 } 4266 //console.log('activateEntry :'+decodeURIComponent(currentEntry.toString())); 4267 //console.log(currentEntry); 4268 //console.log(currentEntry.getStatus()); 4269 switch (xUI.XPS.currentStatus.content){ 4270 case 'Active': 4271 /** 例外処理 ロストセッションの回復 4272 編集中に保存せずに作業セッションを失った場合 この状態となる 4273 また同一ユーザで編集中に他のブラウザからログインした場合も可能性あり 4274 ここに確認用のメッセージが必要 4275 checkinの手続内でここがコールされている? 4276 */ 4277 //console.log('recover acitivate'); 4278 if(xUI.currentUser.sameAs(xUI.XPS.update_user)){ 4279 var msg = localize(nas.uiMsg.alertAbnomalPrccs); 4280 msg += '\n'+localize(nas.uiMsg.dmPMrecoverLostSession); 4281 msg += '\n\n'+localize(nas.uiMsg.confirmOk); 4282 if(confirm(msg)){ 4283 xUI.setUImode('production'); 4284 // 必要があればここでリポジトリの操作(基本不用) 4285 xUI.sWitchPanel();//パネルクリア 4286 return true; 4287 } 4288 } 4289 break; 4290 case 'Aborted':case 'Startup': 4291 alert(localize(nas.uiMsg.dmAlertCantActivate));//アクティベート不可 4292 //NOP return 4293 return false; 4294 break; 4295 case 'Hold':case 'Fixed': 4296 //ユーザが同一の場合のみ 再アクティベート可能(activate) 4297 //Fixed>Active の場合は、通知が必要かも 4298 if (xUI.currentUser.sameAs(xUI.XPS.update_user)){ 4299 //console.log('call repository.activateEntry :') 4300 this.currentRepository.activateEntry(callback,callback2);//コールバックはリレーする 4301 return true; 4302 } else { 4303 alert(localize(nas.uiMsg.dmAlertDataBusy));//ユーザ違い 4304 return false; 4305 } 4306 break; 4307 } 4308 } 4309 /** 4310 作業を保留する リポジトリ内のエントリを更新してステータスを変更 4311 ユーザ判定は不用 4312 現データの送信(保存)後にリスト更新とドキュメントブラウザの更新 4313 */ 4314 serviceAgent.deactivateEntry=function(callback,callback2){ 4315 var currentEntry = this.currentRepository.entry(Xps.getIdentifier(xUI.XPS)); 4316 // var currentCut = this.currentRepository.cut(currentEntry.toString()); 4317 var currentCut = this.currentRepository.cut(currentEntry.issues[0].cutID); 4318 if(! currentEntry) { 4319 if(dbg) console.log ('noentry in repository :' + decodeURIComponent(currentEntry)) 4320 return false; 4321 } 4322 //console.log(currentEntry); 4323 var currentStatus=currentEntry.getStatus(); 4324 switch (currentStatus.content){ 4325 case 'Aborted': case 'Startup': case 'Hold': case 'Fixed': 4326 //NOP 4327 // if(dbg) console.log('fail deactivate so :'+ currentEntry.getStatus()); 4328 alert(localize(nas.uiMsg.dmAlertCantDeactivate));//アクティブでない 4329 return false; 4330 break; 4331 case 'Active': 4332 //編集を確認して Active > Holdへ 4333 if(xUI.edchg) xUI.put(document.getElementById('iNputbOx').value); 4334 this.currentRepository.deactivateEntry(callback,callback2); 4335 break; 4336 } 4337 } 4338 /** 4339 作業にチェックイン 4340 リポジトリ種別にかかわらないので 4341 このメソッド内でジョブ名称を確定しておく 4342 */ 4343 serviceAgent.checkinEntry=function(myJob,callback,callback2){ 4344 // ここで処理前にリストを最新に更新する 4345 /*リストの更新では、ムダに待ち時間が長いので「エントリ情報の更新」に変更したい 後ほど処理 今は保留 0422*/ 4346 // this.currentRepository.getList(true); 4347 //console.log(Xps.getIdentifier(xUI.XPS)) 4348 var currentEntry = this.currentRepository.entry(Xps.getIdentifier(xUI.XPS)); 4349 //console.log(currentEntry); 4350 var currentCut = this.currentRepository.cut(currentEntry.issues[0].cutID); 4351 //console.log(currentCut) 4352 if(! currentEntry){ 4353 alert(localize(nas.uiMsg.dmAlertNoEntry));//対応エントリが無い 4354 // if(dbg) console.log ('noentry in repository :' + decodeURIComponent(currentEntry)) 4355 //当該リポジトリにエントリが無い 4356 return false; 4357 } 4358 var currentStatus=currentEntry.getStatus(); 4359 switch (currentStatus.content){ 4360 case 'Aborted': case 'Active': case 'Hold': 4361 alert(localize(nas.uiMsg.dmAlertCheckinFail)+"\n>"+currentEntry.getStatus(myJob,callback,callback2)); 4362 //NOP return 4363 if(dbg) console.log('fail checkin so :'+ currentEntry.getStatus(myJob,callback,callback2)); 4364 return false; 4365 break; 4366 case 'Fixed':case 'Startup': 4367 //次のJobへチェックイン 4368 //ジョブ名称を請求 4369 var title = localize(nas.uiMsg.pMcheckin);//'作業開始 / チェックイン'; 4370 var msg = localize(nas.uiMsg.dmPMnewItemSwap,localize(nas.uiMsg.pMjob)); 4371 //'新規作業を開始します。\n新しい作業名を入力してください。\nリストにない場合は、作業名を入力してください。'; 4372 // var msg2 = '<br> <input id=newJobName class=mdInputText type=text list=newJobList></input><datalist id=newJobList>'; 4373 var msg2 = '<br> <input type="text" list="newJobList" id=newJobName class=mdInputText autocomplete=on ></input><datalist id="newJobList">'; 4374 //console.log(xUI.XPS.stage.name +","+ ((xUI.XPS.job.id == 0) ? 'primary':'*')); 4375 //console.log(nas.pmdb.jobNames.getTemplate(xUI.XPS.stage.name,((xUI.XPS.job.id == 0) ? 'primary':'*'))); 4376 var newJobList = nas.pmdb.jobNames.getTemplate(xUI.XPS.stage.name,((xUI.XPS.job.id == 0) ? 'primary':'*'));//ここは後ほどリポジトリ個別のデータと差替 4377 //console.log(newJobList) 4378 for(var idx = 0 ; idx < newJobList.length;idx ++){ 4379 msg2 += '<option value="'; 4380 msg2 += newJobList[idx]; 4381 msg2 += '">'+newJobList[idx]+'</option>'; 4382 }; 4383 msg2 += '</datalist>'; 4384 //console.log(msg); 4385 4386 //console.log(newJobList); 4387 //console.log(msg2); 4388 nas.showModalDialog('confirm',[msg,msg2],title,false,function(){ 4389 var newJobName=document.getElementById('newJobName').value; 4390 if((this.status == 0)&&(newJobName)){ 4391 serviceAgent.currentRepository.checkinEntry(newJobName,function(){ 4392 //成功時は現在のデータをリファレンスへ複製しておく 4393 //putReference(); このタイミングで行うと ステータス変更後のデータがリファレンスへ入るので ダメ 各メソッド側に実装 4394 // sync('productStatus');//ここで ステータスの更新を行う 4395 // sync('historySelector');//ここで 履歴セレクタの更新を行う 4396 if(callback instanceof Function) callback(); 4397 }, 4398 function(){ 4399 alert(localize(nas.uiMsg.dmAlertCheckinFail));//チェックイン失敗 4400 // sync('productStatus');//ここで ステータスの更新を行う 4401 // sync('historySelector');//ここで 履歴セレクタの更新を行う 4402 if(callback2 instanceof Function) callback2(); 4403 }); 4404 } 4405 }); 4406 break; 4407 } 4408 } 4409 /** 4410 作業を終了する リポジトリ内のエントリを更新してステータスを変更 4411 ユーザ判定は不用 4412 現データの送信(保存)後にリスト更新とドキュメントブラウザの更新 4413 */ 4414 serviceAgent.checkoutEntry=function(callback,callback2){ 4415 var currentEntry = this.currentRepository.entry(Xps.getIdentifier(xUI.XPS)); 4416 // var currentCut = this.currentRepository.cut(currentEntry.toString()); 4417 var currentCut = (currentEntry.issues[0].cutID) ?this.currentRepository.cut(currentEntry.issues[0].cutID):this.currentRepository.cut(currentEntry.toString()); 4418 //console.log('checkoutEntry'+decodeURIComponent(currentEntry)); 4419 //console.log(currentEntry.toString(true)); 4420 //console.log(currentEntry.getStatus()); 4421 if(! currentEntry) { 4422 //console.log ('noentry in repository :' + decodeURIComponent(currentEntry)) 4423 //当該リポジトリにエントリが無い 4424 alert(localize(nas.uiMsg.dmAlertNoEntry)+'\n>'+decodeURIComponent(currentEntry));//対応エントリが無い 4425 return false; 4426 } 4427 var currentStatus=currentEntry.getStatus(); 4428 switch (currentStatus.content){ 4429 case 'Startup': case 'Hold': case 'Fixed': 4430 //NOP 4431 // if(dbg) console.log('fail checkout so :'+ currentEntry.getStatus()); 4432 alert(localize(nas.uiMsg.dmAlertCantCheckout));//作業データでない 4433 return false; 4434 break; 4435 case 'Active': 4436 //編集状態を確認の上 Active > Fixed 4437 if(xUI.edchg) xUI.put(document.getElementById('iNputbOx').value); 4438 //Jobチェックアウト 4439 //アサイン情報を請求 4440 //このあたりはアサイン関連のDB構成が済むまで保留 要調製 4441 var title = localize(nas.uiMsg.pMcheckout);//'作業終了 / チェックアウト'; 4442 // var msg = localize(nas.uiMsg.dmPMnewAssign,xUI.XPS.cut); 4443 var msg = localize({ 4444 en:"", 4445 ja:"%1\n作業終了します" 4446 },decodeURIComponent(Xps.getIdentifier(xUI.XPS))) 4447 4448 var msg2 = '<br>'; 4449 4450 msg2 += localize(nas.uiMsg.toPrefix); 4451 msg2 += ' <input id=assignNextUser autocomplete=yes class=mdInputText type=text list=assignUserList></input> '; 4452 msg2 += localize(nas.uiMsg.toPostfix); 4453 msg2 += '<datalist id=assignUserList>'; 4454 var assignUserList = ["演出","作画監督","監督","美術監督","美術","原画","動画","仕上","特効"];//ここは後ほどタイトル個別のデータを請求して差替 4455 for(var idx = 0 ; idx < assignUserList.length;idx ++){ 4456 msg2 += '<option value="'; 4457 msg2 += assignUserList[idx]; 4458 msg2 += '"></option>'; 4459 }; 4460 msg2 += '</datalist><br>'; 4461 msg2 += '<textarea id=assignNoteText class=mdInputArea >指名及び申し送りは開発中のダミー画面です。\n指名データを選択または入力して先に進めてください。</textarea>' 4462 4463 nas.showModalDialog('confirm',msg,title,false,function(){ 4464 // nas.showModalDialog('confirm',[msg,msg2],title,false,function(){ 4465 // var assignUserName=document.getElementById('assignNextUser').value; 4466 // var assignNoteText=document.getElementById('assignNoteText').value; 4467 var assignUserName=true 4468 var assignNoteText=""; 4469 if((this.status == 0)&&(assignUserName)){ 4470 var assignData=encodeURIComponent(JSON.stringify([assignUserName,assignNoteText])); 4471 serviceAgent.currentRepository.checkoutEntry(assignData,callback,callback2); 4472 // alert(localize(nas.uiMsg.dmAlertCheckoutFail));//チェックアウト失敗 4473 } 4474 }); 4475 break; 4476 } 4477 } 4478 /** 4479 新規カットを追加登録 4480 現在のリポジトリに存在しないタイトル・エピソードを指定する場合は、必ずXpsオブジェクトを指定すること 4481 マネジメントモード下で引数無しで呼び出された場合に限り、ドキュメントブラウザの入力情報をベースに新規のエントリを作成する。 4482 その際は、規定のコールバック関数を利用して、指定のコールバックは使用されない 4483 引数なしのケースではデータ内容の指定は不可 4484 尺(識別子情報)のみ指定可能 最小テンプレートでカット番号のある空エントリのみが処理対象 4485 4486 現在のTitle+Opus(product)の既存カットに対する衝突は排除 4487 4488 初期状態の、ライン/ステージ/ジョブの指定が可能 4489 引数で与えられるXpsのステータスは、"Floating"である必要がある 4490 */ 4491 serviceAgent.addEntry=function(myXps,callback,callback2){ 4492 if(!myXps){ 4493 //console.log(documentDepot); 4494 if(xUI.uiMode!='management') return false; 4495 var myIdentifier = documentDepot.buildIdentifier(); 4496 //console.log(decodeURIComponent(myIdentifier)); 4497 var entryInfo = Xps.parseIdentifier(myIdentifier); 4498 myXps = new Xps(5,entryInfo.time); 4499 myXps.title = entryInfo.title; 4500 myXps.opus = entryInfo.opus; 4501 myXps.subtitle = entryInfo.subtitle; 4502 myXps.cut = entryInfo.cut; 4503 myXps.createUser = xUI.currentUser; 4504 myXps.updateUser = xUI.currentUser; 4505 myXps.currentStatus = new JobStatus(); 4506 var productIdf = Xps.getIdentifier(myXps,'product'); 4507 //新規エントリを判定 4508 if((String(myXps.cut).length==0)||(serviceAgent.currentRepository.entry(myIdentifier))){ 4509 var msg = ""; 4510 if (String(myXps.cut).length==0){ 4511 //console.log(String(myXps.cut)); 4512 msg += localize(nas.uiMsg.alertCutIllegal);//"カット番号不正" 4513 }else{ 4514 msg += localize(nas.uiMsg.alertCutConflict);//"カット番号衝突" 4515 } 4516 alert(msg+': can not addEntry'); 4517 return false; 4518 }else{ 4519 //限定条件下なのでコールバックを規定値で行う 4520 serviceAgent.addEntry(myXps,function(){ 4521 serviceAgent.currentRepository.getSCi(false,false,Xps.getIdentifier(myXps)); 4522 },function(){ 4523 //console.log('error: addEntry') 4524 }); 4525 }; 4526 return; 4527 }else{ 4528 var myIdentifier = Xps.getIdentifier(myXps); 4529 //既存カットと一致(排除) 4530 if(this.currentRepository.entry(myIdentifier)){ 4531 alert(localize(nas.uiMsg.alertCutConflict)); 4532 return false; 4533 } 4534 4535 //既存プロダクトあり(プロダクト作成処理不用) 4536 if(this.currentRepository.entry(myIdentifier,true)){ 4537 serviceAgent.pushEntry(myXps,callback,callback2); 4538 }else{ 4539 //既存のタイトルがあるか?あればエピソードのみ新作 4540 //なければタイトルを作成後にエピソードを新作して処理続行 4541 // confirmあり 4542 var hasTitle = false; 4543 var hasOpus = false; 4544 for (var pid=0;pid<documentDepot.products.length;pid ++){ 4545 //productsのメンバをオブジェクト化したほうが良いかも 4546 var prdInfo=Xps.parseProduct(documentDepot.products[pid]); 4547 if(prdInfo.title== myXps.title) { 4548 hasTitle = documentDepot.products[pid]; 4549 if(prdInfo.opus == myXps.opus) {hasOpus = documentDepot.products[pid];break;} 4550 } 4551 } 4552 if((hasTitle)&&(! hasOpus)){ 4553 var msg=localize({ 4554 en:"The specified episode #%1[%2] is not registered in this sharing.\nwould you like to create a new episode #%1[%2]?\nTo change sharing please cancel once and try the procedure again.", 4555 ja:"この共有には指定の制作話数 #%1[%2] が登録されていません。\n新規に制作話数 #%1[%2] を登録しますか?\n共有を変更する場合は一旦キャンセルして手続をやり直してください。"},myXps.opus,myXps.subtitle); 4556 if(confirm(msg)) 4557 serviceAgent.currentRepository.addOpus(myIdentifier,productIdf,function(){ 4558 serviceAgent.pushEntry(myXps,callback,callback2); 4559 }); 4560 }else if((! hasTitle)&&(! hasOpus)){ 4561 var msg=localize({ 4562 en:"The specified production %1#%2[%3] is not registered in this sharing.\nwould you like to create a new production %1#%2[%3]?\nTo change sharing please cancel once and try the procedure again.", 4563 ja:"この共有には指定された作品 %1#%2[%3] が登録されていません。\n新規に %1#%2[%3] を登録しますか?\n\n共有を変更する場合は一旦キャンセルして手続をやり直してください。"},myXps.title,myXps.opus,myXps.subtitle); 4564 if(confirm(msg)) 4565 serviceAgent.currentRepository.addTitle(myXps.title,"","",function(){ 4566 serviceAgent.currentRepository.addOpus(myIdentifier,myIdentifier,function(){ 4567 serviceAgent.pushEntry(myXps,callback,callback2); 4568 }); 4569 }); 4570 }else{ 4571 serviceAgent.pushEntry(myXps,callback,callback2); 4572 }; 4573 4574 }; 4575 }; 4576 }; 4577 /** 4578 工程を閉じて次の工程を開始する手続き 4579 逆戻り不能なのでチェックを厳重に 4580 4581 */ 4582 serviceAgent.receiptEntry=function(){ 4583 var currentEntry = this.currentRepository.entry(Xps.getIdentifier(xUI.XPS)); 4584 // var currentEntry = (typeof myIdentifier == 'undefined')?this.currentRepository.entry(Xps.getIdentifier(xUI.XPS)):this.currentRepository.entry(myIdentifier); 4585 if(! currentEntry) return false; 4586 var currentStatus=currentEntry.getStatus(); 4587 //console.log(currentStatus); 4588 switch (currentStatus.content){ 4589 case 'Startup': case 'Active': case 'Hold':case 'Floating': 4590 console.log("not Fixed :"+currentEntry.toString()); 4591 return false; 4592 break; 4593 case 'Fixed': 4594 //Fixedのみを処理 4595 var newStageList = nas.pmdb.stages.getTemplate(xUI.XPS.stage.name); 4596 var newJobList = nas.pmdb.jobNames.getTemplate(xUI.XPS.stage.name); 4597 var title = localize(nas.uiMsg.pMreseiptStage);//'作業検収 / 工程移行'; 4598 var msg = localize(nas.uiMsg.dmPMnewStage);//'現在の工程を閉じて次の工程を開きます。\n新しい工程名を入力してください。\nリストにない場合は、工程名を入力してください。'; 4599 var msg2 = '<br><span>' 4600 + localize(nas.uiMsg.pMcurrentStage) 4601 + ' : %currentStage% <br>' 4602 + localize(nas.uiMsg.pMnewStage) + ' : '+ nas.incrStr(xUI.XPS.stage.id) 4603 + ':</span><input id=newStageName type=text list=taragetStageList onChange="serviceAgent.updateNewJobName(this.value);"></input><datalist id=taragetStageList>'; 4604 msg2 = msg2.replace(/%currentStage%/,xUI.XPS.stage.toString(true)); 4605 for(var idx = 0 ; idx < newStageList.length;idx ++){ 4606 msg2 += '<option value="'; 4607 msg2 += newStageList[idx]; 4608 msg2 += '"></option>'; 4609 }; 4610 msg2 += '</datalist>'; 4611 msg2 += '<br><span>' 4612 + localize(nas.uiMsg.pMnewJob) + ' : 0' 4613 +':</span><input id=newJobName type=text list=taragetJobList ></input><datalist id=taragetJobList></datalist>'; 4614 nas.showModalDialog('confirm',[msg,msg2],title,false,function(){ 4615 var newStageName = document.getElementById('newStageName').value; 4616 var newJobName = document.getElementById('newJobName').value; 4617 if ((this.status == 0)&&(newStageName)&&(newJobName)){ 4618 //if(dbg) console.log([newStageName,newJobName]); 4619 serviceAgent.currentRepository.receiptEntry(newStageName,newJobName); 4620 } 4621 }); 4622 4623 break; 4624 } 4625 } 4626 /** 4627 当該エントリの制作を中断する。 4628 以降は複製のみ可能となる 4629 */ 4630 serviceAgent.abortEntry=function(myIdentifier,callback,callback2){ 4631 var currentEntry = (typeof myIdentifier == 'undefined')? this.currentRepository.entry(Xps.getIdentifier(xUI.XPS)):this.currentRepository.entry(myIdentifier); 4632 //console.log(currentEntry) 4633 if(! currentEntry) return false; 4634 var currentStatus=currentEntry.getStatus(); 4635 //console.log(currentStatus) 4636 switch (currentStatus.content){ 4637 case 'Startup': 4638 case 'Hold': 4639 case 'Active': 4640 case 'Floating': 4641 //管理モード下でのみ処理 このメソッドのコール自体が管理モード下でのみ可能にする 4642 //リポジトリに対して 4643 break; 4644 case 'Fixed': 4645 default: 4646 //console.log('serviceAgent abort entry'); 4647 return this.currentRepository.abortEntry(myIdentifier,callback,callback2); 4648 } 4649 return currentStatus.content; 4650 } 4651 /** 4652 閉じる 4653 開いているエントリが、ActiveならばHoldに変更 4654 XPSをカラ(初期状態=float)する 4655 ドキュメントの状態をFloatingにセット 4656 4657 現状のドキュメントをフロート化する際はfloatEntryメソッドを使用 4658 4659 */ 4660 serviceAgent.closeEntry=function(callback,callback2){ 4661 // ドキュメントがアクティブで変更フラグが立っている場合 holdしてカレントリポジトリにプッシュ 4662 if((xUI.XPS.currentStatus.content=="Active")&&(! xUI.isStored())){ 4663 // 成功したらカレントドキュメントをクリアしてロック 4664 serviceAgent.currentRepository.deactivateEntry(function(){ 4665 serviceAgent.closeEntry(callback,callback2); 4666 },function(){ 4667 xUI.errorCode=9; 4668 if(callback2 instanceof Function) callback2(); 4669 } 4670 ); 4671 }else{ 4672 xUI.resetSheet(new Xps(5,144),new Xps(5,144)); 4673 xUI.XPS.currentStatus= new JobStatus("Floating"); 4674 xUI.setUImode('floating'); 4675 if(callback instanceof Function) callback(); 4676 } 4677 } 4678 /** 4679 フロート化 4680 ドキュメントを複製してFloating状態にする 4681 開いているエントリが、ActiveならばHoldに変更する 4682 XPSはそのままの状態でステータスをフロート化する 4683 レポジトリ上のエントリーは変更なし 4684 これは単純なエクスポートであり、管理情報はここで切れる 4685 */ 4686 serviceAgent.floatEntry=function(callback,callback2){ 4687 // ドキュメントがアクティブで変更フラグが立っている場合 holdしてカレントリポジトリにプッシュ 4688 if((xUI.XPS.currentStatus.content=="Active")&&(! xUI.isStored())){ 4689 // 成功したらカレントドキュメントをクリアしてロック 4690 serviceAgent.currentRepository.deactivateEntry(function(){ 4691 serviceAgent.floatEntry(); 4692 },function(){ 4693 xUI.errorCode=9; 4694 if(callback2 instanceof Function) callback2(); 4695 } 4696 ); 4697 }else{ 4698 xUI.XPS.currentStatus.content='Floating'; 4699 xUI.setUImode('floating'); 4700 if(callback instanceof Function) callback(); 4701 } 4702 } 4703 /** 4704 最終ジョブを破棄する(巻き戻し) 4705 現在のジョブ内容を、保存含めて破棄する 4706 破棄可能な条件は、 4707 現在作業中のジョブまたは作業可能なジョブであること(Activeドキュメントのみに適用) 4708 closeに手順がにているが、ハードデリートを伴う点が異なる 4709 ハードデリートを伴うため バックアップコピーを作成して保険として使うべき 4710 4711 */ 4712 serviceAgent.destroyJob=function(callback,callback2){ 4713 if(xUI.XPS.currentStatus.content !="Active"){alert("this entry is not active.");return false;} 4714 //ドキュメントがアクティブでない場合は操作不能 4715 var currentEntry = serviceAgent.currentRepository.entry(Xps.getIdentifier(xUI.XPS)); 4716 var currentOpus = serviceAgent.currentRepository.opus(currentEntry.toString(0)); 4717 //console.log(currentOpus) 4718 var currentWork = [ 4719 xUI.XPS.line, 4720 xUI.XPS.stage, 4721 xUI.XPS.job 4722 ].join("//"); 4723 var msg=currentEntry.toString() + "\n" +localize({ 4724 en:"%1 : Discard the current work and return it to the state of the previous work. Is it OK?", 4725 ja:"%1 : 現在の作業を廃棄して、一つ前の作業の状態にもどします。よろしいですか?" 4726 },currentWork); 4727 if(confirm(msg)){ 4728 //console.log('bkup'); 4729 xUI.setBackup();//自動でバックアップをとる(undoではない) 4730 serviceAgent.currentRepository.destroyJob(function(){ 4731 alert("destroyed job :" +currentWork); 4732 serviceAgent.currentRepository.getSCi(false,false,currentOpus.token); 4733 documentDepot.documentsUpdate(); 4734 //console.log(serviceAgent.currentRepository); 4735 alert(currentEntry.toString(1)); 4736 serviceAgent.getEntry(currentEntry.toString(1),function(){ 4737 xUI.setUImode("browsing");sync("productStatus"); 4738 }) 4739 },function(result){ 4740 //console.log(result) 4741 alert("作業取り消しに失敗しました。"); 4742 }); 4743 } 4744 } 4745 /** 4746 選択可能な参考ジョブリストの更新 4747 更新されたリスト以外のジョブ名称も認められる 4748 */ 4749 serviceAgent.updateNewJobName=function(stageName,type){ 4750 var targetList=document.getElementById("taragetJobList"); 4751 if(! targetList) return false; 4752 for (var i = targetList.childNodes.length-1; i>=0; i--) { 4753 targetList.removeChild(targetList.childNodes[i]); 4754 } 4755 if(!type) type='init'; 4756 var newJobList = nas.pmdb.jobNames.getTemplate(stageName,type); 4757 for(var idx = 0 ; idx < newJobList.length;idx ++){ 4758 var option = document.createElement('option'); 4759 option.id = idx; 4760 option.value = newJobList[idx]; 4761 targetList.appendChild(option); 4762 }; 4763 // if(dbg) console.log(newJobList); 4764 } 4765 //Test code 4766 /** 4767 サーバエージェントを経由してリポジトリにデータを送出する 4768 保存データが最新のissueでない場合はリジェクト 4769 この場合はデータの更新があるかないかは問わない 4770 ステータスがFloatingの場合は、複製をとってStartup状態でプッシュする 4771 */ 4772 serviceAgent.pushEntry=function(myXps,callback,callback2){ 4773 //console.log('serviceAgent.pushEntry'); 4774 if (typeof myXps == 'undefined') myXps = xUI.XPS; 4775 if((xUI.XPS === myXps)&&(xUI.sessionRetrace > 0)){ 4776 xUI.errorCode=8;//確定済データを更新することはできません 4777 alert(localize(xUI.errorMsg[xUI.errorCode])); 4778 return false; 4779 } 4780 if (!( myXps instanceof Xps)){ 4781 if(callback2 instanceof Function){callback2();} 4782 return false; 4783 } 4784 var newXps = new Xps(); 4785 newXps.parseXps(myXps.toString()); 4786 4787 if(myXps.currentStatus.content.indexOf('Floating')>=0){ 4788 /*プッシュ条件 4789 タイトルが存在する、エピソードが存在する 4790 カット番号がある 4791 ユーザ情報が存在する 4792 ここでユーザアサインメントを付加することが可能ーーー未実装 201802 4793 */ 4794 var msg=localize({ 4795 en:"Add the current cut: %1 :\nto the share : %2 :.\n Is it OK?", 4796 ja:"現在のカット: %1 :を\n共有: %2 :に追加します。\nよろしいですか?" 4797 },myXps.getIdentifier(),serviceAgent.currentRepository.name) 4798 // "TEST push Entry :"+myXps.getIdentifier(); 4799 var go=confirm(msg); 4800 if(go){ 4801 /* データステータスをチェック 4802 カレントタイトルがない場合は新作 4803 カレントのopusが無い場合は新作 4804 いずれも コールバック処理渡し 4805 データステータスがFloatingなので、Startupへ変更 4806 */ 4807 newXps.currentStatus = new JobStatus('Startup'); 4808 }else{ 4809 return false;//処理中断 4810 } 4811 } 4812 // console.log(newXps); 4813 this.currentRepository.pushEntry(newXps,callback,callback2); 4814 } 4815 /** 4816 4817 Repos.getProducts();//一度初期化する 4818 if(dbg) console.log(Repos.productsData); 4819 Repos.getList(); 4820 4821 */ 4822 /** 4823 入力テキストをパースしてカットを集計した配列を返す 4824 入力書式は別紙 4825 */ 4826 function parseCutText(sourceText){ 4827 var sepChar = '\t';//セパレータ初期値H-TAB 4828 var commentRegex = new RegExp('(#|;|//)'); 4829 var cutRegex = new RegExp('cut(#|#|no\.|№)?','i'); 4830 var timeRegex = new RegExp('(time|duration|seconds|秒|時間|尺)','i'); 4831 var sourceArray=sourceText.split('\n'); 4832 var dataStartLine = -1; 4833 var namePosition = -1;var timePosition= -1; 4834 4835 for (var lid=0;lid<sourceArray.length;lid++){ 4836 if(String(sourceArray[lid]).match(/^\s*$/)||String(sourceArray[lid]).match(commentRegex)){ 4837 continue; 4838 }else{ 4839 dataStartLine = lid; 4840 if(String(sourceArray[lid]).match(/,/)){sepChar = ','}; 4841 var myFields = String(sourceArray[lid]).split(sepChar); 4842 for (var fid=(myFields.length-1);fid>=0;fid--){ 4843 if(myFields[fid].match(cutRegex)) {namePosition=fid}; 4844 if(myFields[fid].match(timeRegex)){timePosition=fid}; 4845 } 4846 break; 4847 } 4848 } 4849 // console.log(dataStartLine) 4850 4851 if(namePosition==-1){ 4852 namePosition=0; 4853 if(timePosition != -1){dataStartLine ++}; 4854 timePosition=1; 4855 }else{ 4856 dataStartLine ++; 4857 } 4858 4859 //console.log(dataStartLine) 4860 var resultArray=[]; 4861 var cutName="";var cutTime=""; 4862 var currentName="";var currentTime=0; 4863 4864 for (var lid=dataStartLine;lid<sourceArray.length;lid++){ 4865 if(String(sourceArray[lid]).match(/^\s*$/)||String(sourceArray[lid]).match(commentRegex)){ 4866 continue; 4867 }else{ 4868 var myFields = String(sourceArray[lid]).split(sepChar); 4869 cutName = (myFields[namePosition])? String(myFields[namePosition]) :currentName; 4870 if (cutName.match(/^"([^"]*)"$/)){cutName=RegExp.$1};//" 4871 cutTime = (timePosition < 0)? "":String(myFields[timePosition]); 4872 if (cutTime.match(/^"([^"]*)"$/)){cutTime=RegExp.$1};//" 4873 cutTime = parseInt(nas.FCT2Frm(decodeURI(cutTime)),10); 4874 // console.log(cutName+":"+currentName); 4875 if((cutName != currentName)&&(currentName.length>0)){ 4876 resultArray.push([currentName,currentTime]); 4877 currentTime = cutTime; 4878 }else{ 4879 currentTime+=cutTime; 4880 } 4881 currentName = cutName; 4882 } 4883 } 4884 resultArray.push([currentName,currentTime]); 4885 return resultArray; 4886 } 4887 // test 4888 //sourceText="1,24\n2,48\n3,12\n,12"; 4889 /** 4890 sourceText=([ 4891 "cut\tb\ttime\td\te", 4892 "1\tX\t30\tA\tA", 4893 "2\tW\t30\tA\tA", 4894 "3\tZ\t30\tA\tA", 4895 "\t''\t30\tA\tA", 4896 ]).join("\n"); 4897 sourceText=document.getElementById('data_well').value; 4898 parseCutText(sourceText); 4899 */ 4900 4901 /* 4902 インポート/エクスポートウェルに置いたカット登録テキストを識別子に変換して 4903 entryQueueを作成 4904 これを引数にしてpushEntryを順次コールする。 4905 4906 */ 4907 serviceAgent.entryQueue = []; 4908 serviceAgent.entryQueue.select = 0; 4909 4910 makeNewEntriesFromFormatedText=function(ix){ 4911 if(typeof ix == 'undefined'){ 4912 var sourceText=document.getElementById('data_well').value; 4913 serviceAgent.entryQueue = parseCutText(sourceText); 4914 for (var qid=0;qid<serviceAgent.entryQueue.length;qid++){ 4915 var cutNo = serviceAgent.entryQueue[qid][0]; 4916 var cutTime = serviceAgent.entryQueue[qid][1];//整数化が済んでいるものとする 4917 if((String(cutNo).length > 0)&&(cutTime > 0)){ 4918 // ビルドの際にXPSを参照するのはあまり良くない これは引数で与えるか、またはdocumentDepotのプロパティから取得する 4919 var myXps = new Xps(5,cutTime); 4920 myXps.title = xUI.XPS.title; 4921 myXps.opus = xUI.XPS.opus; 4922 myXps.subtitle = xUI.XPS.subtitle; 4923 myXps.cut = cutNo;//sciはやく 4924 myXps.create_user = xUI.currentUser; 4925 }else{ 4926 myXps=null; 4927 } 4928 serviceAgent.entryQueue[qid] = myXps; 4929 } 4930 serviceAgent.entryQueue.select = 0;//エントリ用のキューを初期化 4931 ix = 0; 4932 } 4933 //カット番号が空・カット尺が0 の場合は処理スキップ 4934 4935 //console.log("queue entry : "+ix); 4936 4937 if(serviceAgent.entryQueue[ix]){ 4938 //console.log(serviceAgent.entryQueue[ix]); 4939 //console.log(decodeURIComponent(Xps.getIdentifier(serviceAgent.entryQueue[ix]))); 4940 serviceAgent.currentRepository.pushEntry(serviceAgent.entryQueue[ix],function(){ 4941 serviceAgent.entryQueue.select ++; 4942 if(serviceAgent.entryQueue.select < serviceAgent.entryQueue.length){ 4943 makeNewEntriesFromFormatedText(serviceAgent.entryQueue.select); 4944 }else{ 4945 //終了 4946 alert('エントリ終了だと思われるナリ :' + serviceAgent.entryQueue.select+"/"+serviceAgent.entryQueue.length) 4947 } 4948 }); 4949 }else{ 4950 //エントリ不正の場合は、処理スキップ 4951 serviceAgent.entryQueue.select ++; 4952 if(serviceAgent.entryQueue.select < serviceAgent.entryQueue.length) 4953 makeNewEntriesFromFormatedText(serviceAgent.entryQueue.select); 4954 } 4955 }; 4956 4957 //makeNewEntriesFromFormatedText(); 4958 4959 /** 4960 プロダクトデータDB 4961 object Pm.Title={ 4962 token:token-string, //ローカルリポジトリのキー 4963 name:title-short-name, 4964 description:title-string, 4965 created_at:time-created, 4966 updated_at:time-updated, 4967 episodes:[[array of Pm.Opus]] 4968 } 4969 object Pm.Opus={ 4970 token:token-string, 4971 name:opus-name 4972 description:opus-string-long(ex subtitle) 4973 created_at:time-created, 4974 updated_at:time-updated, 4975 cuts:[[array of SCi]] 4976 } 4977 object Pm.SCi={ 4978 token:token-string, 4979 name:opus-name 4980 description:entry-identifier-string, 4981 versions:[] 4982 } 4983 4984 object PM.SCiVersion={ 4985 content:[line,stage,Job] 4986 updated_at:time-updated, 4987 description:entry-identifier-string, 4988 version_token:59 4989 } 4990 4991 productsData=[ 4992 { 4993 "token":"fTkqAmVz8ZEfrctW7JrrJ66g", 4994 "name":"mns2_r", 4995 "description":"モンスターストライク2", 4996 "created_at":"2017-01-20T09:42:30.000+09:00", 4997 "updated_at":"2017-01-20T11:59:02.000+09:00", 4998 "episodes":[ 4999 [ 5000 { 5001 "token":"CKmnhS6iu3Hw8Jh2nZyNBWtB", 5002 "name":"00", 5003 "description":"", 5004 "created_at":"2017-01-20T09:43:01.000+09:00", 5005 "updated_at":"2017-01-20T11:28:12.000+09:00", 5006 "cuts":[[ 5007 { 5008 "token":"aDZn4cteVMUSvAsuJa3hmZGW", 5009 "name":"001", 5010 "description":"mns2_r#00//001", 5011 "versions":[] 5012 }, 5013 { 5014 "token":"tCEpSnz9BanvwKrCdtqc5fSs", 5015 "name":"1", 5016 "description":"mns2_r#00//1", 5017 "versions":[] 5018 }, 5019 { 5020 "token":"85c5q2NsNbdXmqkFrMS6jyJy", 5021 "name":"s-c2", 5022 "description":"mns2_r#00//s-c2//0%3A(undefined)//0%3A//0%3Aundefined//Fixed", 5023 "versions":[ 5024 { 5025 "updated_at":"2017-01-20T11:52:12.000+09:00", 5026 "description":null, 5027 "version_token":59 5028 }, 5029 { 5030 "updated_at":"2017-01-20T12:13:58.000+09:00", 5031 "description":"mns2_r#00//s-c2(144)//0%3A(undefined)//%3Aundefined//undefined%3ALO//Active", 5032 "version_token":115 5033 }] 5034 }]], 5035 } 5036 ] 5037 ] 5038 } 5039 ] 5040 //listEntrオブジェクトプロパティ 5041 5042 object listEntry={ 5043 dataInfo : 識別子情報オブジェクト, 5044 parent : リポジトリへの参照, 5045 product : プロダクト識別子-encoded, 5046 sci : 代表カット番号 -encoded, 5047 issues : [[ 5048 ライン情報 -encoded, 5049 ステージ情報-encoded, 5050 ジョブ情報 -encoded, 5051 ステータス -encoded 5052 ]], 5053 issues[0].identifier :カット識別子, 5054 issues[0].time :代表カット尺, 5055 issues[0].cutID :DBアクセスキー, 5056 issues[0].versionID :DBアクセスキー, 5057 titleID : DBアクセスキー, 5058 episodeID : DBアクセスキー 5059 } 5060 5061 アクティブなカットがある状態で、カレントのリポジトリを切り替えると問題が発生するので対応を考えること 5062 編集中のエントリをキャッシュするか、切替前のリポジトリをキャッシュ? 5063 または 切替時にエントリを強制クローズ < これで対処 5064 5065 リポジトリ切り替えのタイミングで強制的にアクティブなドキュメントをディアクティベートすることで処理 5066 5067 切り替えのタイミングでセレクタが使えなくなる(表示データの信頼性が無くなる)タイミングでセレクタを不活性化 5068 5069 データ更新が終了した時点で再活性化するように変更(済) 5070 5071 ネットワーク上でのDB更新にまだ問題あり dev に適用して調整 5072 5073 */