1 /** 2 * @fileOverview pmio.js 3 * production managemaent io 4 * 5 * nas.Pm は 管理情報を分離するためのオブジェクト群 6 * 7 * PmUnitを中核にしてそれに含まれる被管理情報をオブジェクトとして保持する 8 */ 9 /* 10 * 11 * PmUnitは Production(or Project) Management Unit(マネジメントユニット)を表す 12 * =カット袋に相当するオブジェクトの拡張機能= 13 * 14 * 制作ライン及びステージングを管理するためのオブジェクト 15 * カレントの ライン、ステージ、ジョブの値をひとまとめに保持する 16 * 制作上の既経路を保持 17 * エレメントグループに対する変更権の保持(ラインが持つ情報) 18 * 及びこれらの情報に対するアクセスを受け持つ 19 * 開始時間 伝票番号 担当ユーザなどを参照・設定・変更が可能 20 * オブジェクト初期化時点では、空のオブジェクトを作成する 21 * 22 * カット管理を行う場合は ALLアセットを、他の個別素材の場合は個別アセットを引数にして初期化のこと 23 24 nas.Pm配下のDB通信オブジェクトは、アクセスポイントとして 25 nas.pmdb オブジェクトを置いてその配下に参照を配置する 26 配置されたオブジェクト群は基本的な情報テンプレートとして働く 27 28 ClassObject nas.Pm がアプリケーションとしてのテンプレートキャリア 29 初期状態ではnas.pmdbを実アクセスポイントとして参照を置く 30 nas.pmdb は、リポジトリ切り替え毎に各リポジトリの.pmdbに参照先が切り替えられる? 31 32 nas.pmdb.organizations 33 関連組織一覧 組織情報コレクション 34 プライマリエントリーとしてpmdbの組織情報をエントリーする 35 他組織のエントリは、接続情報のみでusersには通常自身のエントリのみを複製する 36 nas.pmdb.users 37 関連ユーザ一覧 ユーザ情報コレクション 38 nas.pmdb.staff 39 スタッフ一覧 スタッフコレクション 40 41 nas.pmdb.lines 42 ライン一覧テーブル ラインコレクション 43 nas.pmdb.stages 44 ステージ一覧テーブル ステージコレクション 45 nas.pmdb.pmTemplates 46 制作管理テンプレートコレクション 47 ラインテンプレート(ライン定義) 48 ラインテンプレートの内容は自分自身と自分で保持するステージコレクション 49 nas.pmdb.jobNames 50 ジョブテンプレートコレクション 51 52 nas.pmdb.workTitles 53 .workTitles[titleIndex].episodes 54 .episodes[episodeIndex].works ? 55 56 nas.pmdb.products 57 58 nas.pmdb.assets 59 アセット情報コレクション 60 制作時に管理対象となるアセットの定義テーブル 61 nas.pmdb.medias 62 制作メディアコレクション 63 制作に供されるメディア情報のトレーラー 64 65 等々 その際にparent 経由で相互の参照を行うので初期化時のパラメータ注意 66 nas オブジェクト内では以下の相互関係を持つ 67 68 nas.Pm.~ マスターとなるクラスデータ 69 nas.Repository.pmd.~ サーバごとのカスタマイズデータ 70 nas.pmdb.~ 実アクセスポイント 71 配下の各オブジェクトのparentは、それぞれの親をポイントして初期化 72 73 Pmモジュールに設定パーサを実装 74 設定パーサは設定ストリームを入力として、リジョン毎に分離 75 各リジョンを適切のパーサに振り分けて、自身のコレクションDBを再初期化する 76 各パーサは、追加処理を行うが、設定パーサ側でデータのクリアを行い、再初期化動作とする 77 78 nas.Pm.parseConfig(ストリーム) 79 80 nas.pmdb.users 81 nas.pmdb.staff 82 83 nas.pmdb.assets 84 nas.pmdb.medias 85 86 nas.pmdb.lines 87 nas.pmdb.stages 88 nas.pmdb.jobNames 89 90 91 // products/workTitles はPmクラスのみに存在するキャッシュオブジェクトなので要注意 92 nas.Pm.products リポジトリ内に記録されたエピソード単位のキャッシュ 93 nas.Pm.workTitles 同、作品単位のデータコレクション 94 95 Object PmDomain 96 nas.Pm.WorkTitle.pmd 97 ・ 98 ・ 99 100 pmdbオブジェクトは親オブジェクトへの参照 pmdb.parent を持つ 101 このプロパティは、pmdbが持つ情報の親ノードへの参照 102 親ノードは以下のオブジェクトに対応する 103 104 organization = Repository.pmdb //pmdb.parent = Repository ; Repository.parent='.'; 105 product(title) = products/product.pmdb //product.pmdb.parent = product ; product.parent = Repository; 106 episode(opus) = product/episodes/episode.pmdb //episode.pmdb.parent = episode ; episode.parent = product; 107 cut(work) = episode/cuts/cut.pmdb //cut.pmdb.parent = cut ; cut.parent = episode 108 各ノードはツリー内を相互にアクセスするための .parentプロパティをもつ 109 pmdbはノードに対する.parent参照を持つ 110 pmdb からツリー上位のpmdbにアクセスするためには this.parent.parent.pmdbをアクセスする必要がある OK? 111 112 organization: 113 repository: 114 product 115 title: 116 opus: 117 pmu: 118 cut: 119 120 121 pmdbの各オブジェクトにはユニークなプロパティを格納するunique配列をもたせる 122 この配列に値がある場合、新規メンバー登録の比較条件としてそのプロパティを参照する 123 RDBMのuniqueインデックスの付いたフィールドに同じ 124 125 */ 126 /** 127 * @class 128 */ 129 nas.Pm = {}; 130 //nas.Pm.organization = new nas.Pm.Organization() 131 nas.Pm.users = new nas.UserInfoCollection(); 132 nas.pmdb = nas.Pm; 133 134 /* 135 PmDomain オブジェクトは、制作管理上の基礎データを保持するキャリアオブジェクト 136 制作管理ディレクトリノード毎に保持される。 137 基礎データを必要とするプログラムに基礎データをサービスする 138 基本データが未登録の場合は親オブジェクトの同データを参照してサービスを行う 139 140 case:localRepository 141 localRepository.pmdb = new nas.Pm.PmDomain(localRepository); 142 case:NetworkRepository 143 NetworkRepository.pmdb = new nas.Pm.PmDomain(NetworkRepository); 144 */ 145 nas.Pm.PmDomain=new function(myParent){ 146 this.parent=myParent; 147 this.users; // 148 this.staff; // 149 this.lines; // 150 this.stages; // 151 this.jobNames; // 152 this.organization 153 this.medias; 154 155 } 156 157 /** 158 * @method 159 * クラスメソッド 160 * @desc 161 * ターゲットコレクション内にkeywordに一致するプロパティを持っているメンバーがあればコレクションメンバーのキー値を返す 162 * keyword がメンバーキーだった場合はそのまま返す 163 * 検索に失敗したらfalse 164 * オブジェクト本体が必要な場合は、Object.members[key]またはこの検索関数を間接的にコールする_getMemberメソッドを使用 165 * タイトル/エピソード/メディア/アセット/ライン/ステージ 共用 166 * @param {string} keyword 167 * @return {property} 168 * memberProp 169 * キーワードは、各コレクションの共通プロパティで、検索対象となるもの 170 id DBアクセス用のキー値(予約) 171 projectName 作品としてのタイトル タイトルに所属する情報の場合に有効だが、検索キーとしてはタイトルコレクション以外では無効 172 name コレクションメンバーの一般名称 173 shortName コレクションメンバーの省略表記 174 fullName コレクションメンバーの正式表記 175 code コレクションメンバーの短縮アイテムコード 176 * 177 */ 178 nas.Pm.searchProp = function(keyword,target){ 179 if(target.members[keyword]) return keyword; 180 for (var prp in target.members){ 181 if( (target.members[prp].id ==keyword)|| 182 (target.members[prp].name ==keyword)|| 183 (target.members[prp].projectName ==keyword)|| 184 (target.members[prp].episodeName ==keyword)|| 185 (target.members[prp].mediaName ==keyword)|| 186 (target.members[prp].shortName ==keyword)|| 187 (target.members[prp].fullName ==keyword)|| 188 (target.members[prp].code ==keyword) ) return prp; 189 } 190 return false; 191 } 192 /* 193 コレクションメンバーキャリアが配列の場合は以下を使用 194 使えないかも 195 */ 196 nas.Pm.searchPropA = function(keyword,target){ 197 if(! target.unique) return false; 198 //メンバー総当たり 199 for (var mix = 0 ; mix < target.menbers.length ; mix ++){ 200 //オブジェクトのプロパティ内で unique情報のあるプロパティのみを検索 201 for (var uix = 0 ; uix < target.unique.length ; uix ++){ 202 if( 203 ((target.members[mix][target.unique[uix]].sameAs)&&(target.members[mix][target.unique[uix]].sameAs(keyword))) || 204 (target.members[mix][target.unique[uix]].toString()==keyword) 205 ) return target.members[mix] 206 } 207 } 208 return null; 209 } 210 211 /** 212 クラスメソッド nas.Pm.searchPropを使ってキーを検索して対応するメンバーを返すオブジェクトメソッド 213 検索に失敗したケースではnullを戻す 214 引数を与えない場合に限り、メンバー内の最初のエントリを戻す 215 これは デフォルトエントリとして使用される 216 デフォルトエントリを必ず最初に登録する必要がある 217 通常は各コレクションの.entryメソッドにマッピングされる 218 */ 219 nas.Pm._getMember = function(keyword){ 220 if(typeof keyword=='undefined'){for (itm in this.members){return this.members[itm];break;}} 221 if(this.members[keyword]) return this.members[keyword]; 222 var prp = nas.Pm.searchProp(keyword,this); 223 if(prp){return this.members[prp]}else{return null} 224 } 225 226 /** 227 コレクションメンバーをテキストとしてダンプ出力するメソッド 汎用 228 対象コレクション 229 nas.Pm.OrganizationCollection //nas.pmdb.Organizations.dump(); 230 nas.Pm.WorkTitleCollection //nas.pmdb.workTitles.dump(); 231 nas.Pm.MediaCollection //nas.pmdb.medias.dump(); 232 nas.Pm.AssetCollection //nas.pmdb.assets.dump(); 233 nas.Pm.StageCollection //nas.pmdb.stages.dump(); 234 nas.Pm.LineCollection //nas.pmdb.lines.dump(); 235 236 nsa.Pm.//nas.pmdb.jobNames.dump(true); これは別わけ コレクションの構造が異なる 237 nas.pmdb.//nas.pmdb.pmTemplates.dump(true); 238 239 引数なし メンバーあたり1要素のカンマ区切りテキスト 改行なし 240 代表値 例えばステージならばステージ名を単独でコンマ区切りで戻す 241 242 plain/text プレーンテキスト 文章形式 config.pmdb用 243 可読性の高い平文フォーマット改行あり 244 1要素1行とは限らないので注意 245 246 full/dump プレーンテキスト設定ファイル用のダンプストリーム config.pmdb用 247 コレクションの addMember メソッドで直接処理可能なテキストデータの配列を改行区切りで出力する 248 1要素1レコード 249 250 JSON JSONによるダンプ 汎用的なデータ交換用 251 オブジェクトごとに戻りデータは構造が異なる 252 253 データ形式の複雑なものは汎用メソッドを使用せずに専用メソッドを持つ 254 ただし仕様は汎用メソッドに準ずる 255 */ 256 nas.Pm._dumpList = function(form){ 257 switch (form){ 258 case "JSON": 259 //コレクションのキャリアが配列ベースの場合 260 if(this.members instanceof Array){ 261 var result = []; 262 for (var ix =0 ; ix<this.members.length;ix++){ 263 result.push(JSON.parse((this.members[ix].dump)?this.members[ix].dump(form):this.members[ix].toString(form))); 264 } 265 }else{ 266 //キャリアがオブジェクトベースの場合 267 var result = {}; 268 for (var prp in this.members){ 269 result[prp]=JSON.parse((this.members[prp].dump)?this.members[prp].dump(form):this.members[prp].toString(form)); 270 } 271 } 272 return JSON.stringify(result); 273 break; 274 case "full-dump": 275 case "full": 276 case "dump": 277 var result=""; 278 //コレクションのキャリアが配列ベースの場合 279 if(this.members instanceof Array){ 280 for (var ix =0 ; ix<this.members.length;ix++){ 281 // if (ix > 0) result +=",\n"; 282 if (ix > 0) result +="\n"; 283 result += (this.members[ix].dump )? this.members[ix].dump('full'):this.members[ix].toString('full'); 284 } 285 result += '\n'; 286 }else{ 287 //キャリアがオブジェクトベースの場合 288 for (var prp in this.members){ 289 result += '"'+prp+'",'; 290 result += (this.members[prp].dump)? this.members[prp].dump('full') : this.members[prp].toString('full'); 291 result += '\n'; 292 } 293 } 294 return result; 295 break; 296 case 'plain-text': 297 case 'plain': 298 case 'text': 299 default: 300 var result = new Array; 301 //コレクションのキャリアが配列ベースの場合 302 if(this.members instanceof Array){ 303 for (var ix =0 ; ix<this.members.length;ix++){ 304 result.push((this.members[ix].dump)? this.members[ix].dump(form) : this.members[ix].toString(form)); 305 } 306 }else{ 307 //キャリアがオブジェクトベースの場合 308 for (var prp in this.members){ 309 result.push((this.members[prp].dump)? this.members[prp].dump(form) : this.members[prp].toString(form)); 310 } 311 } 312 return result.join((form)? '\n':','); 313 } 314 } 315 /* コレクションオブジェクトのメンバ追加オブジェクト 316 引数 メンバオブジェクトの配列 317 戻値 追加に成功したエントリ数 318 重複メンバーは登録しない 319 重複の条件は、Collection.unique配列を参照 いずれかのバッティングを(_getMember() で)検出 320 321 */ 322 nas.Pm._addMembers = function(members){ 323 var result = 0; 324 if(!(members instanceof Array)) members = [members]; 325 if (this.members instanceof Array){ 326 for (var ix = 0 ; ix < members.length ; ix++ ){ 327 var tempMember = members[ix]; 328 var conflict = false; 329 if((this.unique)&&(this.entry)){ 330 for (var uix = 0 ; uix < this.members.length ; uix++ ){ 331 if (this.entry(tempMember[this.unique[uix]])!=null){ conflict = true;break;} 332 } 333 } 334 if(! conflict){ 335 var idx = this.members.add(tempMember)>=0; 336 if(ix == idx) result++; 337 } 338 } 339 }else{ 340 for (var ix = 0 ; ix < members.length ; ix++ ){ 341 var tempMember = members[ix]; 342 var conflict = false; 343 for (var uix = 0 ; uix < this.unique.length ; uix++ ){ 344 if (this.entry(tempMember[this.unique[uix]])!=null){ conflict = true;break;} 345 } 346 if(! conflict){ 347 this.members[tempMember[this.unique[0]]]=tempMember; 348 result++; 349 } 350 } 351 } 352 return result; 353 } 354 /* 355 コレクションオブジェクトの設定読み込みメソッド 356 不正データの排除と重複データの排除はコレクションのaddMembersメソッドが受け持つ 357 これは使用されない メンバーごとのオブジェクトの相関が記述できていない 9/3 358 */ 359 /* 360 nas.Pm._parseConfig = function(dataStream,form){ 361 var myMembers =[]; 362 // 形式が指定されない場合は、第一有効レコードで判定 363 if(! form ){ 364 if (dataStream.match(/\[\s*(\{[^\}]+\}\s*,\s*)+(\{[^\}]+\})?\s*\]/)) form='JSON';//配列JSON 365 else if (dataStream.match(/(\n|^)\s*\[\s*.+\]($|\n)/)) form='full-dump'; 366 else form='plain-text'; 367 } 368 switch(form){ 369 case 'JSON': 370 var tempObject=JSON.parse(dataStream); 371 for (var rix=0;rix<tempObject.length;rix++){ 372 var currentMember=new nas.Pm.Object( 373 tempObject[rix]. 374 375 ); 376 currentMember[]=tempObject[rix][]; 377 378 myMembers.push(currentMember); 379 } 380 break; 381 case 'full-dump': 382 dataStream = String(dataStream).split("\n"); 383 for (var rix=0;rix<dataStream.length;rix++){ 384 if((dataStream[rix].indexOf('#')==0)||(dataStream[rix].length == 0)) continue; 385 var currentMember=new nas.Pm.Object( 386 ); 387 currentMember.parse(dataStream[rix]); 388 if (currentMember) myMembers.push(currentMember); 389 } 390 break; 391 case 'plain-text': 392 default: 393 dataStream = String(dataStream).split("\n"); 394 var currentMember=false; 395 for (var rix=0;rix<dataStream.length;rix++) { 396 if((dataStream[rix].indexOf('#')==0)||(dataStream[rix].length == 0)) continue; 397 var currentField=dataStream[rix]; 398 plainフォーマット 399 entryName 400 prop:value 401 prop:value 402 403 if((currentMember)&&(currentField.match(/^\t([^:])+:(.+)/))){ 404 currentMember[RegExp.$1]=RegExp.$2; 405 } else if(currentField.match(/^[a-z].*$/)) { 406 if(currentMember) myMembers.push(currentMember); 407 currentMember=new nas.Pm.Object(currentField); 408 } 409 } 410 myMembers.push(currentMember); 411 } 412 return this.addStaff(myMembers); 413 } 414 */ 415 //test 上記共用メソッドの関与するコレクションの出力確認 416 // nas.pmdb.workTitles.toString(true) 417 // nas.pmdb.medelias 418 /** ProductionManagementNode 419 * 制作管理オブジェクト 420 * @constractor 421 * 制作管理オブジェクトは、それぞれの管理単位(PmUnit=カット袋)についての制作管理部分を抽出したオブジェクトである。 422 * BANK等の管理移管時データ独立性を持たせるために分離される 423 * ラインごとに各PmUnitのプロパティとして登録され、ラインの開始条件及び終了条件の判定を含む 424 * カット袋よりも上位となるエピソード・タイトルについては、このオブジェクトでなくnas.Pm.PmUnitをコレクションメンバーとする上層ノードオブジェクトを作る 425 >>管理がノードベースでありアセット単位にならないため 426 */ 427 nas.Pm.PmNode = function PmNode(targetAsset,myName){ 428 this.target = targetAsset;//管理単位ごとのゴールを設定 429 this.name = myName; 430 this.jobID ; 431 this.jobs = [];//空配列で初期化 コレクションが望ましい 432 this.stageID ; 433 this.stages = [];//空配列で初期化 コレクションが望ましい 434 this.lineID ; 435 this.line ; 436 } 437 /* 438 Pmuコンストラクタ 439 440 PMU = new PmUnit(scObjects); 441 カット袋に相当するワークキャリア(ワークトレーラー) 442 SCiCオブジェクトを配列で与えて初期化する。 443 複数オブジェクトを持つ場合は 兼用カットとして処理する 444 クラスメソッドを使って後から編集可能 445 カット番号等のムービー内での識別情報が複数入っている 446 また、集合全体の進捗情報が格納されている 447 作品情報・管理フラグ・カットコレクション・進捗情報・素材DBを持つ 448 素材DBはPMUと関連付けられたxMapが保持する。 449 管理情報をこのユニットが受け持つ 450 */ 451 452 nas.Pm.PmUnit=function(mySCs){ 453 //初期パラメータの中の第一要素の情報で識別名を作る 454 this.body = mySCs;// 455 this.cut = this.body[0].cut;// 456 this.scene = this.body[0].myScene;// 457 this.subtitle = mySubTitle;//文字列又は参照 458 //サブタイトル記述はDBと接続のない場合は別途入力するか、又は空白のまま保留 459 this.opus = myOpus;//識別文字列(リレーション または ProductOpusオブジェクト) 460 this.title = myTitle;//識別文字列(リレーション または ProductTitleオブジェクト) 461 this.inherit = mySCs; 462 this.pmNode = new nas.PmNode(); 463 } 464 /* 465 制作管理単位の内容ダンプメソッド 466 引数: form 文字列可形式 html,plain, 467 指定がない場合は Sciオブジェクトのリストを"//(ダブルスラッシュ)"で区切って戻す 468 469 470 */ 471 nas.Pm.PmUnit.prototype.toString=function(form){ 472 if(! form){ 473 return this.body.reverse().join("//"); 474 }else{ 475 return "yet coding"; 476 } 477 //toString()メソッドは、出力用に調整する 478 // 479 } 480 //制作管理用 Organizationオブジェクト 各Repositoryに対応する 481 /* 482 nas.Pm.Organization(組織名) 483 484 name =;//識別名 eg."nekomataya" 485 fullName =;//正式名称 eg.'ねこまたや' 486 code =;//省略コード eg.'nkmt' 487 id =;//DB接続用Index eg.'0001' 488 serviceUrl =;//サービス接続情報 eg.'localRepository:info.nekomataya.pmdb' 489 shortName =;//表示用短縮名 eg.'(ね)' 490 contact =;//コンタクト情報 eg.'ねこまたや;//nekomataya@nekomataya.info' 491 description =;//説明 所在住所等自由記述 492 493 オブジェクトメソッドで初期化する 494 戻り値は組織情報オブジェクト 495 実運用上はDBとリンクして動作するように調整 496 初期化段階ではプライマリオブジェクトとしてRepositoryに関連付けられた組織一つだけが登録される 497 498 Organization.usersには、pmdbのusersへの参照か またはカレントのuserのみを登録した一時的ユーザコレクションを用いる? 499 */ 500 nas.Pm.Organization = function(repoitoryName){ 501 this.name =repoitoryName; 502 this.fullName =repoitoryName; 503 this.code =String(repoitoryName).slice(0,4); 504 this.id ; 505 this.serviceUrl ='localRepository:info.nekomataya.pmdb'; 506 this.shortName =String(repoitoryName).slice(0,2); 507 this.contact =repoitoryName; 508 this.description =""; 509 } 510 nas.Pm.Organization.prototype.toString = function(form){ 511 switch(form){ 512 case 'full-dump': 513 case 'full': 514 case 'dump': 515 return JSON.stringify([ 516 this.fullName, 517 this.code, 518 this.id, 519 this.serviceUrl, 520 this.shortName, 521 this.contact, 522 this.description 523 ]); 524 break; 525 case 'plain-text': 526 case 'plain': 527 case 'text': 528 var result=[ 529 this.name, 530 "\tfullName:"+this.fullName, 531 "\tcode:"+this.code, 532 "\tid:"+this.id, 533 "\tserviceUrl:"+this.serviceUrl, 534 "\tshortName:"+this.shortName, 535 "\tcontact:"+this.contact, 536 "\tdescription:"+this.description 537 ]; 538 return result.join('\n'); 539 break; 540 case 'JSON': 541 return JSON.stringify({ 542 "name":this.name, 543 "fullName":this.fullName, 544 "code":this.code, 545 "id":this.id, 546 "serviceUrl":this.serviceUrl, 547 "shortName":this.shortName, 548 "contact":this.contact, 549 "description":this.contact 550 }); 551 break; 552 default: 553 if(this[form]){ 554 return this[form] 555 }else{ 556 return this.name; 557 } 558 } 559 } 560 /** 561 組織コレクション 562 プライマリの組織はデータベースを維持する組織本体の情報 563 564 */ 565 nas.Pm.OrganizationCollection = function(myParent){ 566 this.parent = myParent; 567 this.members = {}; 568 this.unique =["name","id","fullName","serviceUrl","shortName","code"]; 569 } 570 nas.Pm.OrganizationCollection.prototype.entry = nas.Pm._getMember; 571 nas.Pm.OrganizationCollection.prototype.addMembers = nas.Pm._addMembers; 572 nas.Pm.OrganizationCollection.prototype.dump = nas.Pm._dumpList; 573 /* 574 設定パーサ 575 */ 576 nas.Pm.OrganizationCollection.prototype.parseConfig = function(configStream){ 577 if(String(configStream).length==0) return false; 578 var newMembers=[]; 579 this.members = {};//clear 580 var form = 'plain-text'; 581 if(configStream.match(/\{[^\}]+\}/)){ 582 form = 'JSON'; 583 } else if(configStream.match(/.+\,\[.+\]/)){ 584 form = 'full-dump'; 585 } 586 switch(form){ 587 case 'JSON': 588 var configData=JSON.parse(configStream); 589 for(prp in configData){ 590 var tempData = configData[prp]; 591 var newEntry = new nas.Pm.Organization(prp); 592 newEntry.fullName = tempData.fullName; 593 newEntry.code = tempData.code; 594 newEntry.id = tempData.id; 595 newEntry.serviceUrl = tempData.serviceUrl; 596 newEntry.shortName = tempData.shortName; 597 newEntry.contact = tempData.contact; 598 newEntry.description = tempData.description; 599 newMembers.push(newEntry); 600 } 601 break; 602 case 'full-dump': 603 configStream=String(configStream).split('\n'); 604 for(var ir = 0;ir<configStream.length;ir++){ 605 if((configStream[ir].indexOf("#")==0)||(configStream[ir].length==0)) continue;//コメント/空行スキップ 606 var tempData = JSON.parse("["+configStream[ir]+"]"); 607 var newEntry = new nas.Pm.Organization(tempData[0]); 608 newEntry.fullName = tempData[1][0]; 609 newEntry.code = tempData[1][1]; 610 newEntry.id = tempData[1][2]; 611 newEntry.serviceUrl = tempData[1][3]; 612 newEntry.shortName = tempData[1][4]; 613 newEntry.contact = tempData[1][5]; 614 newEntry.description = tempData[1][6]; 615 newMembers.push(newEntry); 616 } 617 break; 618 default: 619 configStream=String(configStream).split('\n'); 620 var currentEntry=null; 621 for(var ir = 0;ir<configStream.length;ir++){ 622 if((configStream[ir].indexOf("#")==0)||(configStream[ir].length==0)) continue;//コメント/空行スキップ 623 if((configStream[ir].match( /^\t([a-z]+)\:(.+)$/i ))&&(currentEntry)){ 624 currentEntry[RegExp.$1]=RegExp.$2;//プロパティ設定 625 }else{ 626 if (currentEntry) newMembers.push(currentEntry); 627 currentEntry=new nas.Pm.Organization(configStream[ir]); 628 } 629 } 630 newMembers.push(currentEntry); 631 } 632 return this.addMembers(newMembers); 633 } 634 635 nas.Pm.organizations = new nas.Pm.OrganizationCollection(nas.Pm); 636 637 //制作管理用 WorkTitelオブジェクト サーバ上のProductに対応する 638 /* 639 nas.Pm.newWorkTitle(タイトル識別子) 640 オブジェクトメソッドで初期化する 641 戻り値はタイトル情報オブジェクト 642 実運用上はDBとリンクして動作するように調整 643 644 クラスメソッドとしての初期化機能は保留 645 タイトル情報及びタイトルの制作母体となる組織(Organization)へのペアレントリンクを保持する 646 親オブジェクト内のタイトルコレクションのメンバー 647 タイトル内にOpusコレクションを持たせる 648 */ 649 nas.Pm.WorkTitle = function(){ 650 this.id; //DB接続用index - UATサーバの場合はtoken tokenはidへの参照 651 this.projectName; //タイトル - UATサーバの場合はname name はprojectNameへの参照 652 this.fullName; //完全なタイトル文字列(なるべく公式に) 653 this.shortName; //表示用短縮名 654 this.code; //ファイル名使用の略号2~3文字アルファベット限定 655 this.framerate; //Object nas.Framerate フレームレート 656 this.length; //String 納品定尺フレーム数 または nasTC 657 this.inputMedia; //Object nas.AnimationField スタンダードフレーム 658 this.outputMedia; //Object nas.AnimationField 編集スペック 659 //**************************************************************** 660 // this.pmTemplates; //作品内の標準工程テンプレート 不要 661 // this.staff; //作品のスタッフ一覧 スタッフコレクションオブジェクト 不要 662 // this.opuses = new nas.Pm.OpusCollection(this); //Object nas.Pm.OpusCollection タイトル配下の話数コレクション 不要 663 //**************************************************************** 664 //UATサーバのためのプロパティ 665 this.token = this.id; 666 this.name = this.projectName; 667 this.updated_at; 668 this.created_at; 669 this.description;//タイトル識別子として使用? 670 } 671 /* タイトル文字列化 672 引数 673 なし プロジェクト名で返す 674 propName 一致したプロパティを単独で返す 文字列またはオブジェクト 675 "full" 設定ダンプ形式 676 "plain" 設定ダンプ形式 プレーンテキスト ダンプと同形式? 677 "JSON" データ交換用JSONフォーマット 678 */ 679 nas.Pm.WorkTitle.prototype.toString = function(form){ 680 switch (form){ 681 case 'full-dump': 682 case 'full': 683 case 'dump': 684 return JSON.stringify([ 685 this.id, 686 this.fullName, 687 this.shortName, 688 this.code, 689 this.framerate.toString(true), 690 nas.Frm2FCT(this.length,2), 691 this.inputMedia, 692 this.outputMedia 693 ]); 694 break; 695 case 'plain-text': 696 case 'plain': 697 case 'text': 698 var result=[ 699 this.projectName, 700 "\tid:"+this.id, 701 "\tfullName:"+this.fullName, 702 "\tshortName:"+this.shortName, 703 "\tcode:"+this.code, 704 "\tframerate:"+this.framerate.toString(true), 705 "\tformat:"+nas.Frm2FCT(this.length,2), 706 "\tinputMedia:"+this.inputMedia, 707 "\toutputMedia:"+this.outputMedia 708 ]; 709 return result.join('\n'); 710 break; 711 case 'JSON': 712 return JSON.stringify({ 713 "projectName":this.projectName, 714 "id":this.id, 715 "fullName":this.fullName, 716 "shortName":this.shortName, 717 "code":this.code, 718 "framerate":this.framerate.toString(true), 719 "format":nas.Frm2FCT(this.length,2), 720 "inputMedia":this.inputMedia, 721 "outputMedia":this.outputMedia 722 }); 723 break; 724 default: 725 if(this[form]){ 726 return this[form]; 727 }else{ 728 return this.projectName; 729 } 730 } 731 } 732 nas.Pm.WorkTitle.prototype.valueOf=function(){return this.id;} 733 /** 734 ワークタイトルコレクションオブジェクト 735 一般に組織の配下に入るが、システム配下のリセント情報としても利用される 736 */ 737 nas.Pm.WorkTitleCollection = function(myParent){ 738 this.parent = myParent; 739 this.members = {}; 740 this.unique =["projectName","id","fullName","shortName","code"]; 741 } 742 nas.Pm.WorkTitleCollection.prototype.entry = nas.Pm._getMember; 743 nas.Pm.WorkTitleCollection.prototype.addMembers = nas.Pm._addMembers; 744 nas.Pm.WorkTitleCollection.prototype.dump = nas.Pm._dumpList; 745 /* 746 function(keyword){ 747 if(keyword){ return this.entry(keyword)}; 748 return JSON.stringify(this.members); 749 } 750 */ 751 /* 752 タイトル登録メソッド 753 引数 メンバーオブジェクトの配列 754 戻値 エントリに成功したメンバー数 755 756 重複メンバーは登録しない 757 重複の条件は、projectName,id,fullName,shortName,code いずれかのバッティングを検出(_getMember) 758 他のプロパティは比較対象外 759 propListの形式は 760 projectName,[id,fullName,shortName,code,framerate,format,inputMedia,outputMedia] 761 */ 762 /* 763 function(members){ 764 var result = 0; 765 if(!(members instanceof Array)) members = [members]; 766 for (var ix = 0 ; ix < members.length ; ix++ ){ 767 var tempTitle = members[ix]; 768 if( (this.entry(tempTitle.projectName)==null)&& 769 (this.entry(tempTitle.id)==null)&& 770 (this.entry(tempTitle.fullName)==null)&& 771 (this.entry(tempTitle.shortName)==null)&& 772 (this.entry(tempTitle.code)==null) 773 ){ 774 this.members[tempTitle.projectName]=tempTitle; 775 result++; 776 } 777 } 778 return result; 779 } 780 */ 781 /* 782 設定パーサ 783 */ 784 nas.Pm.WorkTitleCollection.prototype.parseConfig = function(configStream){ 785 if(String(configStream).length==0) return false; 786 var newMembers=[]; 787 this.members = {};//clear 788 var form = 'plain-text'; 789 if(configStream.match(/\{[^\}]+\}/)){ 790 form = 'JSON'; 791 } else if(configStream.match(/.+\,\[.+\]/)){ 792 form = 'full-dump'; 793 } 794 switch(form){ 795 case 'JSON': 796 var configData=JSON.parse(configStream); 797 for(prp in configData){ 798 var tempData = configData[prp]; 799 var newTitle = new nas.Pm.WorkTitle(); 800 newTitle.projectName = prp; 801 newTitle.id = tempData.id; 802 newTitle.fullName = tempData.fullName; 803 newTitle.shortName = tempData.shortName; 804 newTitle.code = tempData.code; 805 newTitle.framerate = new nas.Framerate(tempData.framerate); 806 newTitle.length = nas.FCT2Frm(tempData.format); 807 newTitle.inputMedia = tempData.inputMedia; 808 newTitle.outputMedia = tempData.outputMedia; 809 newMembers.push(newTitle); 810 } 811 break; 812 case 'full-dump': 813 configStream=String(configStream).split('\n'); 814 for(var ir = 0;ir<configStream.length;ir++){ 815 if((configStream[ir].indexOf("#")==0)||(configStream[ir].length==0)) continue;//コメント/空行スキップ 816 var tempData = JSON.parse("["+configStream[ir]+"]"); 817 var newTitle = new nas.Pm.WorkTitle(); 818 newTitle.projectName = tempData[0]; 819 newTitle.id = tempData[1][0]; 820 newTitle.fullName = tempData[1][1]; 821 newTitle.shortName = tempData[1][2]; 822 newTitle.code = tempData[1][3]; 823 newTitle.framerate = new nas.Framerate(tempData[1][4]); 824 newTitle.length = nas.FCT2Frm(tempData[1][5]); 825 newTitle.inputMedia = tempData[1][6]; 826 newTitle.outputMedia = tempData[1][7]; 827 newMembers.push(newTitle); 828 } 829 break; 830 default: 831 configStream=String(configStream).split('\n'); 832 var currentTitle=null; 833 for(var ir = 0;ir<configStream.length;ir++){ 834 if((configStream[ir].indexOf("#")==0)||(configStream[ir].length==0)) continue;//コメント/空行スキップ 835 if((configStream[ir].match( /^\t([a-z]+)\:(.+)$/i ))&&(currentTitle)){ 836 var prop = RegExp.$1;var value = RegExp.$2; 837 switch(prop){ 838 case 'format':currentTitle['length']=nas.FCT2Frm(value);//納品フォーマット尺 839 break; 840 case 'framerate':currentTitle['framerate'] = new nas.Framerate(value); 841 break; 842 default:currentTitle[prop] = value; 843 } 844 }else{ 845 if (currentTitle) newMembers.push(currentTitle); 846 currentTitle=new nas.Pm.WorkTitle(); 847 currentTitle.projectName=String(configStream[ir]); 848 } 849 } 850 newMembers.push(currentTitle); 851 } 852 return this.addMembers(newMembers); 853 } 854 /* タイトル登録メソッド 試験用 855 パーサのfull-dumpの部分 856 */ 857 nas.Pm.WorkTitleCollection.prototype.addTitle = function(titleName,propList){ 858 var newTitle = new nas.Pm.WorkTitle(); 859 newTitle.projectName = titleName; 860 newTitle.id = propList[0]; 861 newTitle.fullName = propList[1]; 862 newTitle.shortName = propList[2]; 863 newTitle.code = propList[3]; 864 newTitle.framerate = new nas.Framerate(propList[4]); 865 newTitle.length = nas.FCT2Frm(propList[5]); 866 newTitle.inputMedia = propList[6]; 867 newTitle.outputMedia = propList[7]; 868 869 this.addMembers(newTitle); 870 } 871 872 //テンプレート用コレクション 873 /* 874 UI上で参照されるコレクション 875 使用したタイトルを記録してテンプレートとして利用 876 recentTitles 877 プロダクションオブジェクトの配下のコレクションは別に設定される 878 */ 879 nas.Pm.workTitles = new nas.Pm.WorkTitleCollection(nas.Pm); 880 881 nas.Pm.activeTitle = nas.Pm.workTitles.entry(); 882 //制作管理用 Opusオブジェクト サーバ上のEpisodeに対応する 883 /* 884 *nas.Pm.newOpus(タイトル識別子) 885 * // nas.Pm.newOpus(識別ID) 886 *nas.Pm.newOpus(管理話数名,タイトル) 887 *オブジェクトメソッドで初期化する 888 *戻り値は管理単位情報オブジェクト 889 *実運用上はDBとリンクして動作するように調整 890 * 891 *クラスメソッドとしての初期化機能は保留 892 制作話数(Opus/Episode)が所属するタイトル(Title/Product)へのリンクを持つ 893 894 */ 895 nas.Pm.Opus = function Opus(myID,myOpus,mySubtitle,myTitle){ 896 this.id = myID ;//DB接続用index UATtoken 897 this.name = myOpus ;//表示名 話数/制作番号等 UATname 898 this.subtitle = mySubtitle ;//サブタイトル文字列 UATdescription 899 this.title = myTitle ;//String タイトルキー または Object nas.Pm.WorkTitle 900 this.valueOf = function(){return this.id}; 901 // this.pmunits ;//カット袋コレクション 不要 902 } 903 904 nas.Pm.newOpus = function(identifier,index){ 905 if(! identifier) return false; 906 var arg = Xps.parseIdentifier(identifier); 907 if(arg){ 908 return new nas.Pm.Opus(index,arg.opus,arg.subtitle,arg.title); 909 }else{ 910 return arg; 911 } 912 } 913 /** 914 引数 915 なし 識別名を返す 916 propName 一致したプロパティを単独で返す 文字列またはオブジェクト 917 "full" 設定ダンプ形式 918 "plain" 設定ダンプ形式 プレーンテキスト ダンプと同形式? 919 JSON データ交換用JSONフォーマット 920 toStringメソッド 引数がなければ識別子用の文字列を返す 921 引数を与えると設定ファイル形式のJSONを返す 922 */ 923 nas.Pm.Opus.prototype.toString = function(form){ 924 switch (form){ 925 case 'full': 926 return JSON.stringify([ 927 this.id, 928 this.name, 929 this.subtitle, 930 this.title 931 ]); 932 break; 933 case 'plain': 934 var result=[ 935 this.name, 936 "\tid:"+this.id, 937 "\tname:"+this.name, 938 "\tsubTitle:"+this.subtitle, 939 "\ttitle:"+this.title.toString() 940 ]; 941 return result.join('\n'); 942 break; 943 case 'JSON': 944 return JSON.stringify({ 945 "id":this.id, 946 "name":this.name, 947 "subTitle":this.subtitle, 948 "title":this.title.toString() 949 }); 950 break; 951 default: 952 //デフォルトは識別子を組んで返す 953 return this.title+"#"+this.name+(this.subtitle)?"["+this.subtitle+"]":""; 954 } 955 }; 956 /** 957 各話(エピソード)コレクションオブジェクト OpusCorrection 958 一般にタイトルの配下に入るが、システム配下でキャッシュとしても利用 959 */ 960 nas.Pm.OpusCollection = function(myParent){ 961 this.parent = myParent;//parentTitle 962 this.members = {}; 963 this.unique =["name","id"]; 964 } 965 nas.Pm.OpusCollection.prototype.entry = nas.Pm._getMember; 966 nas.Pm.OpusCollection.prototype.addMembers = nas.Pm._addMembers; 967 nas.Pm.OpusCollection.prototype.dump = nas.Pm._dumpList; 968 /* 969 970 971 nas.Pm.OpusCollection.prototype.addMembers = function(members){ 972 var result = 0; 973 if(!(members instanceof Array)) members = [members]; 974 for (var ix = 0 ; ix < members.length ; ix++ ){ 975 var tempOpus = members[ix]; 976 if( (this.entry(tempOpus.name)==null)&& 977 (this.entry(tempOpus.id)==null) 978 ){ 979 this.members[tempOpus.name]=tempOpus; 980 result++; 981 } 982 } 983 return result; 984 985 } 986 */ 987 /* 988 設定パーサ 989 */ 990 nas.Pm.OpusCollection.prototype.parseConfig = function(configStream){ 991 if(String(configStream).length==0) return false; 992 var newMembers=[]; 993 this.members = {};//clear 994 var form = 'plain-text'; 995 if(configStream.match(/\{[^\}]+\}/)){ 996 form = 'JSON'; 997 } else if(configStream.match(/.+\,\[.+\]/)){ 998 form = 'full-dump'; 999 } 1000 switch(form){ 1001 case 'JSON': 1002 var configData=JSON.parse(configStream); 1003 for(prp in configData){ 1004 var tempData = configData[prp]; 1005 var newOpus = new nas.Pm.Opus(tempData.id,prp,tmpData.subtitle,this.parent.entry(tempData.title)); 1006 newMembers.push(newTitle); 1007 } 1008 break; 1009 case 'full-dump': 1010 configStream=String(configStream).split('\n'); 1011 for(var ir = 0;ir<configStream.length;ir++){ 1012 if((configStream[ir].indexOf("#")==0)||(configStream[ir].length==0)) continue;//コメント/空行スキップ 1013 var tempData = JSON.parse("["+configStream[ir]+"]"); 1014 var newOpus = new nas.Pm.Opus(tempData.id,prp,tmpData.subtitle,this.parent.entry(tempData.title)); 1015 newMembers.push(newTitle); 1016 } 1017 break; 1018 default: 1019 configStream=String(configStream).split('\n'); 1020 var currentOpus=null; 1021 for(var ir = 0;ir<configStream.length;ir++){ 1022 if((configStream[ir].indexOf("#")==0)||(configStream[ir].length==0)) continue;//コメント/空行スキップ 1023 if((configStream[ir].match( /^\t([a-z]+)\:(.+)$/i ))&&(currentOpus)){ 1024 currentOpus[RegExp.$1]=RegExp.$2;//プロパティ設定 1025 }else{ 1026 if (currentOpus) newMembers.push(currentOpus); 1027 currentOpus=new nas.Pm.WorkTitle(); 1028 currentOpus.projectName=String(configStream[ir]); 1029 } 1030 } 1031 newMembers.push(currentOpus); 1032 } 1033 return this.addMembers(newMembers); 1034 } 1035 1036 1037 nas.Pm.opuses= new nas.Pm.OpusCollection(nas.Pm); 1038 1039 //メディアDB 1040 /* 1041 メディアDBは、入出力のメディアスペックを記述するための複合オブジェクト 1042 MAP内部ではワークタイトルに付属する情報として処理する 1043 animationField,framerate,baseResolution等は、オブジェクトで保持 1044 初期化時は、デフォルトの値で作成 再初期化が必用 1045 idは初期化時は未設定 1046 コレクション加入時に設定される 1047 DBとの連結時は連結時に再設定 1048 */ 1049 nas.Pm.ProductionMedia = function(mediaName,animationField,framerate){ 1050 this.id ; 1051 this.animationField = new nas.AnimationField(animationField); 1052 this.mediaName = mediaName;// 1053 this.baseResolution = new nas.UnitResolution();// 1054 this.type ;//mediaType drawing/video 1055 this.baseWidth = this.animationField.baseWidth; 1056 this.frameAspect = this.animationField.frameAspect; 1057 this.framerate = nas.newFramerate(framerate); 1058 this.tcType ;//string tradJA/SMPTE/TC/frame 1059 this.pegForm = this.animationField.peg;//animationField.peg 1060 this.pegOffset = this.animationField.pegOffset; 1061 this.pixelAspect ;//float 1062 this.description ; 1063 } 1064 /* 1065 1066 */ 1067 nas.Pm.ProductionMedia.prototype.toString = function(form){ 1068 switch (form){ 1069 case 'JSON': 1070 return JSON.stringify({ 1071 "mediaName" :this.mediaName, 1072 "id" :this.id, 1073 "animationField":this.animationField.toString(), 1074 "baseResolution":this.baseResolution.toString(), 1075 "mediaType" :this.mediaType, 1076 "tcType" :this.tcType, 1077 "pegForm" :this.pegForm.toString(), 1078 "pixelAspect" :this.pixelAspect, 1079 "description" :this.description 1080 }); 1081 break; 1082 case 'dump': 1083 case 'full': 1084 return JSON.stringify([ 1085 this.id, 1086 this.animationField.toString(), 1087 this.baseResolution.toString(), 1088 this.mediaType, 1089 this.tcType, 1090 this.pegForm.toString(), 1091 this.pixelAspect, 1092 this.description 1093 ]); 1094 break; 1095 case 'plain': 1096 case 'text': 1097 return ([ 1098 this.mediaName, 1099 "\tid:"+this.id, 1100 "\tanimationField:"+this.animationField.toString(), 1101 "\tbaseResolution:"+this.baseResolution.toString(), 1102 "\tmediaType:"+this.mediaType, 1103 "\ttcType:"+this.tcType, 1104 "\tpegForm:"+this.pegForm.toString(), 1105 "\tpixelAspect:"+this.pixelAspect, 1106 "\tdescription:"+this.description 1107 ]).join('\n'); 1108 break; 1109 default: 1110 return this.mediaName; 1111 } 1112 } 1113 // 1114 nas.Pm.MediaCollection= function(myParent){ 1115 this.parent = myParent; 1116 this.members = {}; 1117 // this.unique =["mediaName","id"]; 1118 this.unique =["mediaName"]; 1119 } 1120 nas.Pm.MediaCollection.prototype.entry = nas.Pm._getMember; 1121 nas.Pm.MediaCollection.prototype.addMembers= nas.Pm._addMembers; 1122 nas.Pm.MediaCollection.prototype.dump = nas.Pm._dumpList; 1123 /* 1124 コレクションメンバー登録メソッド 1125 引数 メンバーオブジェクト配列 1126 戻値 エントリに成功したメンバー数 1127 重複メンバーは登録しない 1128 重複の条件は、mediaName,id いずれかのバッティングを検出(_getMember) 1129 他のプロパティは比較対象外 1130 full-dump の形式は 1131 mediaName,[id,animationField,baseResolution,mediaType,tcType,pegForm,pixelAspect,description] 1132 nas.Pm.MediaCollection.prototype.addMembers=function(members){ 1133 var result = 0; 1134 if(!(members instanceof Array)) members = [members]; 1135 for (var ix = 0 ; ix < members.length ; ix++ ){ 1136 var tempOpus = members[ix]; 1137 if( (this.entry(tempOpus.mediaName)==null)&& 1138 (this.entry(tempOpus.id)==null) 1139 ){ 1140 this.members[tempOpus.name]=tempOpus; 1141 result++; 1142 } 1143 } 1144 return result; 1145 } 1146 */ 1147 /* 1148 */ 1149 nas.Pm.MediaCollection.prototype.parseConfig = function(configStream){ 1150 if((! configStream)||(String(configStream).length==0)) return false; 1151 var newMembers=[]; 1152 this.members = {};//clear 1153 var form = 'plain-text'; 1154 if(configStream.match(/\{[^\}]+\}/)){ 1155 form = 'JSON'; 1156 } else if(configStream.match(/.+\,\[.+\]/)){ 1157 form = 'full-dump'; 1158 } 1159 switch(form){ 1160 case 'JSON': 1161 var configData=JSON.parse(configStream); 1162 for(prp in configData){ 1163 var tempData = configData[prp]; 1164 var newMedia = new nas.Pm.ProductionMedia(tempData.mediaName,tempData.animationField,tempData.framerate); 1165 newMedia.id = tempData.id; 1166 // newMedia.mediaName = tempData.mediaName;// 1167 // newMedia.animationField = tempData.new nas.AnimationField(tempData.animationField); 1168 // newMedia.baseWidth = newMedia.animationField.baseWidth; 1169 // newMedia.frameAspect = newMedia.animationField.frameAspect; 1170 // newMedia.pegForm = newMedia.animationField.peg;//animationField.peg 1171 // newMedia.pegOffset = newMedia.animationField.pegOffset; 1172 newMedia.baseResolution = new nas.UnitResolution(tempData.baseResolution);// 1173 newMedia.type = tempData.type;//mediaType drawing/video 1174 // newMedia.framerate = nas.newFramerate(tempData.framerate); 1175 newMedia.tcType = tempData.tcType;//string tradJA/SMPTE/TC/frame 1176 newMedia.pixelAspect = parseFloat(tempData.pixelAspect);//float 1177 newMedia.description = tempData.description; 1178 newMembers.push(newMedia); 1179 } 1180 break; 1181 case 'full-dump': 1182 configStream=String(configStream).split('\n'); 1183 for(var ir = 0;ir<configStream.length;ir++){ 1184 if((configStream[ir].indexOf("#")==0)||(configStream[ir].length==0)) continue;//コメント/空行スキップ 1185 var tempData = JSON.parse("["+configStream[ir]+"]"); 1186 var newMedia = new nas.Pm.ProductionMedia(tempData[0],tempData[1][1]); 1187 newMedia.id = tempData[1][0]; 1188 // newMedia.animationField = tempData[1][1];//new nas.AnimationField(animationField); 1189 // newMedia.mediaName = tempData[0];// mediaName;// 1190 newMedia.baseResolution = tempData[1][2];// new nas.UnitResolution();// 1191 newMedia.type = tempData[1][3];// ;//mediaType drawing/video 1192 // newMedia.baseWidth = ;// newMedia.animationField.baseWidth; 1193 // newMedia.frameAspect = ;// newMedia.animationField.frameAspect; 1194 // newMedia.framerate = ;// nas.newFramerate(framerate); 1195 newMedia.tcType = tempData[1][4];// ;//string tradJA/SMPTE/TC/frame 1196 newMedia.pegForm = tempData[1][5];// newMedia.animationField.peg;//animationField.peg 1197 // newMedia.pegOffset = newMedia.animationField.pegOffset; 1198 newMedia.pixelAspect = parseFloat(tempData[1][6]) ;//float 1199 newMedia.description = tempData[1][7]; 1200 1201 newMembers.push(newMedia); 1202 } 1203 break; 1204 case 'plain-text': 1205 default: 1206 configStream=String(configStream).split('\n'); 1207 var currentMedia=false; 1208 for(var ir = 0;ir<configStream.length;ir++){ 1209 if((configStream[ir].indexOf("#")==0)||(configStream[ir].length==0)) continue;//コメント/空行スキップ 1210 if((configStream[ir].match( /^\t([a-z]+)\:(.+)$/i ))&&(currentMedia)){ 1211 currentMedia[RegExp.$1]=RegExp.$2;//プロパティ設定 1212 }else{ 1213 if (currentMedia) newMembers.push(currentMedia); 1214 currentMedia=new nas.Pm.ProductionMedia(configStream[ir]); 1215 } 1216 } 1217 newMembers.push(currentMedia); 1218 } 1219 return this.addMembers(newMembers); 1220 1221 1222 if( (this.entry(mediaName)==null)&& 1223 (this.entry(propList[0])==null) 1224 ){ 1225 var tempMedia = new nas.Pm.ProductionMedia(mediaName); 1226 var tempField = new nas.AnimationField( 1227 name, 1228 basewidth, 1229 frameaspect, 1230 scale, 1231 pegform, 1232 pegOffset 1233 ); 1234 tempMedia.id = (propList[0]=='')? nas.Zf(Object.keys(this.members).length,4):propList[0]; 1235 tempMedia.animationField = propList[1];//現在は文字列のまま 1236 // 本日は仕様変更が主眼なのでこのまま保留 12/04 1237 tempMedia.baseResolution = propList[2]; 1238 tempMedia.mediaType = propList[3]; 1239 tempMedia.tcType = propList[4];//nas.Framerate Objectする場合は nas.newFramerate(this.tcType) 1240 tempMedia.pegForm = propList[5]; 1241 tempMedia.pixelAspect = propList[6]; 1242 tempMedia.description = propList[7]; 1243 this.members[mediaName]=tempMedia; 1244 } 1245 } 1246 1247 1248 nas.Pm.MediaCollection.prototype.addMedia = function(mediaName,propList){ 1249 1250 this.members[mediaName] = new nas.Pm.ProductionMedia(); 1251 this.members[mediaName].mediaName = mediaName; 1252 this.members[mediaName].id = propList[0]; 1253 this.members[mediaName].animationField = propList[1];//現在は文字列のまま 1254 // 本日は仕様変更が主眼なのでこのまま保留 12/04 1255 this.members[mediaName].baseResolution = propList[2]; 1256 this.members[mediaName].mediaType = propList[3]; 1257 this.members[mediaName].tcType = propList[4];//nas.Framerate Objectする場合は nas.newFramerate(this.tcType) 1258 this.members[mediaName].pegForm = propList[5]; 1259 this.members[mediaName].pixelAspect = propList[6]; 1260 this.members[mediaName].description = propList[7]; 1261 } 1262 /* 1263 nas.Pm.MediaCollection.prototype.addMembers = function (members){ 1264 if(!(members instanceof Array)) members =[members]; 1265 for (var ix=0 ;ix< members.length;ix++) this.addMember(members[ix]) 1266 } 1267 */ 1268 nas.Pm.medias = new nas.Pm.MediaCollection(nas.Pm); 1269 1270 /*制作管理用 Assetオブジェクト 1271 *アセットベースの管理を行う 1272 *このシステム上のアセットは、通常XPSを介して時間/空間的に配置された再利用可能データ群を指す 1273 *XPSを持たない場合もある(時間構造を持たない) 1274 * 1275 *作品内でユニークな識別名を持つ管理用のキーオブジェクトに結合されたデータ群を総称するもの、 1276 *管理用オブジェクトは以下のプロパティを持つ 1277 * name String 識別名称:作品内での一意性を求められる 1278 * hasXPS Boolean アセットがXPS(時間構造)を持つかのフラグ 1279 * code String 省略表記用短縮コード 2〜3バイトを推奨 ユニークであること 1280 * shortName String 画面表示用略称 8文字程度までを推奨 指定のない場合はnameを転用 1281 * description String アセットの説明 ユーザのために必用 1282 * endNode Boolean アセットがラインを終了させうるか否かのフラグ このフラグのあるアセットは、制作ラインの目標となりラインを収束させる 1283 * callStage Array ステージ識別名配列 当該アセットを受けて(入力として)開始することが可能なステージ群 ユーザが選択する 一つのアセットを受けて2つ以上のステージを開始する場合、ライン分岐が発生する 1284 * 1285 */ 1286 nas.Pm.Asset = function(){ 1287 this.assetName ; 1288 this.name ; 1289 this.hasXPS ; 1290 this.code ; 1291 this.shortName ; 1292 this.description ; 1293 this.endNode ; 1294 this.callStage ; 1295 } 1296 1297 nas.Pm.Asset.prototype.toString = function(form){ 1298 switch (form) { 1299 case 'JSON': 1300 return JSON.stringify({ 1301 name:this.name, 1302 hasXPS:this.hasXPS, 1303 code:this.code, 1304 shortName:this.shortName, 1305 descripion:this.description, 1306 endNode:this.endNode, 1307 callStage:this.callStage 1308 }); 1309 case 'full-dump': 1310 case 'full': 1311 case 'dump': 1312 return JSON.stringify([ 1313 this.name, 1314 this.hasXPS, 1315 this.code, 1316 this.shortName, 1317 this.description, 1318 this.endNode, 1319 this.callStage 1320 ]); 1321 case 'plain-text': 1322 case 'plain': 1323 case 'text': 1324 return ([ 1325 this.assetName, 1326 '\tname:'+this.name, 1327 '\thasXPS:'+this.hasXPS, 1328 '\tcode:'+this.code, 1329 '\tshortName:'+this.shortName, 1330 '\tdescription:'+this.description, 1331 '\tendNode:'+this.endNode, 1332 '\tcallStage:'+this.callStage 1333 ]).join('\n'); 1334 default: 1335 return this.name; 1336 // return nas.Pm.searchProp(this.name,nas.pmdb.assets); 1337 } 1338 } 1339 /** 1340 アセットコレクション 1341 */ 1342 nas.Pm.AssetCollection = function(myParent){ 1343 this.parent = myParent; 1344 this.members = {}; 1345 this.unique = ["assetName","name","code","shortName"]; 1346 } 1347 nas.Pm.AssetCollection.prototype.entry = nas.Pm._getMember; 1348 nas.Pm.AssetCollection.prototype.addMembers = nas.Pm._addMembers; 1349 nas.Pm.AssetCollection.prototype.dump = nas.Pm._dumpList; 1350 1351 //アセット登録メソッド 1352 nas.Pm.AssetCollection.prototype.addAsset = function(assetName,propList){ 1353 this.members[assetName] = new nas.Pm.Asset(); 1354 this.members[assetName].assetName = assetName; 1355 this.members[assetName].name = propList[0]; 1356 this.members[assetName].hasXPS = (propList[1])?true:false; 1357 this.members[assetName].code = propList[2]; 1358 this.members[assetName].shortName = propList[3]; 1359 this.members[assetName].description = propList[4]; 1360 this.members[assetName].endNode = (propList[5])?true:false; 1361 this.members[assetName].callStage = propList[6]; 1362 } 1363 /* 1364 return [ this[assetName].name, 1365 this[assetName].hasXPS, 1366 this[assetName].code, 1367 this[assetName].shortName, 1368 this[assetName].description, 1369 this[assetName].endNode, 1370 "["+(this[assetName].callStage).join()+"]" 1371 ]; 1372 */ 1373 /*データパーサ 1374 1375 */ 1376 nas.Pm.AssetCollection.prototype.parseConfig =function(configStream){ 1377 if(String(configStream).length==0) return false; 1378 var newMembers=[]; 1379 this.members = {};//clear 1380 var form = 'plain-text'; 1381 if(configStream.match(/\{[^\}]+\}/)){ 1382 form = 'JSON'; 1383 } else if(configStream.match(/.+\,\[.+\]/)){ 1384 form = 'full-dump'; 1385 } 1386 switch(form){ 1387 case 'JSON': 1388 var configData=JSON.parse(configStream); 1389 for(prp in configData){ 1390 var tempData = configData[prp]; 1391 var newEntry = new nas.Pm.Asset(); 1392 newEntry.assetName = prp; 1393 newEntry.name = tempData.name; 1394 newEntry.hasXPS = tempData.hasXPS; 1395 newEntry.code = tempData.code; 1396 newEntry.shortName = tempData.shortName; 1397 newEntry.description = tempData.description; 1398 newEntry.endNode = tempData.endNode; 1399 newEntry.callStage = tempData.callStage; 1400 newMembers.push(newEntry); 1401 } 1402 break; 1403 case 'full-dump': 1404 case 'full': 1405 case 'dump': 1406 configStream=String(configStream).split('\n'); 1407 for(var ir = 0;ir<configStream.length;ir++){ 1408 if((configStream[ir].indexOf("#")==0)||(configStream[ir].length==0)) continue;//コメント/空行スキップ 1409 var tempData = JSON.parse("["+configStream[ir]+"]"); 1410 var newEntry = new nas.Pm.Asset(); 1411 newEntry.assetName = tempData[0]; 1412 newEntry.name = tempData[1][0]; 1413 newEntry.hasXPS = tempData[1][1]; 1414 newEntry.code = tempData[1][2]; 1415 newEntry.shortName = tempData[1][3]; 1416 newEntry.description = tempData[1][4]; 1417 newEntry.endNode = tempData[1][5]; 1418 newEntry.callStage = tempData[1][6]; 1419 newMembers.push(newEntry); 1420 } 1421 break; 1422 case 'plain-text': 1423 case 'plain': 1424 case 'text': 1425 default: 1426 configStream=String(configStream).split('\n'); 1427 var currentEntry=false; 1428 for(var ir = 0;ir<configStream.length;ir++){ 1429 if((configStream[ir].indexOf("#")==0)||(configStream[ir].length==0)) continue;//コメント/空行スキップ 1430 if((configStream[ir].match( /^\t([a-z]+)\:(.+)$/i ))&&(currentEntry)){ 1431 currentEntry[RegExp.$1]=(RegExp.$1=='callStage')?(RegExp.$2).split(','):RegExp.$2;//プロパティ設定 1432 }else{ 1433 if (currentEntry) newMembers.push(currentEntry); 1434 currentEntry=new nas.Pm.Asset(); 1435 currentEntry.assetName=String(configStream[ir]); 1436 } 1437 } 1438 newMembers.push(currentEntry); 1439 } 1440 return this.addMembers(newMembers) 1441 } 1442 1443 nas.Pm.assets = new nas.Pm.AssetCollection(nas.Pm); 1444 1445 /*制作管理用 PmTemplateオブジェクト 1446 *プロパティ すべて配列 1447 * lineNames ライン名称コレクション 1448 * stageNames ステージ名称コレクション 1449 * jobName ジョブ名称コレクション 1450 * 1451 * .getLines() 設定されているラインのリストを返す 1452 * .getStageName(myLine) ラインごとのステージ候補セットを設定順で戻す 1453 * .getJobNames(myStage) 指定ステージのジョブ候補セットを設定順で戻す 1454 * 1455 * タイトルごとに設定される工程テンプレート 1456 * ユーザが管理情報を入力する際に提示される参考データとして提示される 1457 * 記録データ的には、コレクション外の入力はOK 1458 * コレクション外の入力は入力時にコレクションに追加されて必要に従ってマスターDBへ送信される 1459 * アクセスメソッドを介して情報セットを引き出す 1460 * 1461 lineNames[line]=[stage1,stage2,stage3]; 1462 stageNames[stage]=[line1,line2]; 1463 jobNames[job]=[stage1,stage2] 1464 line null,ALL,trunk,backgroundArt, 1465 */ 1466 //ラインテンプレートコレクション配列 1467 nas.Pm.PmTemplateCollection = function(myParent){ 1468 this.parent = myParent; 1469 this.members = []; 1470 this.unique =["line"]; 1471 }; 1472 /*テンプレートコレクションメンバー追加メソッド 1473 配列型のみを受け取る 1474 重複チェックはなし 上書き 1475 */ 1476 nas.Pm.PmTemplateCollection.prototype.addTemplate = function(templates){ 1477 if(! templates[0] instanceof Array){templates = [templates];} 1478 for (var eid = 0;eid<templates.length ; eid ++){ 1479 //引数: トレーラーオブジェクトの参照,ライン識別名,ステージコレクションの内容配列 1480 this.members[eid] = new nas.Pm.LineTemplate(this,templates[eid][0],templates[eid][1]); 1481 } 1482 }; 1483 nas.Pm.PmTemplateCollection.prototype.entry = nas.Pm._getMember; 1484 nas.Pm.PmTemplateCollection.prototype.addMembers = nas.Pm._addMembers; 1485 /* 1486 設定データストリームパーサ 1487 */ 1488 nas.Pm.PmTemplateCollection.prototype.parseConfig = function(dataStream,form){ 1489 if(! dataStream) return false; 1490 var myMembers =[]; 1491 // 形式が指定されない場合は、第一有効レコードで判定 1492 if(! form ){ 1493 if (dataStream.match(/\[\s*(\{[^\}]+\}\s*,\s*)+(\{[^\}]+\})?\s*\]/)) form='JSON';//配列JSON 1494 else if (dataStream.match(/(\n|^)\[.+\]($|\n)/)) form='full-dump'; 1495 else form='plain-text'; 1496 } 1497 switch(form){ 1498 case 'JSON': 1499 var tempObject=JSON.parse(dataStream); 1500 for (var rix=0;rix<tempObject.length;rix++){ 1501 var currentMember=new nas.Pm.LineTemplate( 1502 this, 1503 tempObject[rix].line, 1504 tempObject[rix].stages 1505 ); 1506 myMembers.push(currentMember); 1507 } 1508 break; 1509 case 'full-dump': 1510 dataStream = String(dataStream).split("\n"); 1511 for (var rix=0;rix<dataStream.length;rix++){ 1512 if((dataStream[rix].indexOf('#')==0)||(dataStream[rix].length == 0)) continue; 1513 var currentRecord=JSON.parse(dataStream[rix]); 1514 var currentMember=new nas.Pm.LineTemplate( 1515 this, 1516 currentRecord[0], 1517 currentRecord[1] 1518 ); 1519 if (currentMember) myMembers.push(currentMember); 1520 } 1521 break; 1522 case 'plain-text': 1523 default: 1524 dataStream = String(dataStream).split("\n"); 1525 var currentMember=false; 1526 for (var rix=0;rix<dataStream.length;rix++) { 1527 if((dataStream[rix].indexOf('#')==0)||(dataStream[rix].length == 0)) continue; 1528 var currentField=dataStream[rix]; 1529 /*plainフォーマット 1530 entryName 1531 prop:value 1532 prop:value 1533 */ 1534 if((currentMember)&&(currentField.match( /^\t([a-z]+)\:(.+)$/i ))){ 1535 if(RegExp.$1=='stages'){ 1536 var stages=(RegExp.$2).split(','); 1537 for (var sid=0;sid<stages.length;sid++){ 1538 currentMember.stages.addStage(stages[sid],currentMember.parent.parent.stages.entry(stages[sid])); 1539 } 1540 }else{ 1541 currentMember[RegExp.$1]=RegExp.$2;//追加プロパティ用 1542 } 1543 } else if(currentField.match( /^.+$/i )) { 1544 if(currentMember) myMembers.push(currentMember); 1545 currentMember = new nas.Pm.LineTemplate(this,currentField,[]); 1546 } 1547 } 1548 myMembers.push(currentMember); 1549 } 1550 return this.addMembers(myMembers); 1551 } 1552 nas.Pm.PmTemplateCollection.prototype.dump = nas.Pm._dumpList; 1553 /** 1554 ラインテンプレート ステージデータコレクションを持つ 1555 引数 1556 myParent 1557 lineName ライン識別名称 1558 [myStarges] ラインの標準的なステージ並びを配列で与える 空配列で初期化可能 1559 1560 */ 1561 nas.Pm.LineTemplate = function(myParent,lineName,myStages){ 1562 if (!(myStages instanceof Array)) myStages = [myStages]; 1563 this.parent = myParent;//親参照は不要? 1564 this.line = this.parent.parent.lines.getLine(lineName); 1565 this.stages = new nas.Pm.StageCollection(this); 1566 for (var ix=0;ix< myStages.length;ix++){ 1567 var stageKey= nas.Pm.searchProp(myStages[ix],this.parent.parent.stages) 1568 this.stages.addStage(stageKey,this.parent.parent.stages.entry(stageKey)); 1569 } 1570 }; 1571 /* 1572 toString(true) でテキスト設定形式で書き出す 1573 1574 */ 1575 nas.Pm.LineTemplate.prototype.toString = function(form){ 1576 switch(form){ 1577 case 'JSON': 1578 return JSON.stringify({ 1579 line: this.line.toString(), 1580 stages:(this.stages.dump()).split(',') 1581 }); 1582 case 'full-dump': 1583 case 'full': 1584 case 'dump': 1585 return JSON.stringify([ 1586 this.line.toString(), 1587 (this.stages.dump()).split(',') 1588 ]); 1589 break; 1590 case 'plain-text': 1591 case 'plain': 1592 case 'text': 1593 return ([ 1594 this.line.toString(), 1595 '\tstages:'+this.stages.dump() 1596 ]).join('\n'); 1597 break; 1598 default: 1599 return this.line.toString(); 1600 } 1601 }; 1602 1603 nas.Pm.pmTemplates = new nas.Pm.PmTemplateCollection(nas.Pm); 1604 1605 /*制作管理用 Jobオブジェクト 1606 *プロパティ 1607 * name String: ジョブ名 1608 * // line Object:Line 所属ライン<<不要 stage にライン情報が含まれるので不用 1609 * stage Object:Stage 所属ステージ 1610 * type Number:typeID 0:init/1:primary/2~:check/ 当該Jobのタイプ 1611 * id Number:Index ステージ内でのユニークID 自己アクセスのための配列インデックスを内部保持 1612 * jobId生成規則 1613 * 管理単位所属ステージ内部でユニークな整数ID 重複不可 飛び番等は許容される 1614 * DB連結時はDBへの照合プロパティになるので初期化時には引数として外部から与えるのが基本 1615 * 引数が与えられない(=DB連結が無い)場合は、その場での自動生成を行う 1616 * その際のルールは、同PmStage内部での出現順連番 0はStartupJobとして予約 1617 * currentStatus String:ステータス startup|active<>hold|fixed 1618 * createUser String:UID 1619 * createDate String:DATE 1620 * updateUser String:UID 1621 * updateDate String:DATE 1622 * slipNumber String:伝票番号 1623 *new Job(jobName?) 1624 */ 1625 nas.Pm.ProductionJob = function ProductionJob(myName,myStage,myIndex,mySlipNumber){ 1626 this.name = myName;//* 1627 this.stage = myStage; 1628 // if(! myStage){alert("stage Argument is :"+myStage)} 1629 this.type ; 1630 this.id = (typeof myIndex == "undefined")? null:myIndex;//* 1631 this.currentStatus ;// 1632 this.createUser ;// 1633 this.createDate = new Date();// 1634 this.updateUser ;// 1635 this.updateDate ;// 1636 this.slipNumber ;//* 1637 }; 1638 nas.Pm.ProductionJob.prototype.getPath = function(){return [this.name,this.stage.getPath()].join(".");} 1639 1640 nas.Pm.ProductionJob.prototype.toString = function(){ 1641 var myResult = ""; 1642 // myResult += "##["+this.stage.name+"][["+this.name+"]"+"id:"+this.id+"]\n"; 1643 myResult += "##[["+this.name+"]"+"id:"+this.id+"]\n"; 1644 myResult += "##created="+this.createDate+"/"+this.createUser+";\n"; 1645 myResult += "##updated="+this.createDate+"/"+this.createUser+";\n"; 1646 1647 if(this.manager) myResult += "##manager="+this.manager+";\n"; 1648 if(this.worker) myResult += "##worker="+this.worker+";\n"; 1649 if(this.slipNumber) myResult += "##slipNumber="+this.slipNumber+";\n"; 1650 1651 var myGroups = new Array(); 1652 var myMapElements = this.stage.line.parent.elementStore; 1653 //エレメント総当りで ジョブに対応するグループを抽出 1654 for (var eID=0 ; eID < myMapElements.length ; eID++){ 1655 if((myMapElements[eID] instanceof nas.xMapGroup)&&(myMapElements[eID].link===this.stage)){ 1656 myGroups.push(myMapElements[eID].link); 1657 } 1658 } 1659 //登録グループごとにエレメント総当りで ジョブ内のグループに対応するエレメントを抽出して出力に加算 1660 for (var gID=0;gID<myGroups.length;gID++){ 1661 myResult+="["+myGroup[gID].name+"\t"+myGroup[gID].type+"]\n"; 1662 for (var eID=0;eID<myMapElements.length;eID++){ 1663 if((myMapElements[eID] instanceof nas.xMapElement)&&(myMapElements[eID].link===this)){ 1664 myResult+=myMapElements[eID].toString();// 1665 } 1666 } 1667 // myResult+="["+myGroup[gID].name+"]/\n";//グループ終了子は省略可 1668 } 1669 // myResult+="##[["+this.name+"]]/\n";//終了子をここでは出力しない 呼び出し側で処置 1670 return myResult; 1671 }; 1672 /** 1673 JOB名称ストア 1674 クラス内でDBとして働くコレクション 1675 このオブジェクト(配列)がDBと通信を行う 1676 引数: jobName,targetStage,jobType 1677 ジョブ名,所属ステージ名,ジョブタイプ 1678 配列要素は引数の配列である必要あり。 1679 実際のジョブは定義されるものではなく、名称をその場で決めて開始することが可能 1680 これらの設定は、 1681 */ 1682 nas.Pm.JobTemplate = function(jobName,targetStage,jobType){ 1683 this.jobName = jobName ; 1684 this.targetStage = targetStage; 1685 this.jobType = jobType ; 1686 }; 1687 nas.Pm.JobTemplate.prototype.toString = function(form){ 1688 switch(form){ 1689 case 'JSON': 1690 return JSON.stringify({ 1691 jobName:this.jobName, 1692 targetStage:this.targetStage, 1693 jobType:this.jobType 1694 }); 1695 break; 1696 case 'full-dump': 1697 case 'full': 1698 case 'dump': 1699 return JSON.stringify([this.jobName,this.targetStage,this.jobType]); 1700 break; 1701 case 'plain-text': 1702 case 'plain': 1703 case 'text': 1704 return ([ 1705 this.jobName, 1706 "\ttargetStage:"+this.targetStage, 1707 "\tjobType:"+this.jobType 1708 ]).join('\n'); 1709 break; 1710 default: 1711 return this.jobName; 1712 } 1713 }; 1714 nas.Pm.JobTemplateCollection = function(myParent){ 1715 this.parent = myParent ; 1716 this.members = []; 1717 } 1718 /** 1719 ジョブテンプレートコレクション 1720 一括登録メソッド 1721 1722 */ 1723 nas.Pm.JobTemplateCollection.prototype.addNames = function(names){ 1724 if(! names[0] instanceof Array){names = [names];} 1725 for (var eid = 0;eid<names.length ; eid ++){ 1726 this.members[eid] = new nas.Pm.JobTemplate(names[eid][0],names[eid][1],names[eid][2]); 1727 } 1728 } 1729 nas.Pm.JobTemplateCollection.prototype.addMembers = nas.Pm._addMembers; 1730 /** 1731 テンプレート取得 1732 引数に従ってJobテンプレートから必要な集合を抽出して返す 1733 引数: 1734 ステージキーワード layout LO レイアウト 等 1735 ジョブタイプ init/primary/check/* ジョブタイプ'*'は primary+check (! init) 1736 */ 1737 nas.Pm.JobTemplateCollection.prototype.getTemplate = function(stage,type){ 1738 if((! stage)||(! type)){return []}; 1739 var result=[]; 1740 for (var eid = 0;eid<this.members.length ; eid ++){ 1741 if((this.members[eid].jobType == type)||(this.members[eid].jobType == "*")||(type == "*")&&(this.members[eid].jobType != "init")){ 1742 if((this.parent.stages.getStage(this.members[eid].targetStage) === this.parent.stages.getStage(stage))||(this.members[eid].targetStage == "*")){ 1743 var jobName = this.members[eid].jobName; 1744 var parentStage = this.parent.stages.getStage(stage); 1745 if(( jobName.indexOf("*") >= 0)&&(parentStage)){ 1746 var myString = jobName.replace(/\*/,parentStage.name); 1747 }else{ 1748 var myString = jobName; 1749 } 1750 result.push(myString); 1751 } 1752 } 1753 } 1754 return result; 1755 } 1756 nas.Pm.JobTemplateCollection.prototype.dump = nas.Pm._dumpList; 1757 /* 設定パーサ 1758 nas.Pm.JobTemplate (jobName,targetStage,jobType) 1759 */ 1760 nas.Pm.JobTemplateCollection.prototype.parseConfig = function(dataStream,form){ 1761 var myMembers =[]; 1762 // 形式が指定されない場合は、第一有効レコードで判定 1763 if(! form ){ 1764 if (dataStream.match(/\[\s*(\{[^\}]+\}\s*,\s*)+(\{[^\}]+\})?\s*\]/)) form='JSON';//配列JSON 1765 else if (dataStream.match(/(\n|^)\[.+\]($|\n)/)) form='full-dump'; 1766 else form='plain-text'; 1767 } 1768 switch(form){ 1769 case 'JSON': 1770 var tempObject=JSON.parse(dataStream); 1771 for (var rix=0;rix<tempObject.length;rix++){ 1772 var currentMember=new nas.Pm.JobTemplate( 1773 tempObject[rix].jobName, 1774 tempObject[rix].targetStage, 1775 tempObject[rix].jobType 1776 ); 1777 myMembers.push(currentMember); 1778 } 1779 break; 1780 case 'full-dump': 1781 dataStream = String(dataStream).split("\n"); 1782 for (var rix=0;rix<dataStream.length;rix++){ 1783 if((dataStream[rix].indexOf('#')==0)||(dataStream[rix].length == 0)) continue; 1784 var currentRecord=JSON.parse(dataStream[rix]); 1785 var currentMember=new nas.Pm.JobTemplate( 1786 currentRecord[0], 1787 currentRecord[1], 1788 currentRecord[2] 1789 ); 1790 if (currentMember) myMembers.push(currentMember); 1791 } 1792 break; 1793 case 'plain-text': 1794 default: 1795 dataStream = String(dataStream).split("\n"); 1796 var currentMember=false; 1797 for (var rix=0;rix<dataStream.length;rix++) { 1798 if((dataStream[rix].indexOf('#')==0)||(dataStream[rix].length == 0)) continue; 1799 var currentField=dataStream[rix]; 1800 /*plainフォーマット 1801 entryName 1802 prop:value 1803 prop:value 1804 */ 1805 if((currentMember)&&(currentField.match( /^\t([a-z]+)\:(.+)$/i ))){ 1806 currentMember[RegExp.$1]=RegExp.$2; 1807 } else if(currentField.match( /^.+$/i )) { 1808 if(currentMember) myMembers.push(currentMember); 1809 currentMember = new nas.Pm.JobTemplate(currentField); 1810 } 1811 } 1812 myMembers.push(currentMember); 1813 } 1814 return this.addMembers(myMembers); 1815 } 1816 /* 1817 function(form){ 1818 if(form == 'JSON'){ 1819 return JSON.stringify(this.members);//JSON.stringify不能なオブジェクトがあるので注意 1820 }else if(form == 'dump'){ 1821 var result="["; 1822 for (var ix =0 ; ix<this.members.length;ix++){ 1823 result += this.members[ix].toString('dump'); 1824 result += ((ix+1)<this.members.length)? ",\n":"]\n"; 1825 } 1826 return result; 1827 }else{ 1828 var result="["; 1829 for (var ix =0 ; ix<this.members.length;ix++){ 1830 result += this.members[ix].toString(true); 1831 result += ((ix+1)<this.members.length)? ",\n":"]\n"; 1832 } 1833 return result; 1834 } 1835 } 1836 */ 1837 nas.Pm.jobNames = new nas.Pm.JobTemplateCollection(nas.Pm); 1838 1839 1840 1841 /*制作管理用 Stageオブジェクト 1842 * 1843 * name String 識別名称:作品内での一意性を求められる 1844 * line Object ステージが所属するラインへの参照 1845 * code String 省略表記用短縮コード 2〜3バイトを推奨 ユニークであること 1846 * shortName String 画面表示用略称 8文字程度までを推奨 指定のない場合はnameを転用 1847 * description String ステージの説明 ユーザのために必用 1848 * output Asset ステージの出力アセット 1849 * staffs Object スタッフリスト(リスト) 1850 * ステージは必ずステージコレクションを介してラインに所属するので、親ラインの参照はコレクション側のline属性で保持する。 1851 * ステージ内では、コレクションを parent プロパティで示す 従って親のラインを参照するパスは this.parent.line 1852 */ 1853 nas.Pm.ProductionStage=function(myName,myParent){ 1854 this.parent=myParent; 1855 this.name=myName; 1856 this.code; 1857 this.shortName; 1858 this.description; 1859 this.output; 1860 this.stageName; 1861 } 1862 //nas.Pm.ProductionStage.prototype.getPath=function(){return [this.name,this.parent.line.getPath()].join(".")} 1863 nas.Pm.ProductionStage.prototype.getPath=function(){return [this.name,this.line.getPath()].join(".")} 1864 nas.Pm.newStage=function(myStage,myLine){ 1865 var newStage= nas.Pm.stages.getStage(myStage);//参照をとっているが、これは複製? 1866 if(newStage){ 1867 newStage.line=myLine; 1868 return newStage; 1869 }else{ 1870 //ステージは未登録なので、新規ステージ編集? 1871 return new nas.Pm.ProductionStage(myStage,myLine); 1872 } 1873 } 1874 nas.Pm.ProductionStage.prototype.toString=function(form){ 1875 1876 switch(form){ 1877 case 'JSON': 1878 return JSON.stringify({ 1879 name:this.name, 1880 code:this.code, 1881 shortName:this.shortName, 1882 description:this.description, 1883 output:this.output, 1884 stageName:this.stageName 1885 }); 1886 break; 1887 case 'full-dump': 1888 case 'full': 1889 case 'dump': 1890 return JSON.stringify([ 1891 this.name, 1892 this.code, 1893 this.shortName, 1894 this.description, 1895 this.output 1896 ]); 1897 break; 1898 case 'plain-text': 1899 case 'plain': 1900 case 'text': 1901 return ([ 1902 this.stageName, 1903 "\tname:"+this.name, 1904 "\tcode:"+this.code, 1905 "\tshortName:"+this.shortName, 1906 "\tdescription:"+this.description, 1907 "\toutput:"+this.output 1908 ]).join('\n'); 1909 1910 default: 1911 return this.name; 1912 } 1913 }; 1914 /* ステージコレクション 1915 * 1916 *クラス内でDBとして働くオブジェクト 1917 *このオブジェクトがDBと通信する 1918 ステージにテンプレートとしてスタッフコレクションを持たせる拡張を行う 1919 */ 1920 nas.Pm.StageCollection = function(myParent){ 1921 this.parent = myParent; 1922 this.members = {}; 1923 this.unique =["stageName","name","code","shortName"]; 1924 } 1925 1926 nas.Pm.StageCollection.prototype.dump = nas.Pm._dumpList; 1927 nas.Pm.StageCollection.prototype.getStage = nas.Pm._getMember; 1928 nas.Pm.StageCollection.prototype.entry = nas.Pm._getMember; 1929 nas.Pm.StageCollection.prototype.addMembers = nas.Pm._addMembers 1930 //ステージコレクション追加メソッド 1931 /* 1932 引数: 1933 stageName 1934 myStage ステージオブジェクト または プロパティリスト配列 1935 */ 1936 nas.Pm.StageCollection.prototype.addStage=function(stageName,myStage){ 1937 if(myStage instanceof nas.Pm.ProductionStage){ 1938 this.members[stageName]= myStage; 1939 }else if(myStage instanceof Array){ 1940 this.members[stageName] = new nas.Pm.ProductionStage(myStage[0],null); 1941 // this.members[stageName].name=myStage[0]; 1942 this.members[stageName].code = myStage[1]; 1943 this.members[stageName].shortName = myStage[2]; 1944 this.members[stageName].description = myStage[3]; 1945 this.members[stageName].output = myStage[4]; 1946 this.members[stageName].stageName = stageName; 1947 } 1948 } 1949 1950 /* 1951 設定パーサ 1952 */ 1953 nas.Pm.StageCollection.prototype.parseConfig = function(configStream){ 1954 if(String(configStream).length==0) return false; 1955 var newMembers=[]; 1956 this.members = {};//clear 1957 var form = 'plain-text'; 1958 if(configStream.match(/\{[^\}]+\}/)) form = 'JSON'; 1959 else if(configStream.match(/.+\,\[.+\]/)) form = 'full-dump'; 1960 switch(form){ 1961 case 'JSON': 1962 var configData=JSON.parse(configStream); 1963 for(prp in configData){ 1964 var tempData = configData[prp]; 1965 var newStage = new nas.Pm.ProductionStage(prp,this); 1966 newStage.stageName = prp; 1967 newStage.name = tempData.name; 1968 newStage.code = tempData.code; 1969 newStage.shortName = tempData.shortName; 1970 newStage.description = tempData.description; 1971 newStage.output = tempData.output; 1972 newMembers.push(newStage); 1973 } 1974 break; 1975 case 'full-dump': 1976 configStream=String(configStream).split('\n'); 1977 for(var ir = 0;ir<configStream.length;ir++){ 1978 if((configStream[ir].indexOf("#")==0)||(configStream[ir].length==0)) continue;//コメント/空行スキップ 1979 var tempData = JSON.parse("["+configStream[ir]+"]"); 1980 var newStage = new nas.Pm.ProductionStage(tempData[1][0],this); 1981 newStage.stageName = tempData[0]; 1982 newStage.name = tempData[1][0]; 1983 newStage.code = tempData[1][1]; 1984 newStage.shortName = tempData[1][2]; 1985 newStage.description = tempData[1][3]; 1986 newStage.output = tempData[1][4]; 1987 newMembers.push(newStage); 1988 } 1989 break; 1990 default: 1991 configStream=String(configStream).split('\n'); 1992 var currentStage=false; 1993 for(var ir = 0;ir<configStream.length;ir++){ 1994 if((configStream[ir].indexOf("#")==0)||(configStream[ir].length==0)) continue;//コメント/空行スキップ 1995 if((configStream[ir].match( /^\t([a-z]+)\:(.+)$/i ))&&(currentStage)){ 1996 currentStage[RegExp.$1]=RegExp.$2;//プロパティ設定 1997 }else{ 1998 if (currentStage) newMembers.push(currentStage); 1999 currentStage=new nas.Pm.ProductionStage(configStream[ir],this); 2000 currentStage.stageName=String(configStream[ir]); 2001 } 2002 } 2003 newMembers.push(currentStage); 2004 } 2005 return this.addMembers(newMembers); 2006 } 2007 /** 2008 次のステージの候補を抽出する関数 2009 引数: 2010 ライン識別子 2011 ステージ識別子 2012 基本構造 2013 引数のステージの出力アセットから、そのアセットが呼び出し可能なステージを得て展開する 2014 2015 */ 2016 nas.Pm.StageCollection.prototype.getTemplate = function(stageName){ 2017 var result=[]; 2018 var myStageAsset =this.parent.assets.entry(this.getStage(stageName).output); 2019 var newStageList=(myStageAsset)? myStageAsset.callStage:[]; 2020 for (var idx = 0 ;idx < newStageList.length ; idx ++){ 2021 var myStage = this.getStage(newStageList[idx]);//null可能性あり 2022 if(myStage) result.push(myStage.name); 2023 } 2024 return result; 2025 } 2026 /** 2027 ステージコレクション内からスタートアップ候補(開始デフォルト)のステージを取得するメソッド 2028 第一ステージとなるアイテムはステージコレクションに最初に置かれたステージ 2029 for( itm in this.menbers) で最初に出てくるステージのこと 2030 ↑これはgetStage=_getMember に統合 したので不要 2031 2032 nas.Pm.StageCollection.prototype.getStartup =function(){ 2033 for(itm in this.members){return itm;break;} 2034 } 2035 */ 2036 2037 nas.Pm.stages = new nas.Pm.StageCollection(nas.Pm); 2038 /* 2039 定義テーブルからテンプレートを取得するための機能 2040 名前と検索先(指定がない場合はcallerから判定)を与えて、その定義テーブル内のオブジェクト引数を返す 2041 あたるべきプロパティはname,code,shortName,fullName オブジェクトによってはいくつかのプロパティを持たないものものある 2042 2043 */ 2044 2045 /*制作管理用 ProductionLineオブジェクト 2046 2047 name String 識別名称:作品内での一意性を求められる 2048 shortName String 画面表示用略称 8文字程度までを推奨 指定のない場合はnameを転用 2049 outputAsset Asset ラインの出力アセット 2050 initAsset Asset ラインの入力アセット 2051 code String 省略表記用短縮コード 2〜3バイトを推奨 ユニークであること 2052 description String ラインの説明 ユーザのために必用 2053 2054 */ 2055 2056 nas.Pm.ProductionLine=function(lineName){ 2057 this.lineName; 2058 this.name; 2059 this.shortName; 2060 this.outputAsset; 2061 this.initAsset; 2062 this.code; 2063 this.description; 2064 } 2065 2066 nas.Pm.ProductionLine.prototype.getPath = function(){return this.name;} 2067 2068 nas.Pm.ProductionLine.prototype.toString = function(form){ 2069 switch (form){ 2070 case 'JSON': 2071 return JSON.stringify({ 2072 name:this.name, 2073 shortName:this.shortName, 2074 outputAsset:((this.outputAsset)?this.outputAsset.toString():this.outputAsset), 2075 initAsset:((this.initAsset)?this.initAsset.toString():this.initAsset), 2076 code:this.code, 2077 description:this.description 2078 }); 2079 break; 2080 case 'full-dump': 2081 case 'full': 2082 case 'dump': 2083 return JSON.stringify([ 2084 this.name, 2085 this.shortName, 2086 (this.outputAsset)?this.outputAsset.toString():this.outputAsset, 2087 (this.initAsset)?this.initAsset.toString():this.initAsset, 2088 this.code, 2089 this.description 2090 ]); 2091 break; 2092 case 'plain-text': 2093 case 'plain': 2094 case 'text': 2095 return ([ 2096 this.lineName, 2097 '\tname:'+this.name, 2098 '\tshortName:'+this.shortName, 2099 '\toutoputAsset:'+((this.outputAsset)?this.outputAsset.toString():null), 2100 '\tinitAsset:'+((this.initAsset)?this.initAsset.toString():null), 2101 '\tcode:'+this.code, 2102 '\tdescription:'+this.description 2103 ]).join('\n'); 2104 break; 2105 default: 2106 return this.name 2107 } 2108 }; 2109 /* ラインストア 2110 2111 クラス内でDBとして働くコレクションオブジェクト 2112 このオブジェクトがタイトルの下に入り上位オブジェクトがDBと通信する 2113 */ 2114 nas.Pm.LineCollection = function(myParent){ 2115 this.parent = myParent; 2116 this.members = {}; 2117 this.unique =["lineName","name","code","shortName"]; 2118 } 2119 2120 nas.Pm.LineCollection.prototype.dump = nas.Pm._dumpList; 2121 //function(){ return JSON.stringify(this.members);} 2122 nas.Pm.LineCollection.prototype.addMembers = nas.Pm._addMembers; 2123 2124 /** 2125 ラインテンプレートの中から指定された名前と一致するオブジェクトを戻す 2126 lineNameと一致していればそのまま、一致するものがない場合はname/shortName/codeを検索してその順で最初に一致したものを戻す 2127 */ 2128 nas.Pm.LineCollection.prototype.getLine = nas.Pm._getMember; 2129 nas.Pm.LineCollection.prototype.entry = nas.Pm._getMember; 2130 2131 /*設定パーサ 2132 2133 */ 2134 2135 nas.Pm.LineCollection.prototype.parseConfig =function(configStream){ 2136 if(String(configStream).length==0) return false; 2137 var newMembers=[]; 2138 this.members = {};//clear 2139 var form = 'plain-text'; 2140 if(configStream.match(/\{[^\}]+\}/)){ 2141 form = 'JSON'; 2142 } else if(configStream.match(/.+\,\[.+\]/)){ 2143 form = 'full-dump'; 2144 } 2145 switch(form){ 2146 case 'JSON': 2147 var configData=JSON.parse(configStream); 2148 for(prp in configData){ 2149 var tempData = configData[prp]; 2150 var newLine = new nas.Pm.ProductionLine(); 2151 newLine.lineName = prp; 2152 newLine.name = tempData.name; 2153 newLine.shortName = tempData.shortName; 2154 newLine.outputAsset = tempData.outputAsset; 2155 newLine.initAsset = tempData.initAsset; 2156 newLine.code = tempData.code; 2157 newLine.description = tempData.description; 2158 newMembers.push(newLine); 2159 } 2160 break; 2161 case 'full-dump': 2162 case 'full': 2163 case 'dump': 2164 configStream=String(configStream).split('\n'); 2165 for(var ir = 0;ir<configStream.length;ir++){ 2166 if((configStream[ir].indexOf("#")==0)||(configStream[ir].length==0)) continue;//コメント/空行スキップ 2167 var tempData = JSON.parse("["+configStream[ir]+"]"); 2168 var newLine = new nas.Pm.ProductionLine(); 2169 newLine.lineName = tempData[0]; 2170 newLine.name = tempData[1][0]; 2171 newLine.shortName = tempData[1][1]; 2172 newLine.outputAsset = tempData[1][2]; 2173 newLine.initAsset = tempData[1][3]; 2174 newLine.code = tempData[1][4]; 2175 newLine.description = tempData[1][5]; 2176 newMembers.push(newLine); 2177 } 2178 break; 2179 case 'plain-text': 2180 case 'plain': 2181 case 'text': 2182 default: 2183 configStream=String(configStream).split('\n'); 2184 var currentLine=false; 2185 for(var ir = 0;ir<configStream.length;ir++){ 2186 if((configStream[ir].indexOf("#")==0)||(configStream[ir].length==0)) continue;//コメント/空行スキップ 2187 if((configStream[ir].match( /^\t([a-z]+)\:(.+)$/i ))&&(currentLine)){ 2188 currentLine[RegExp.$1]=RegExp.$2;//プロパティ設定 2189 }else{ 2190 if (currentLine) newMembers.push(currentLine); 2191 currentLine=new nas.Pm.ProductionLine(); 2192 currentLine.lineName=String(configStream[ir]); 2193 } 2194 } 2195 newMembers.push(currentLine); 2196 } 2197 return this.addMembers(newMembers) 2198 } 2199 /* 2200 ライン編集メソッド 2201 */ 2202 2203 nas.Pm.LineCollection.prototype.addLine =function(lineName,propList){ 2204 this.members[lineName] =new nas.Pm.ProductionLine(); 2205 this.members[lineName].lineName =lineName; 2206 this.members[lineName].name =propList[0]; 2207 this.members[lineName].shortName =propList[1]; 2208 this.members[lineName].outputAsset =nas.Pm.assets.entry(propList[2]); 2209 this.members[lineName].initAsset =nas.Pm.assets.entry(propList[3]); 2210 this.members[lineName].code =propList[4]; 2211 this.members[lineName].description =propList[5]; 2212 } 2213 2214 2215 nas.Pm.lines = new nas.Pm.LineCollection(nas.Pm); 2216 2217 //制作管理用 SCオブジェクト 2218 /* 2219 新規オブジェクト作成は以下のクラスメソッドを利用されたし 2220 2221 nas.Pm.newSC(カット識別子,時間指定文字列); 2222 2223 カット識別子を与えて初期化 2224 分解はクラスメソッドで行う 2225 格納はプロパティを分けて、可能ならばDBと比較対照して校正する? 2226 識別子がフルで与えられなかった場合は、現在アクティブなPmでポイントしている作品で補う 2227 2228 識別子はMapフォーマットドキュメントを参照 2229 [TITLE(セパレータ)][Oo#]OPUS(セパレータ)][[Ss]SCENE(セパレータ)?[Cc]CUT 2230 例: 2231 nas.Pm.newSC("ktc#01.s-c123","3+12,OL(1+12),--(0+0)",framerate) 2232 2233 */ 2234 /** 2235 * SCオブジェクトコンストラクタ 2236 * コンストラクタの引数は、分離を終えた状態で与える 2237 * プロパティの不足は呼び出し側(newSCi)で行う 2238 * コンストラクタ内でのチェックはしない 2239 */ 2240 nas.Pm.SCi = function SC(cutName,sceneName,myOpus,myTitle,myTime,myTRin,myTRout,myRate,myFrate,myId){ 2241 this.id = myId ;//DB連結用 DBに接続していない場合はundefined 2242 this.cut = cutName;// 2243 this.scene = sceneName;// 2244 this.opus = myOpus;//Object nas.Pm.Opus 2245 this.title = myTitle;//Object nsa.Pm.WorkTitle参照 2246 this.time = myTime;//ここでは静的プロパティ フレーム数で記録 2247 this.trin = myTRin;//[0,"trin"];//後で初期化 2248 this.trout = myTRout;//[0,"trout"];//後で初期化 2249 this.framerate = myFrate; //Object nas.Framerate; 2250 } 2251 nas.Pm.newSCi = function(idString,index){ 2252 var mySCi=Xps.parseIdentifier(idString) 2253 var mySC= new nas.PM.SC( 2254 mySCi.cut, 2255 mySCi.scene, 2256 mySCi.opus, 2257 mySCi.title, 2258 nas.FCT2Frm(mySCi.time), 2259 "", 2260 "", 2261 mySCi.framerate 2262 ) 2263 return mySC 2264 } 2265 2266 2267 nas.Pm.SCi.prototype.toString =function(){ 2268 var myResult=""; 2269 if(arguments.length){ 2270 myResult+= "##CUT="+this.cut+"\n"; 2271 myResult+= "##SCENE="+this.scene+"\n"; 2272 myResult+= this.opus.toString(true)+"\n"; 2273 myResult+= "##TIME="+this.time+"\n"; 2274 myResult+= "##TRIN="+this.trin+"\n"; 2275 myResult+= "##TROUT="+this.trout+"\n"; 2276 myResult+= "##FRAME_RATE="+this.cut+"\n"; 2277 }else{ 2278 myResult+=["s",this.scene,"-c",this.cut].join(""); 2279 } 2280 return myResult; 2281 };// 2282 nas.Pm.SCi.prototype.valueOf =function(){return this.id;};// 2283 2284 /** 2285 引数をまとめて解釈してSCiオブジェクトを返すPmクラスメソッド 2286 2287 2288 */ 2289 nas.Pm.newSC=function(myTitleString,myTimeString,myRateString){ 2290 var myInfo = nas.separateTitleString(myTitleString) 2291 var myOpus = nas.newOpus(myInfo[2],myInfo[3]); 2292 var myTimeInfo = nas.perseTimeString(myTimeString); 2293 var myRate = (myRateString)? new nas.Framerate(myRateString):myOpus.workTitle.framerate; 2294 var myTime = myTimeInfo[0]; 2295 var myTrin = myTimeInfo[1]; 2296 return new nas.Pm.SCi(myInfo[0],myInfo[1],myOpus,myTimeInfo[0],myTimeInfo[1],myTimeInfo[2],myRate); 2297 } 2298 //Test 2299 // A=nas.Pm.newSC("mte02") 2300 2301 /* 2302 管理ライン 2303 2304 new nas.Pm.Issue(Line or LineName,IssueID) 2305 発行されたライン情報 2306 .lineId; String/ 識別ID 文字列処理 専用のパーサを作る 2307 .lineName; String/ 識別名 2308 .line Object/Line 2309 .checkOut; string/ date / user 2310 .checkOutDate; string/ date / user 2311 .checkIn; String/ date / user 2312 .checkInDate; String/ date / user 2313 .currentStatus; String/ Startup,Active,Hold,Fixed,Aborted 2314 制御関連は各ステージの持つアセットがステージ内で完結する構造により無用の概念となる 2315 更新権利の概念は消失したので不要 これを持って制御する事項が無い 2316 アセット(ステージ)間の衝突の検知は必用 2317 2318 作業状態の遷移 2319 startup 初期化状態(未着手) 2320 ↓(一方通行) 2321 active ⇐⇒ hold 2322 ↓ ↓ 2323 fixed/aborted 2324 activeには本作業中とチェック作業中が含まれる 2325 holdは、作業をサーバ側で預かっている状態 作業権限の無いユーザはアクティブに遷移出来ない 2326 fixedは、ラインの作業が完成した状態 2327 abortedは、ライン自体が中断(破棄)された状態 中断からの復帰が可能なので reject.discard,destruct 等では無いが実質同等 2328 ステータス属性はラインの状態 2329 2330 */ 2331 nas.Pm.Issue=function(myLine,myID){ 2332 this.line=(myLine instanceof nas.Pm.ProductionLine)? myLine:undefined;//Object:Pm.line if exists link 2333 //名前指定時は 次の拡張では初期化時点でシステム上の既存ラインを検索、存在しない場合はライン新規登録用の機能を呼び出す 2334 this.lineId = new String(myID);//String:index 2335 this.lineName = (myLine instanceof nas.Pm.ProductionLine)? this.line.name:myLine;//String:name 2336 this.lineCheckOut = nas.CURRENTUSER;//String:uid 2337 this.lineCheckOutDate = new Date();//Date; 2338 this.lineCheckIn ;//String:uid undefined 2339 this.lineCheckInDate ;//Date: undefined 2340 this.currentStatus = "startup";//String:startup active hold fixed aborted 2341 } 2342 /* 2343 IssueにJSONの入出力を設置する必用あり 2344 */ 2345 nas.Pm.Issue.prototype.toString = function(){ 2346 var myResult = ""; 2347 myResult += "##CHECK_OUT=("+this.lineName+"):"+this.lineId+" / "+this.lineCheckOutDate.toNASString()+" / "+this.lineCheckOut +";\n"; 2348 if(this.lineCheckInDate) 2349 myResult += "##CHECK_IN=("+this.lineName+"):"+this.lineId+" / "+this.lineCheckInDate+" / "+this.lineCheckIn +";\n"; 2350 return myResult 2351 } 2352 /* 2353 LineIssues 2354 issue コレクション 2355 発行されたライン記述をパースする機能と文字列化する機能をオブジェクトメソッドで加える 2356 支線の発行/合流機能を持たせる 2357 LineIssues.branch(newIssue) : boranchedLines 2358 自分自身の現在のコピーをつくって新たなIssues オブジェクトで返す 2359 LineIssues.merge(LineIssues) : mergedLines 2360 与えられたIssuesをマージする。コンフリクト判定が必用 2361 LineIssues.parse(LineString) : initLinesItself 2362 2363 2364 2365 本体にチェックインされてクローズされたブランチを戻す 2366 引数無しでコールされた場合、条件をチェックして可能なら本体をクローズする 2367 2368 LineIssues.toString() : LineString 2369 LineIssues.valueOf() : currentIssue 2370 2371 これらのメソッドは、さらに外側のxMapにも同名メソッドが必用 2372 このメソッドはそちらから呼ばれるのが前提でありユーザやアプリケーションが直接呼び出すことは無いとしておく 2373 不正引数のハンドリングはしない 2374 2375 ライン発行コレクションはラインの作業状態を保持するコレクション 2376 作業状態はアクティブなラインの作業状態を保存する>>ステージ/ジョブの作業状態が反映される 2377 日付情報は、チェックアウト・チェックインを独自に保存 2378 */ 2379 nas.Pm.LineIssues=function LineIssues(myIssue,myParent){ 2380 this.currentId=0;//Int currentLine Array index 2381 this.body=[myIssue];// Object Array; 2382 this.parent=myParent;//Object xMap; 2383 } 2384 nas.Pm.LineIssues.prototype.valueOf =function(){return this.body[this.id]}; 2385 /* 2386 Issue 2387 */ 2388 nas.Pm.LineIssues.prototype.toString=function(){ 2389 var myResult=""; 2390 myResult+="##LINE_ID=("+ this.body[this.currentId].lineName +"):"+this.body[this.currentId].lineId+"\n"; 2391 myResult+="##currentStatus="+ this.body[this.currentId].currentStatus+"\n"; 2392 for (var iix=0;iix<this.body.length;iix++){myResult+=this.body[iix].toString();} 2393 return myResult; 2394 } 2395 /* branch(新規ライン名) 2396 ブランチ 2397 既存のラインと同名のブランチが指定された場合ブランチは失敗 false を戻す 2398 ただし現在の実装だと、支線側で親のラインを把握していないので 重複の可能性を排除できない 2399 DB接続時は、マスターDBに問い合わせを行う処理が必用 2400 最終的には同名のラインは許容される 2401 */ 2402 nas.Pm.LineIssues.prototype.branch=function(newLineName){ 2403 for(var ix =0;ix<this.body.length;ix++){if(this.body[ix].lineName==newLineName) return false;};//重複をリジェクト 2404 var currentDepth = this.body[this.currentId].lineId.split(":").length;//現在の分岐深度 2405 var branchCount = 0; 2406 for(var ix =0;ix<this.body.length;ix++){if(this.body[ix].lineId.split(":").length==currentDepth) branchCount++;}; 2407 var newBranchId = (this.body[this.currentId].lineId=="0")? branchCount :this.body[this.currentId].lineId+":"+branchCount; 2408 var newIssue = new nas.Pm.Issue(newLineName,newBranchId); 2409 this.body.push(newIssue); 2410 var newIssues = new nas.Pm.LineIssues(newIssue); 2411 return newIssues; 2412 } 2413 /* merge(Issueオブジェクト) 2414 //支線のIssues配列をマージする 今日は検査は保留20160505 2415 マージの手順 2416 マージされる側のラインのステータスを検査 startup,active,hold のラインはマージ不可 処理失敗 2417 fixed,abortedのラインのみがマージ可能 2418 マージ側のトランクに対する被マージ(親)側の該当するラインを閉じる(チェックイン) 2419 同時にマージ側のラインを同じタイムスタンプで閉じる 2420 親ラインに未登録のサブラインは、ここでマージされる。 2421 この時点で発給されたラインにマージ(チェックイン)されていないラインはこれ以降のマージは親ラインに対して行なわれる。 2422 =クローズした子ラインに対するマージは、データの整合性を脅かすので禁止 2423 2424 */ 2425 nas.Pm.statuses={"startup":0,"active":1,"hold":2,"fixed":3,"aborted":4}; 2426 2427 nas.Pm.LineIssues.prototype.merge = function(myBranch){ 2428 if(nas.Pm.statuses[myBranch.body[myBranch.currentId].currentStatus]<3) return false; 2429 //カレントラインがフィックスしていない場合失敗 2430 for(var ix=0;ix<this.body.length;ix++){ 2431 if(this.body[ix].lineId==myBranch.body[0].lineId){ 2432 //マージ側のラインが被マージ側にあるか否か確認 2433 if(typeof this.body[ix].lineCheckIn !="undefined"){ 2434 return false;//既にマージ済みの場合もリジェクト 2435 }else{ 2436 this.body[ix].lineCheckIn=nas.CURRENTUSER; 2437 this.body[ix].lineCheckInDate =new Date(); 2438 myBranch.body[0].lineCheckIn =this.body[ix].lineCheckIn;//転記 2439 myBranch.body[0].lineCheckInDate=this.body[ix].lineCheckInDate;//転記 2440 for(var mix=1;mix<myBranch.body.length;mix++){ 2441 this.body.push(myBranch.body[mix]);//残り情報を転記 2442 } 2443 } 2444 } 2445 } 2446 return myBranch; 2447 } 2448 //クラスメソッド 2449 nas.Pm.parseIssue = function(datastream){ 2450 if(! datastream.match){return false}; 2451 //ラインで分割して配列に取り込み 2452 var SrcData = new Array(); 2453 if(datastream.match(/\r/)){datastream=datastream.replace(/\r\n?/g,("\n"))}; 2454 SrcData=datastream.split("\n"); 2455 var newIssues = false; 2456 for (l=0;l<SrcData.length;l++){ 2457 if(SrcData[l].match(/^\#\#([\[<A-Z][^=]+)=?(.*)$/)){var nAme=RegExp.$1;var vAlue=RegExp.$2;} 2458 switch (nAme){ 2459 case "LINE_ID": 2460 if(! newIssues) { 2461 var myContent = vAlue.split(":"); 2462 var myLineName = myContent[0].replace(/^\(|\)$/g,""); 2463 // alert("setupLine :"+myLineName); 2464 var myLineId = myContent.slice(1,myContent.length).join(":"); 2465 newIssues = new nas.Pm.LineIssues(new nas.Pm.Issue(myLineName,myLineId)); 2466 }else{continue;} 2467 break; 2468 case "CHECK_OUT": 2469 case "CHECK_IN": 2470 var myContentIssue = vAlue.split(";")[0].split("/"); 2471 var myIndex = myContentIssue[0].split(":");myIndex[1] = nas.chopString(myIndex[1]); 2472 var myDate = myContentIssue.slice(1,myContentIssue.length-1).join("/"); 2473 var myUser = nas.chopString(myContentIssue[myContentIssue.length-1]); 2474 if((newIssues)&&(newIssues.body[newIssues.body.length-1].lineId==myIndex[1])){ 2475 var myIssue = newIssues.body[newIssues.body.length-1]; 2476 }else{ 2477 var myIssue = new nas.Pm.Issue(myIndex[0].replace(/^\(|\)$/g,""),myIndex[1]); 2478 newIssues.body.push(myIssue); 2479 } 2480 if(nAme=="CHECK_OUT"){ 2481 myIssue.lineCheckOut = myUser; 2482 myIssue.lineCheckOutDate= new Date(myDate); 2483 }else{ 2484 myIssue.lineCheckIn = myUser; 2485 myIssue.lineCheckInDate = new Date(myDate); 2486 } 2487 break; 2488 case "currentStatus": 2489 newIssues.currentStatus = nas.chopString(vAlue) ; 2490 break; 2491 } 2492 } 2493 return newIssues; 2494 } 2495 /* 2496 ライン情報は、1セットのxMap/Xpsに対して1種類発行される 2497 Pm.PmUには同時に複数セットのラインが記録され 複数の 2498 2499 A= "##LINE_ID=(本線):0\n##CHECK_OUT=(本線):0/ 2016/01/31 18:45:22 / kiyo;" 2500 B=nas.Pm.parseIssue(A); 2501 C=B.branch("BG").toString(); 2502 B.body[B.currentId].lineId 2503 2504 */ 2505 /*========================================================================この下は整理が済んだらcommonライブラリへ移行*/ 2506 /** 2507 カット表記用時間文字列オブジェクト 2508 名前とフレーム数で初期化する 2509 toString()メソッドは 秒+コマ 又は 名前(秒+コマ)型式文字列 2510 valueOf() メソッドは フレーム数を返す 2511 toStringにXps保存用の形式も必要 ","区切りで倒置 2512 */ 2513 nas.TimeUnit = function(myName,myFrames){ 2514 this.name = myName; 2515 this.frames = myFrames; 2516 this.toString = function(myForm){ 2517 if(myForm){ 2518 return (this.name)?([nas.Frm2FCT(this.frames,3) , this.name ]).join(","):nas.Frm2FCT(this.frames,3); 2519 }else{ 2520 return (this.name)? this.name+" ( "+nas.Frm2FCT(this.frames,3)+" )":nas.Frm2FCT(this.frames,3); 2521 } 2522 } 2523 this.valueOf = function(){return this.frames;} 2524 } 2525 /** 2526 カット用の時間記述を解釈してTimeUnitオブジェクトの配列で返す 2527 nas.parseTimeString("timeString") 2528 "1+12,OL(3+0),4+0" コンマ区切りでいくつでも配列で返す 2529 ⇒[{name:"time",frames:Frames-Int},{name:"tr-in",frames:Frames-Int},{name:"tr-out",frames:Frames-Int}] 2530 **解釈の幅を広げてパターン調整が必要 2531 */ 2532 nas.parseTimeString = function(myTimeString){ 2533 var myTarget = myTimeString.split(","); 2534 var myResult = new Array(); 2535 for (var t = 0; t < myTarget.length; t ++){ 2536 myResult[t] =new nas.TimeUnit(); 2537 if(myTarget[t].match(/(.*)\(([^\)]+)\)$/)){ 2538 myResult[t] =new nas.TimeUnit(RegExp.$1,nas.FCT2Frm(RegExp.$2)); 2539 }else{ 2540 myResult[t]=new nas.TimeUnit("",nas.FCT2Frm(myTarget[t])); 2541 } 2542 } 2543 return myResult; 2544 } 2545 //test nas.pareseTimeString("12+6,trin(0),tr-out(0)"); 2546 2547 /* nas.separateTitleString(titleString) 2548 識別文字列を分解して配列戻し 2549 カット識別文字列の詳細はドキュメントを参照 2550 引数:カット識別文字列 "title.opus.scene.cut" 2551 戻値:配列[cut,scene,opus,title] 2552 例: 2553 nas.separateTitleString("Title#12_s12-c#123B") == ["123B","12","12","Title"] 2554 nas.separateTitleString("XAv/10/s-c0023") == ["0023","","10","XAv"] 2555 セパレータは . / _ - 2556 プレフィックスは Oo#Ss#Cc# 2557 ポストフィックスはカット番号に含まれるものとします。>必要にしたがって別途パースすること 2558 */ 2559 nas.separateTitleString = function(myName){ 2560 // alert(myName); 2561 var regSep = new RegExp("[\\.\/\-]+","g");//セパレータ("_"以外) 2562 var myString = myName.toString().replace(regSep,"_");//セパレータを統一 2563 myString = myString.replace(/[cCcCsSsSoOoO##№][##№]?([0-9]+)/g,"_$1") 2564 // プレフィクスをセパレータに変換 2565 // alert(myString); 2566 myString = myString.replace(/_+/g,"_");//連続セパレータを縮小 2567 // alert(myString); 2568 var myParse = myString.split("_").reverse(); 2569 var newCut = (myParse.length>0)?myParse[0]:""; 2570 // var newCut=(myParse.length>0)?new String(myParse[0]).replace(/^[cCcC]?[##№]?/,""):""; 2571 var newScene = (myParse.length>1)?new String(myParse[1]).replace(/^[sSsS]?[##№]?/g,""):myScene; 2572 // var newOpus = (myParse.length>2)?new String(myParse[2]).replace(/^[oOoO]?[##№]?/g,""):myOpus; 2573 var newOpus = (myParse.length>2)?myParse[2]:myOpus; 2574 var newTitle = (myParse.length>3)?myParse[3]:myTitle; 2575 return [newCut,newScene,newOpus,newTitle]; 2576 } 2577 // nas.separateTitleString("Title#12_s12-c#123B"); 2578 // nas.separateTitleString("TitleO#12s#12c#123B"); 2579 // timeString 2580 // 1+12 (trin:0+00)(trout:0+00) 2581 // test 2582 // var A=new SC("c012","s") 2583 /** nas.Pm.Orgnization 2584 システム内で参照される組織の 2585 */ 2586 /** nas.Pm.Staff 2587 作業許可/拒否の判定基準となるスタッフオブジェクト 2588 .type String //自動設定スタッフエントリのタイプ識別名 2589 .user Object nas.UserInfo or null or * // 2590 .duty Object dutyName or null or * // 2591 .section Object sectionName or null or * // 2592 .access bool //アクセス権 2593 .alias String //スタッフユーザの表示名称 ユーザ指定可能 デフォルトは"" データがある場合は、優先的にユーザハンドルと置換される 2594 2595 ""(ヌルストリング) nullエントリとして扱う 2596 nullエントリは、自身を含む全てのエントリとマッチしない 2597 2598 特殊なエントリとして"*"(スターエントリ)を扱う 2599 アクセス権を判定する場合、設定可能な全てのユーザとマッチする特殊なエントリ 2600 *同士は判定対象外(マッチがおきない) 2601 2602 以下のエントリは全ての部門、役職及びユーザのアクセスを禁止する (一般に指定されない) 2603 false,"*","*","*" 2604 2605 以下のエントリは演出部のユーザ全てのアクセスを許す 2606 true,"*","*","演出" 2607 以下のエントリ役職が演出である演出部所属のユーザのアクセスを許す 2608 true,"*","演出","演出" 2609 以下のエントリは役職が演出である全てのユーザのアクセスを許す、このエントリは上記のエントリの内容を包括する 2610 true,"*","演出","*" 2611 以下のエントリは役職が演出でいずれの部門にも属さないユーザのアクセスを許す 2612 true,"*","演出","" 2613 2614 以下のエントリは演出部の全て役職のアクセスを許す 2615 true,"*","*","演出" 2616 */ 2617 nas.Pm.Staff = function(user,duty,section,access,alias){ 2618 this.type ; //String タイプ識別名 section/duty/user 2619 // if(!(user instanceof nas.UserInfo)) user =new nas.UserInfo(user); 2620 this.user = (user)? user:null;//Object nas.UserInfo or * or null 2621 this.duty = (duty)? duty:null; //StringID of duty 2622 this.section = (section)? section:null; //StringID of section 2623 this.access = (typeof access == "undefined")? true:(access); //bool アクセス権 2624 this.alias = (alias)? alias:""; //String 表示名称 ユーザ指定可能 デフォルトは"" 2625 this.typeSet(); 2626 } 2627 /* 2628 テキスト形式の指定を受けてスタッフオブジェクトを再初期化するオブジェクトメソッド 2629 palin形式の文字列は、単一レコードでは初期化に必要な情報に欠けるのでここでは扱わない 2630 StaffCollectionのメソッドのみが受け付ける 2631 ここではdump形式のみを判定 それ以外はfullフォーマットとして扱う 2632 */ 2633 nas.Pm.Staff.prototype.parseStaff = function(staffString){ 2634 if (staffString.match(/^\[([^\[\]]+)\]$/)) {; 2635 /* 2636 [access ,alias ,user ,duty ,section] 2637 dump format 2638 */ 2639 var myProps=JSON.parse(staffString); 2640 if (myProps.length!=5) return false; 2641 this.access = (String(myProps[0]).match(/-|false/i))?false:true; 2642 this.alias = myProps[1]; 2643 this.user = (myProps[2])? new nas.UserInfo(myProps[2]):null; 2644 this.duty = myProps[3]; 2645 this.section = myProps[4]; 2646 } else { 2647 //full format 2648 /* 2649 Access *SECTION* [DUTY] handle:email ALIAS 2650 2651 Access 以外は順不同 2652 ALIAS は、スタッフユーザの表示エイリアスなのでuserエントリがnullの場合は意味を持たないことに注意 2653 */ 2654 staffString= staffString.replace(/\s+/g,'\t');//空白をタブに置換 2655 var myProps = staffString.split('\t');//配列化 2656 if ((myProps.length<2)||(myProps.length>6)) return false;//フィールド数0,1,6~は不正データ 2657 this.access=(myProps[0].match( /-|false/i ))?false:true;//第一フィールドは、固定でアクセス可否 bool 2658 //第二フィールド〜ラストまでループでチェック 2659 for (var ix=1;ix<myProps.length;ix++){ 2660 if(myProps[ix].match(/^\*([^\*]+)\*$/)){ 2661 this.section=RegExp.$1;// *SECTION* 2662 }else if(myProps[ix].match(/^\[([^\]]+)\]$/)){ 2663 this.duty=RegExp.$1;// [duty] 2664 }else if(myProps[ix].match(/^[^:]+:[^:]+/)){ 2665 this.user=new nas.UserInfo(myProps[ix]);// Handle:email 2666 }else{ 2667 this.alias = myProps[ix] 2668 } 2669 } 2670 } 2671 this.typeSet(); 2672 return this; 2673 } 2674 /*TEST 2675 var A = new nas.Pm.Staff(); 2676 A.parseStaff('[false,"","","プロデューサ","制作管理"]'); 2677 A.parseStaff(' *うなぎ* [海遊館] ハンドル:sample@example.com ほげら'); 2678 2679 */ 2680 /* 2681 データの内容を確認してtypeプロパティをセットする。 2682 同時に必要なエントリにスタープロパティを補う 2683 初期化以後プロパティの変更の際にコールする必要がある 2684 */ 2685 nas.Pm.Staff.prototype.typeSet = function(){ 2686 if((this.user)&&(this.user!="*")){ 2687 this.type = "user"; 2688 }else{ 2689 if((this.duty)&&(this.duty!="*")){ 2690 this.type = "duty"; 2691 }else if((this.section)&&(this.section!="*")){ 2692 this.type = "section"; 2693 }else{ 2694 this.type = null; 2695 } 2696 } 2697 return this.type; 2698 } 2699 /* .samaAs 2700 同値判定用メソッド 2701 アクセス可否判定を含めてエントリが完全に一致した場合のみtrueを返す 2702 ユーザ情報はメールアドレスのみでなくハンドルまで一致した場合にtrue 2703 null,"" は、いずれのエントリとも一致しない 2704 マッチングの順位あり 2705 タイプ 部署 役職 ユーザ ハンドル アクセス可否 2706 user 全マッチ以外はfalse 2707 section 2708 duty 2709 */ 2710 nas.Pm.Staff.prototype.sameAs = function(target){ 2711 if(!(target instanceof nas.Pm.Staff)) return false; 2712 var result = 0; 2713 //user プロパティに値がある 双方がUserInfoオブジェクトだった場合のみ文字列化して比較 それ以外は直接比較 2714 if(this.user){ 2715 if ((this.user instanceof nas.UserInfo)&&(target.user instanceof nas.UserInfo)){ 2716 if(this.user.toString()==target.user.toString()) result += 4; 2717 } else { 2718 if(this.user==target.user) result +=4; 2719 } 2720 }else{ 2721 //値がない>相手先に値がない場合のみマッチ (nullが"",0,false等とマッチする) 2722 if(! target.user) result += 4; 2723 } 2724 if (this.duty){ 2725 if(String(this.duty)==String(target.duty)) result += 2;//文字列比較 2726 }else{ 2727 if(! target.duty) result += 2; 2728 } 2729 if (this.section){ 2730 if(String(this.section)==String(target.section)) result += 1;//文字列比較 2731 }else{ 2732 if(! target.section) result += 1; 2733 } 2734 if ((this.access)==(target.access)) result += 8 ;//比較先にアクセス権がなければ負数へ 2735 return (result==15); 2736 } 2737 /*TEST 2738 var A = new nas.Pm.Staff("*","*","作画"); 2739 var B = new nas.Pm.Staff("","作画監督","作画"); 2740 var C = new nas.Pm.Staff("","演出",""); 2741 var D = new nas.Pm.Staff(new nas.UserInfo("kiyo:kiyo@nekomataya.info"),"作画監督","作画"); 2742 D.alias="ねこまたや"; 2743 2744 A.sameAs(A); 2745 A.sameAs(B); 2746 A.sameAs(C); 2747 A.sameAs(D); 2748 A.sameAs(); 2749 A.sameAs("kjsadhjakshdjkh"); 2750 2751 B.parseStaff(A.toString("dump")) 2752 */ 2753 2754 /* 2755 .compareWith(target) 2756 比較用に与えられたオブジェクトとの比較係数を返す 2757 特殊エントリ "*" 2758 比較先が"*"エントリの場合、"*","",nullを除く全てのエントリに対してマッチが発生する 2759 比較元が"*"の場合は、 比較先"*"を含めてなにものにもマッチしない 2760 2761 片方向判定を行うので、thisとtargetを入れ替えた場合の戻り値は一致しない 2762 2763 特殊エントリ "" == null 2764 比較元が及び比較先が""またはnullの場合""同士、null同士を含めてマッチが発生しない 2765 「比較先」のアクセス可否情報を見てfalseの場合 得られた係数を正負反転させて戻す。 2766 (自身の可否情報は見ない 必要があれば戻り値に対して自身のアクセス可否情報を乗せる) 2767 2768 var A=[true * * 演出] 2769 var B=[false * 監督 演出] 2770 var C=[true タヌキ 監督 演出] 2771 として 2772 A.cpmpareWith(A) result 1 2773 A.cpmpareWith(B) result -1 2774 A.cpmpareWith(C) result 1 2775 B.cpmpareWith(A) result 3 2776 B.cpmpareWith(B) result -3 2777 B.cpmpareWith(C) result 3 2778 C.compareWith(A) result 7 2779 C.compareWith(B) result -7 2780 C.compareWith(C) result 7 2781 2782 用途: 自身に対する相手の比較係数を得て自身のアクセスの可否を判定するのが主 2783 副用途として、エントリコレクション中の完全一致するエントリを検出して重複エントリの排除を行う? 2784 --完全一致の判定が出来ない? 2785 */ 2786 nas.Pm.Staff.prototype.compareWith = function(target){ 2787 if(!(target instanceof nas.Pm.Staff)) return false; 2788 var result = 0; 2789 // 一致条件 2790 // 相手先が nullと*以外の場合で自身が* >マッチ 2791 // 自身の値が存在して(null以外) >相手を判定 相手先が 2792 // >相手先問わずアンマッチ 2793 // 自身と相手先の判別 2794 if ( 2795 (this.user!="*")&& 2796 (((this.user)&&(target.user=="*"))|| 2797 ((this.user instanceof nas.UserInfo)&&(this.user.sameAs(target.user)))) 2798 ) result += 4; 2799 if ( 2800 (this.duty!="*")&& 2801 (((this.duty)&&(target.duty=="*"))|| 2802 (this.duty == target.duty)) 2803 ) result += 2; 2804 if ( 2805 (this.section!="*")&& 2806 ((this.section)&&(target.section=="*"))|| 2807 ((this.section)&&(this.section == target.section)) 2808 ) result += 1; 2809 //比較先にアクセス権がなければ負数へ(自身のアクセス権は問わない) 2810 if (! target.access) result *= -1 ; 2811 return result; 2812 } 2813 /*TEST (user,duty,section,access,alias) 2814 var A=new nas.Pm.Staff("*","*","演出"); 2815 var B=new nas.Pm.Staff("*","監督","演出",false); 2816 var C=new nas.Pm.Staff(new nas.UserInfo("タヌキ:tanuki@animal.example.com"),"監督","演出",true); 2817 // として 2818 console.log(A.compareWith(A)) ;//result 1 2819 console.log(A.compareWith(B)) ;//result -1 2820 console.log(A.compareWith(C)) ;//result 1 2821 console.log(B.compareWith(A)) ;//result 3 2822 console.log(B.compareWith(B)) ;//result -3 2823 console.log(B.compareWith(C)) ;//result 3 2824 console.log(C.compareWith(A)) ;//result 7 2825 console.log(C.compareWith(B)) ;//result -7 2826 console.log(C.compareWith(C)) ;//result 7 2827 */ 2828 /* 2829 文字列化して返す 2830 formオプション 2831 plain-textフォーマット 2832 'plain-text' 2833 'plain' 2834 'text' 2835 この書式は、スタッフコレクションから呼び出された時のみに意味を持つので注意 2836 sction 2837 部門 \t部門名 2838 duty 2839 役職 \t\t役職名 2840 user 2841 ユーザ \t\t\tハンドル:e-メール 2842 2843 スタッフコレクションの'plain'オプションに対応する機能 2844 2845 2846 full-dumpフォーマット 2847 'full-dump' 2848 'full' 2849 'dump' 2850 2851 アクセス可否 UID [役職] *部門* 別名 2852 2853 スペース区切りで、第一フィールドはアクセス可否 2854 最終フィールドは別名 2855 UIDは通常文字列 2856 役職はブラケットで囲む 2857 部門はスターで囲む 2858 それぞれのエントリが無い場合はフィールドごと省略するのでフィールド数は可変 2859 2860 dumpフォ−マット 2861 'dump'テキスト記録用文字列で返す 2862 2863 [アクセス可否,"別名","UID","役職","部門"] 2864 配列型文字列 フィールド数固定 2865 2866 エントリーの全情報をカンマ区切りで出力する。 2867 コレクションのエントリ追加メソッドの引数形式 2868 2869 2870 上記以外の返り値の文字列はtypeにより異なる 2871 section(部門)エントリーはセクション名の前後に'*'を付けて返す 2872 ex:*演出* *作画* 2873 duty(役職)エントリーは役職名の前後をブラケットで囲んで返す 2874 ex:[監督][作画監督] 2875 部門エントリがあればそれを添付する 2876 2877 ユーザエントリーは、ユーザの表示名を返す オブジェクトに設定されたALIASまたはユーザ情報オブジェクトのハンドル 2878 2879 JSONフォーマット 2880 他のDBとのデータ交換用にJSON文字列化したデータを返す 2881 */ 2882 nas.Pm.Staff.prototype.toString = function(form){ 2883 switch(form){ 2884 case 'JSON': 2885 return JSON.stringify({ 2886 acsess:this.access, 2887 type:this.type, 2888 alias:this.alias, 2889 user:((this.user)?this.user.toString():null), 2890 duty:this.duty, 2891 section:this.section 2892 }); 2893 break; 2894 case 'plain-text': 2895 case 'plain': 2896 case 'text': 2897 var result=(this.access)?"\t":"-\t"; 2898 switch(this.type){ 2899 case "section": 2900 result += this.section; 2901 break; 2902 case "duty": 2903 result += "\t"; 2904 result += this.duty; 2905 break; 2906 case "user": 2907 if(this.alias.length){this.user.handle=this.alias} 2908 result += "\t\t"; 2909 result += this.user.toString(true); 2910 break; 2911 } 2912 return result; 2913 break 2914 case 'full-dump': 2915 case 'full': 2916 case 'dump': 2917 var result=(this.access)?[true]:[false]; 2918 result.push(this.alias); 2919 result.push((this.user)?this.user.toString():''); 2920 result.push(this.duty); 2921 result.push(this.section); 2922 return JSON.stringify(result); 2923 break; 2924 /* case 'void': 2925 var result=''; 2926 result +=(this.access)? "":"-"; 2927 if(this.user){ 2928 result +="\t"; 2929 result += (this.user instanceof nas.UserInfo)? this.user.toString():String(this.user); 2930 } 2931 if(this.duty){ 2932 result +="\t"; 2933 result += "["+String(this.duty)+"]"; 2934 } 2935 if (this.section){ 2936 result +="\t"; 2937 result += "*"+String(this.section)+"*" ; 2938 } 2939 if (this.alias){ 2940 result +="\t"; 2941 result += String(this.alias) ; 2942 } 2943 return result; 2944 */ 2945 default: 2946 var result=(this.access)?'':'-'; 2947 switch(this.type){ 2948 case "duty" : 2949 result += "["+String(this.duty)+"]"; 2950 break; 2951 case "section": 2952 result += "*"+String(this.section)+"*" ; 2953 break; 2954 case "user" : 2955 if(this.alias.length){ 2956 result += String(this.alias); 2957 }else{ 2958 result += String(this.user.handle); 2959 } 2960 break; 2961 default: 2962 return false; 2963 } 2964 return result; 2965 } 2966 } 2967 //test 初期化引数 user,duty,section,access,alias 2968 /* 2969 var A = new nas.Pm.Staff("*","*","作画"); 2970 var B = new nas.Pm.Staff("","作画監督","作画"); 2971 var C = new nas.Pm.Staff("","演出",""); 2972 var D = new nas.Pm.Staff(new nas.UserInfo("kiyo:kiyo@nekomataya.info"),"作画監督","作画"); 2973 D.alias="ねこまたや"; 2974 F= new nas.Pm.StaffCollection(nas.pm); 2975 F.addStaff([A,B,C,D]); 2976 2977 //console.log(F) 2978 //A.sameAs(B); 2979 D.sameAs(C); 2980 */ 2981 /** nas.Pm.StaffCollection 2982 スタッフコレクションオブジェクト 2983 スタッフを収集したスタッフコレクションをエントリノード毎に保持する 2984 問い合わせに対して権利の解決を行う 2985 ペアレント属性には、自身が所属するノードが格納される 2986 ノードのペアレント属性に親子関係にあるノードがあるので、継承及び参照の解決は当該の情報パスをたどる。 2987 コレクションのメンバー数が0の場合、コレクションは上位ディレクトリの内容を返す 2988 .parent Object 所属するノード 親ノードのstaffをアクセスするパスは this.parent.parent.staffs 2989 .members Array オブジェクトトレーラー配列 2990 .add() Function メンバー追加メソッド 戻り値 追加成功時 Object staff 失敗時 false 2991 .parseConfig() Function 設定ファイルのストリームからメンバーを入れ替え 2992 .dump() Functio ダンプリストを取得 2993 .toString() Function 2994 .remove() エントリを削除 2995 2996 2997 */ 2998 nas.Pm.StaffCollection = function(myParent){ 2999 this.parent = myParent; 3000 this.members = []; 3001 } 3002 /* 3003 toStringは、二種の出力フォーマットを持つ 3004 full/引数なし または dump 3005 フルフォーマットは可読テキストとして出力 3006 第1フィールドに何らかのデータのあるレコードは拒否エントリになる 3007 第4フィールドはalias 個々にデータがある場合、そのエントリの表示名称として優先して使用される 3008 例 \t演出\t監督\t\tbigBoss 3009 例 \t作画\t原画\tcitten:cat@animals.example.com\tキティちゃん 3010 各フィールドの値として、h-tabは使用できない 3011 ダンプフォーマットは、機械読み取り用のフォーマットでaddStaffメソッドの引数形式 3012 3013 3014 nas.Pm.StaffCollection.prototype.toString = function(form){ 3015 var result=""; 3016 switch (form){ 3017 case "full": 3018 for (var ix =0 ; ix<this.members.length;ix++){ 3019 if (ix > 0) result +="\n"; 3020 result += this.members[ix].toString('full'); 3021 } 3022 result += '\n'; 3023 return result; 3024 break; 3025 case "plain": 3026 for (var ix =0 ; ix<this.members.length;ix++){ 3027 if (ix > 0) result +="\n"; 3028 result += this.members[ix].toString('plain'); 3029 } 3030 result += '\n'; 3031 return result; 3032 break; 3033 case "dump": 3034 for (var ix =0 ; ix<this.members.length;ix++){ 3035 if (ix > 0) result +=",\n"; 3036 result += this.members[ix].toString('dump'); 3037 } 3038 result += '\n'; 3039 return result; 3040 break; 3041 default: 3042 var result = new Array; 3043 for (var ix =0 ; ix<this.members.length;ix++){ 3044 result.push(this.members[ix].toString()); 3045 } 3046 return result.toString(); 3047 } 3048 } 3049 */ 3050 nas.Pm.StaffCollection.prototype.dump=nas.Pm._dumpList; 3051 /* 3052 コレクションをソートする 3053 ソート基準は 3054 部門 役職 ユーザ 3055 メンバーをタイプ別にわける 3056 タイプごとに部門でソートする 3057 部門エントリを抽出して 辞書ソート 3058 部門1エントリ毎に役職エントリを抽出して辞書ソート 3059 役職1エントリ毎にユーザエントリを抽出して 3060 役職エントリ 部門ソート 辞書ソート 3061 ユーザエントリ 部門ソート 役職ソート 辞書ソート 3062 3063 */ 3064 nas.Pm.StaffCollection.prototype.sort = function(){ 3065 3066 }; 3067 /* 3068 コレクション内の指定条件にマッチするエントリを新たなコレクションで返すメソッド 3069 引数 staffString 3070 フルフォーマット文字列 3071 "*演出*" 部門・演出 のエントリをタイプ問わず 3072 "*演出* [演出助手]","user" 部門・演出 && 役職・演出助手 のユーザエントリ 3073 " [作画監督]","section" 役職・作画監督 を含む部門エントリ 3074 '馬:hose@animal.example.com','duty' ユーザ・馬が所属する役職エントリ 3075 エントリの問い合わせがあった場合、コレクションメンバーを検索してアクセスの可否を返す。 3076 コレクションのエントリ数が0の場合のみ、親オブジェクトの持つスタッフコレクションに問い合わせを行いその結果を返す。 3077 */ 3078 nas.Pm.StaffCollection.prototype.getMember = function(staffString,type){ 3079 var result=new nas.Pm.staffCollection(this.parent); 3080 var sect=''; var dut =''; var usr =''; 3081 } 3082 /* .parseConfig 3083 設定ファイルのスタッフ初期化文字列をパースしてスタッフコレクションを更新するオブエジェクトメソッド 3084 引数はレコード改行区切りテキストストリーム 3085 受け入れ形式は3つ 3086 ストリームの第一有効レコードで判定する 3087 3088 いずれも行頭 '#'はコメント行 空行は無視 3089 JSON データ交換用JSON 3090 {access:<ACESS>,alilas:<ALIAS>,user:<USER>,duty:<DUTY>,section:<SECTION>,type:<TYPE>} 3091 full-dump 引数配列形式 3092 [アクセス可否,"別名","UID","役職","部門"] 3093 3094 plain-text タブ区切りフィールド 3095 アクセス可否\t部門\t役職\tユーザ\t別名 3096 3097 free-form スペース分離 不定フィールドテキスト 3098 アクセス可否 handle:UID [役職] *部門* 別名 3099 例: 3100 true *演出* 3101 false *作画* [原画] 3102 3103 ** Free-Formは、スタッフDB記述の独自記法なので充分に留意のこと これに類する記法は他に Line,Stage,Job にみられる 3104 3105 3106 */ 3107 nas.Pm.StaffCollection.prototype.parseConfig = function(dataStream,form){ 3108 var myMembers =[]; 3109 // 形式が指定されない場合は、第一有効レコードで判定 3110 if(! form ){ 3111 if (dataStream.match(/\[\s*(\{[^\}]+\}\s*,)\s*(\{[^\}]+\})?\s*\]/)) form='JSON';//配列JSON 3112 else if (dataStream.match(/(\n|^)\[.+\]($|\n)/)) form='full-dump'; 3113 else if (dataStream.match(/\*[^\*]+\*|\[[^\[\]]+\]/)) form='free-form';//] 3114 else form='plain-text'; 3115 } 3116 switch(form){ 3117 case 'JSON': 3118 var tempObject=JSON.parse(dataStream); 3119 for (var rix=0;rix<tempObject.length;rix++){ 3120 var currentStaff=new nas.Pm.Staff( 3121 tempObject[rix].user, 3122 tempObject[rix].duty, 3123 tempObject[rix].section, 3124 tempObject[rix].access, 3125 tempObject[rix].alias 3126 ); 3127 myMembers.push(currentStaff); 3128 } 3129 break; 3130 case 'full-dump': 3131 case 'free-form': 3132 dataStream = String(dataStream).split("\n"); 3133 for (var rix=0;rix<dataStream.length;rix++){ 3134 if(dataStream[rix].indexOf('#')==0) continue; 3135 var currentStaff=new nas.Pm.Staff(); 3136 currentStaff.parseStaff(dataStream[rix]); 3137 if (currentStaff) myMembers.push(currentStaff); 3138 } 3139 break; 3140 case 'plain-text': 3141 default: 3142 dataStream = String(dataStream).split("\n"); 3143 var currentSection=null;var currentDuty=null; 3144 for (var rix=0;rix<dataStream.length;rix++) { 3145 if((dataStream[rix].indexOf('#')==0)||(dataStream[rix].length == 0)) continue; 3146 var currentRecord=dataStream[rix].split('\t'); 3147 var currentAccess=true;var currentUser=null;var currentAlias=""; 3148 //plainフォーマットはタブ区切り タブ1つは部門 2つで役職 3つでユーザ ユーザ指定のレコードには別名の指定も可 3149 //例: ^access section duty user alias 3150 if(currentRecord[0]) currentAccess = (String(currentRecord[0]).match( /-|false/i ))?false:true; 3151 if(currentRecord[1]) { 3152 var mySection = currentRecord[1].replace(/\/$/,""); 3153 if(mySection != currentSection) {currentSection=mySection;currentDuty=null;} 3154 //myMembers.push(new nas.Pm.Staff(null,null,currentSection,currentAccess,"")); 3155 } 3156 if(currentRecord[2]) { 3157 currentDuty = currentRecord[2]; 3158 // myMembers.push(new nas.Pm.Staff(null,currentDuty,currentSection,currentAccess,"")); 3159 } 3160 if(currentRecord[3]) { 3161 var currentUser = new nas.UserInfo(currentRecord[3]); 3162 var currentAlias = (currentRecord[4])? currentRecord[4]:""; 3163 // myMembers.push(new nas.Pm.Staff(currentUser,currentDuty,currentSection,currentAccess,currentAlias)); 3164 } 3165 myMembers.push(new nas.Pm.Staff(currentUser,currentDuty,currentSection,currentAccess,currentAlias)); 3166 } 3167 } 3168 return this.addStaff(myMembers); 3169 } 3170 /*TEST 3171 3172 */ 3173 3174 3175 3176 /* 3177 ターゲットになるユーザまたはスタッフとコレクションの内容を比較して、 3178 一致したエントリIDを返すメソッド 3179 ヒットしなかった場合は -1 3180 */ 3181 nas.Pm.StaffCollection.prototype.indexOf = function(target){ 3182 for (var ix =0 ;ix <this.members.length;ix ++){ 3183 if(this.members[ix].sameAs(target)) return ix; 3184 } 3185 return -1; 3186 } 3187 /* スタッフの追加メソッド 3188 引数は nas.Pm.Staff オブジェクト 3189 引数形式は、Staffオブジェクトまたはオブジェクトの配列 3190 可読テキストの再ロードはparseConfigメソッドを利用 3191 parseConfigメソッドは、可読テキストをdump形式にコンバートしてこのメソッドを内部で呼び出す 3192 同内容のエントリがあった場合は追加されない。 3193 3194 追加時に既存のsection/dutyエントリに存在しないプロパティを持ったuserエントリがあった場合は、 3195 当該のエントリを新規に作成して追加する? ユーザの設定を変更することになるのでコレは行わない 3196 戻り値は、追加に成功したエントリ数(エントリ配列か?) 3197 3198 */ 3199 nas.Pm.StaffCollection.prototype.addStaff = function(members){ 3200 var result=0; 3201 if(!( members instanceof Array)) members = [members]; 3202 for(var ix =0 ; ix<members.length;ix++){ 3203 if(!(members[ix] instanceof nas.Pm.Staff)){ 3204 /* 3205 member[0]// access 3206 member[1]// alias 3207 member[2]// user 3208 member[3]// duty 3209 member[4]// section 3210 */ 3211 var member=new nas.Pm.Staff(); 3212 member.parseStaff(members[ix]);//文字列としてパースする 不正データの場合は初期化できないのでスキップ 3213 }else{ 3214 var member = members[ix] 3215 } 3216 if(! member) continue; 3217 var checkHint = this.indexOf(member); 3218 //console.log("checkHint : " + checkHint) ; 3219 //一致エントリがないので追加 3220 if (checkHint < 0){ 3221 this.members.push(member); 3222 result ++; 3223 //console.log('push member :'+member.toString('dump')); 3224 continue; 3225 } 3226 } 3227 return result; 3228 } 3229 3230 nas.Pm.staff=new nas.Pm.StaffCollection(nas.Pm); 3231 /*TEST 3232 新設が必要な設定群 3233 ユーザDB 3234 U-AT の場合はサーバから取得 Repository.pmd.users? この管理はサーバに任せて、スタッフだけもらうべき 3235 ローカルストレージ等の 3236 スタッフDB 3237 部門、役職、ユーザを合成したスタッフDB 3238 Repository.pmd.staff ~ タイトル、エピソード、カット(ライン、ステージ)までのツリー状の構造の各所でそれぞれのデータを参照可能にするための構造 3239 3240 nas.Pm.inportDB(settingStream) 3241 3242 DBとの通信は基本的に serviceAgent配下で各ServiceNodeが行う 3243 読み出しは低レベル関数をそれぞれのオブジェクトが受け持ち 3244 設定ファイル読み出しに相当するひとまとまりのアクションを親オブジェクト側で実装する 3245 3246 統一形式 3247 Object.parseConfig(dataStream) 3248 3249 perseStaff等もリネーム 3250 3251 */ 3252