- Timestamp:
- 2010/03/11 10:35:11 (14 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
tmp/version-2_5-test/html/user_data/packages/default/js/layout_design.js
r16708 r18609 2 2 * This file is part of EC-CUBE 3 3 * 4 * Copyright(c) 2000-200 7LOCKON CO.,LTD. All Rights Reserved.4 * Copyright(c) 2000-2008 LOCKON CO.,LTD. All Rights Reserved. 5 5 * 6 6 * http://www.lockon.co.jp/ … … 20 20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 21 21 */ 22 // サイズ管理クラスの定義 23 function SC_Size() { 24 this.id = ''; // ID 25 this.left = 0; // 配置するY軸座標 26 this.top = 0; // 配置するX軸座標 27 this.width = 0; // オブジェクトの幅 28 this.height = 0; // オブジェクトの高さ 29 this.target_id = ''; // 配置場所(左ナビとか) 30 this.margin = 10; // 上のオブジェクトとの幅 31 this.obj; 32 }; 33 34 // 変数宣言 35 var defUnused = 500; // 未使用領域のデフォルトの高さ 36 var defNavi = 400; // 左右ナビのデフォルトの高さ 37 var defMainNavi = 100; // メイン上下のデフォルトの高さ 38 var defMain = 200; // メインのデフォルトの高さ 39 40 var NowMaxHeight = 0; // 現在の最大の高さ 41 var MainHeight = 200; 42 43 var marginUnused = 688; // 未使用領域の左マージン 44 var marginLeftNavi = 180; // 左ナビの左マージン 45 var marginRightNavi = 512; // 右ナビの左マージン 46 var marginMain = 348; // メイン上下の左マージン 47 var marginMainFootTop= 595; // メイン下の上マージン 48 49 var gDragged = ""; // ドラッグ中オブジェクト 50 var gDropTarget = ""; // ドラッグ開始時のDropTarget 51 52 var arrObj = new Object(); // ブロックオブジェクト格納用 53 54 var mouseFlg = false; 55 56 var all_elms; // divタグオブジェクト格納用 57 58 // ウィンドウサイズ 59 var scrX; 60 var scrY; 61 62 // イベントの関連付けを行う 63 function addEvent( elm, evtType, fn, useCapture) { 64 65 if (elm.addEventListener) { 66 elm.addEventListener(evtType, fn, useCapture); 67 return true; 68 69 } 70 else if (elm.attachEvent) { 71 72 var r = elm.attachEvent('on' + evtType, fn); 73 return r; 74 75 } 76 else { 77 elm['on'+evtType] = fn; 78 79 } 22 (function($){ 23 var updateUpDown = function(sortable){ 24 $('div:not(.ui-sortable-helper)', sortable) 25 .removeClass('first') 26 .filter(':first').addClass('first').end() 27 .children('input.target-id').val(sortable.id).end() 28 .each(function(){ 29 var top = $(this).prevAll().length + 1; 30 $(this).children('input.top').val(top); 31 }); 32 }; 80 33 81 } 82 83 84 // イベントの関連付けを解除 85 function removeEvent( elm, evtType, fn, useCapture) { 86 87 if (elm.removeEventListener) { 88 89 elm.removeEventListener(evtType, fn, useCapture); 90 return true; 91 92 } 93 else if (elm.detachEvent) { 94 95 var r = elm.detachEvent('on' + evtType, fn); 96 return r; 97 98 } 99 else { 100 101 elm['on'+evtType] = fn; 102 103 } 104 105 } 106 107 // マウスカーソルを変更 108 function setCursor ( elm, curtype ) { 109 elm.style.cursor = curtype; 110 } 111 112 // オブジェクトの透明度を変更 113 function setOpacity(node,val) { 114 115 if (node.filters) { 116 node.filters["alpha"].opacity = val*100; 117 } else if (node.style.opacity) { 118 node.style.opacity = val; 119 } 120 } 121 122 // Zindexを変更する(前面表示切替) 123 function setZindex(node, val) { 124 node.style.zIndex = val; 125 // alert(val); 126 } 127 128 // 値を取得 129 function getAttrValue ( elm, attrname ) { 130 131 if (typeof(elm.attributes[ attrname ]) != 'undefined') { 132 return elm.attributes[ attrname ].nodeValue; 133 } 134 135 /* 136 // if (typeof(elm.attributes.getNamedItem(attrname)) != 'object'){ 137 val = ""; 138 if((typeof ScriptEngineMajorVersion)=='function') 139 { 140 if( Math.floor(ScriptEngineMajorVersion()) == 5 && 141 navigator.userAgent.indexOf("Win")!=-1) //win-e5対応 142 { 143 val = elm.attributes.item(attrname) 144 } 145 else 146 { 147 val = elm.attributes.getNamedItem(attrname) 148 } 149 } else { 150 val = elm.attributes.getNamedItem(attrname) 151 } 152 153 alert(val.value); 154 155 return val.value; 156 // } 157 */ 158 } 159 160 // 値をセット 161 function setAttrValue ( elm, attrname, val ) { 162 elm.attributes[ attrname ].nodeValue = val; 163 } 164 165 // オブジェクトのX座標を取得 166 function getX ( elm ) { 167 // return parseInt(elm.style.left); 168 return parseInt(elm.offsetLeft); 169 } 170 171 // オブジェクトのY座標を取得 172 function getY ( elm ) { 173 return parseInt(elm.offsetTop); 174 // return parseInt(elm.style.top); 175 } 176 177 // X座標を取得 178 function getEventX ( evt ) { 179 return evt.clientX ? evt.clientX : evt.pageX; 180 } 181 182 // Y座標を取得 183 function getEventY ( evt ) { 184 return evt.clientY ? evt.clientY : evt.pageY; 185 } 186 187 // オブジェクトの幅を取得 188 function getWidth ( elm ) { 189 return parseInt( elm.style.width ); 190 } 191 192 // オブジェクトの高さを取得 193 function getHeight ( elm ) { 194 // return parseInt( elm.style.height ); 195 return parseInt( elm.offsetHeight ); 196 } 197 198 // ページの可視領域のX座標を取得する 199 function getPageScrollX() 200 { 201 var x = 0; 202 203 if (document.body && document.body.scrollLeft != null) { 204 x = document.body.scrollLeft; 205 } else if (document.documentElement && document.documentElement.scrollLeft != null) { 206 x = document.documentElement.scrollLeft; 207 } else if (window.scrollX != null) { 208 x = window.scrollX; 209 } else if (window.pageXOffset != null) { 210 x = window.pageXOffset; 211 } 212 213 return x; 214 } 215 216 // ページの可視領域のY座標を取得する 217 function getPageScrollY() 218 { 219 var y = 0; 220 221 if (document.body && document.body.scrollTop != null) { 222 y = document.body.scrollTop; 223 } else if (document.documentElement && document.documentElement.scrollTop != null) { 224 y = document.documentElement.scrollTop; 225 } else if (window.scrollY != null) { 226 y = window.scrollY; 227 } else if (window.pageYOffset != null) { 228 y = window.pageYOffset; 229 } 230 231 return y; 232 } 233 234 235 // オブジェクトの座標をセット 236 function moveElm ( elm, x, y ) { 237 elm.style.left = x + 'px'; 238 elm.style.top = y + 'px'; 239 } 240 241 // マウスダウンイベント 242 function onMouseDown (evt) { 243 244 var target = evt.target ? evt.target : evt.srcElement; 245 var x = getEventX ( evt ); 246 var y = getEventY ( evt ); 247 248 // 249 // Save Information to Globals 250 // 251 if (mouseFlg == false) { 34 var sortableUpdate = function(e, ui){ 35 updateUpDown(this); 36 if(ui.sender) 37 updateUpDown(ui.sender[0]); 38 }; 252 39 253 gDragged = target; 254 255 gDeltaX = x - getX(gDragged); 256 gDeltaY = y - getY(gDragged); 257 258 gDraggedId = getAttrValue ( gDragged, 'did' ); 259 setCursor ( gDragged, 'move' ); 260 261 gOrgX = getX ( gDragged ); 262 gOrgY = getY ( gDragged ); 263 gtarget_id = getAttrValue ( gDragged, 'target_id' ); 264 265 // 266 // Set 267 // 268 269 // ドラッグ中は半透明 270 setOpacity ( gDragged, 0.6 ); 271 272 // ドラッグ中は最前面表示 273 setZindex ( gDragged , 2); 274 275 addEvent ( document, 'mousemove', onMouseMove, false ); 276 addEvent ( document, 'mouseup', onMouseUp, false ); 277 278 // ドラッグを開始したときは高さを一度初期化する。 279 NowMaxHeight = defNavi; 280 281 mouseFlg = true; 282 } 283 } 284 285 286 // マウスムーブイベント 287 function onMouseMove(evt) { 288 289 // 現在の座標を取得 290 var x = getEventX ( evt ) + document.body.scrollLeft; // マウス座標 X 291 var y = getEventY ( evt ) + document.body.scrollTop; // マウス座標 Y 292 var nowleft = getEventX ( evt ) - gDeltaX; // オブジェクト座標 LEFT 293 var nowtop = getEventY ( evt ) - gDeltaY; // オブジェクト座標 TOP 294 295 // オブジェクトを移動 296 moveElm ( gDragged, nowleft, nowtop ); 297 298 for ( var i = 0; i < all_elms.length; i++ ) { 299 // drop_target上にきた場合にのみ処理を行う 300 if ( isEventOnElm ( evt, all_elms[i].id ) ) { 301 if ( all_elms[i].attributes['tid'] ) { 302 var tid = getAttrValue ( all_elms[i], 'tid' ); 303 304 // 背景色の変更 未使用領域は変更しない 305 all_elms[i].style.background="#ffffdd"; 306 307 // target_id の書き換え 308 setAttrValue ( gDragged, 'target_id', tid ); 309 310 //objCheckLine.style.top = parseInt(nowtop) + parseInt(gDragged.style.height) / 2 + 'px'; 311 //objCheckLine.style.top = y; 312 313 // 配列の再作成 314 fnCreateArr(1, y, x); 315 // 配列の並び替え 316 fnChangeObj(tid); 317 } 318 }else{ 319 if ( all_elms[i].attributes['tid'] && all_elms[i].style.background!="#ffffff") { 320 // 背景色の変更 321 all_elms[i].style.background="#ffffff"; 322 } 323 } 324 } 325 } 326 327 // マウスアップイベント 328 function onMouseUp(evt) { 329 // イベントの関連付け解除 330 if (mouseFlg == true) { 331 removeEvent ( document, 'mousemove', onMouseMove, false ); 332 removeEvent ( document, 'mouseup', onMouseUp, false ); 333 mouseFlg = false; 334 } 335 336 if ( !isOnDropTarget (evt) ) { 337 // 元の位置に戻す 338 moveElm ( gDragged, gOrgX, gOrgY ); 339 setAttrValue ( gDragged, 'target_id', gtarget_id ); 340 341 // 配列の再作成 342 fnCreateArr(1, gOrgY, gOrgX); 343 } 40 $(document).ready(function(){ 41 var els = ['#MainHead', '#MainFoot', '#LeftNavi', '#RightNavi', '#TopNavi', '#BottomNavi', '#HeadNavi', '#HeaderTopNavi', '#FooterBottomNavi', '#Unused']; 42 var $els = $(els.toString()); 43 44 $els.each(function(){ 45 updateUpDown(this); 46 }); 47 48 $els.sortable({ 49 items: '> div', 50 //handle: 'dt', 51 cursor: 'move', 52 //cursorAt: { top: 2, left: 2 }, 53 //opacity: 0.8, 54 //helper: 'clone', 55 appendTo: 'body', 56 placeholder: 'clone', 57 placeholder: 'placeholder', 58 connectWith: els, 59 start: function(e,ui) { 60 ui.helper.css("width", ui.item.width()); 61 }, 62 //change: sortableChange, 63 update: sortableUpdate 64 }); 65 }); 344 66 345 // hidden要素の書き換え 346 var did = getAttrValue( gDragged, 'did' ); 347 var target_id = "target_id_"+did; 348 document.form1[target_id].value = getAttrValue( gDragged, 'target_id' ); 349 350 // 半透明、マウスポインタ、最前面処理を戻す 351 setOpacity( gDragged, 1); 352 setCursor ( gDragged, 'move' ); 353 setZindex ( gDragged , 1); 354 355 // 並び替え 356 fnSortObj(); 357 358 // 背景色を戻す 359 for ( var i = 0; i < all_elms.length; i++ ) { 360 // drop_target上にきた場合にのみ処理を行う 361 if ( isEventOnElm ( evt, all_elms[i].id ) && all_elms[i].attributes['tid']) { 362 // 背景色の変更 363 all_elms[i].style.background="#ffffff"; 364 } 365 } 366 } 367 368 // DropTarget上にオブジェクトが来たかを判断する 369 function isOnDropTarget ( evt ) { 370 371 for ( var i=0; i<all_elms.length; i++ ) { 372 if ( isEventOnElm ( evt, all_elms[i].id ) ) { 373 if ( all_elms[i].attributes['tid'] ) { 374 return true; 375 } 376 } 377 } 378 return false; 379 } 380 function isEventOnElm (evt, drop_target_id) { 381 382 if (drop_target_id == '') { 383 return ''; 384 } 385 386 var evtX = getEventX(evt) + getPageScrollX(); 387 var evtY = getEventY(evt) + getPageScrollY(); 388 389 var drop_target = document.getElementById( drop_target_id ); 390 391 drp_left = getX( drop_target ); 392 drp_top = getY( drop_target ); 393 394 var x = drp_left; 395 var y = drp_top; 396 397 var width = getWidth ( drop_target ); 398 var height = getHeight ( drop_target ); 399 400 // alert(evtX +" / "+ x +" / "+ evtY +" / "+ y +" / "+ width +" / "+ height); 401 402 return evtX > x && evtY > y && evtX < x + width && evtY < y + height; 403 } 404 405 // オブジェクトの並び替えを行う 406 function fnSortObj(){ 407 fnSetTargetHeight(); 408 for ( var cnt = 0; cnt < all_elms.length; cnt++ ) { 409 410 // classが drop_target の場合のみ処理を行う 411 if ( getAttrValue ( all_elms[cnt], 'class' ) == 'drop_target' ) { 412 var tid = getAttrValue ( all_elms[cnt], 'tid' ); 413 414 // 配列の並び替え 415 fnChangeObj(tid); 416 417 // 配置 418 fnSetObj( tid, cnt ); 419 } 420 } 421 } 422 423 function alerttest(msg, x, y){ 424 alert(msg); 425 } 426 427 // 配列の作成 428 function fnCreateArr( addEvt , top , left ){ 429 430 var arrObjtmp = new Object(); 431 arrObjtmp['LeftNavi'] = Array(); 432 arrObjtmp['RightNavi'] = Array(); 433 arrObjtmp['MainHead'] = Array(); 434 arrObjtmp['MainFoot'] = Array(); 435 arrObjtmp['Unused'] = Array(); 436 437 for ( var i = 1; i < all_elms.length; i++ ) { 438 // classが dragged_elm の場合のみ処理を行う 439 if ( getAttrValue ( all_elms[i], 'class' ) == 'dragged_elm' ) { 440 441 // マウスダウンイベントと関連付けを行う 442 if (addEvt == 0) { 443 addEvent ( all_elms[i], 'mousedown', onMouseDown, false ); 444 } 445 446 var target_id = getAttrValue ( all_elms[i], 'target_id' ); 447 var len = arrObjtmp[target_id].length; 448 var did = getAttrValue ( all_elms[i], 'did' ); 449 450 arrObjtmp[target_id][len] = new SC_Size(); 451 arrObjtmp[target_id][len].id = did; 452 arrObjtmp[target_id][len].obj = all_elms[i]; 453 arrObjtmp[target_id][len].width = getWidth( all_elms[i] ); 454 arrObjtmp[target_id][len].height = getHeight( all_elms[i] ); 455 456 // ドラッグ中のオブジェクトが存在すれば、そのオブジェクトだけマウスポインタの座標を指定する。 457 if (gDragged != "") { 458 if (did != getAttrValue ( gDragged, 'did' )) { 459 // top は常にオブジェクトの中心を取得するようにする 460 arrObjtmp[target_id][len].top = (parseInt(getY( all_elms[i] )) + arrObjtmp[target_id][len].height / 2 ); 461 arrObjtmp[target_id][len].left = getX( all_elms[i] ); 462 }else { 463 arrObjtmp[target_id][len].top = top; 464 arrObjtmp[target_id][len].left = left; 465 } 466 } else { 467 // top は常にオブジェクトの中心を取得するようにする 468 arrObjtmp[target_id][len].top = i; 469 arrObjtmp[target_id][len].left = getX( all_elms[i] ); 470 } 471 } 472 } 473 474 arrObj = arrObjtmp; 475 } 476 477 // 配列の並び替え (バブルソートで並び替えを行う) 478 function fnChangeObj( tid ){ 479 for ( var i = 0; i < arrObj[tid].length-1; i++ ) { 480 for ( var j = arrObj[tid].length-1; j > i; j-- ) { 481 if ( arrObj[tid][j].top < arrObj[tid][i].top ) { 482 var arrTemp = new Array(); 483 arrTemp = arrObj[tid][j]; 484 arrObj[tid][j] = arrObj[tid][i]; 485 arrObj[tid][i] = arrTemp; 486 } 487 } 488 } 489 } 490 491 // 配置 492 function fnSetObj( tid, cnt ){ 493 var target_height = 0; 494 495 drp_left = getX(all_elms[cnt]); //all_elms[cnt].offsetLeft; 496 drp_top = getY(all_elms[cnt]); //all_elms[cnt].offsetTop; 497 498 for ( var j = 0; j < arrObj[tid].length; j++ ) { 499 // 配置する座標の取得 500 var left = parseInt(drp_left) + parseInt(all_elms[cnt].style.width) / 2 - parseInt(arrObj[tid][j].width) / 2; 501 if (j == 0){ 502 var top = drp_top + arrObj[tid][j].margin; 503 }else{ 504 var top = arrObj[tid][j-1].top + arrObj[tid][j].margin + arrObj[tid][j-1].height 505 } 506 507 // 座標を保持 508 arrObj[tid][j].top = top; 509 arrObj[tid][j].left = left; 510 511 // 配置を行う 512 moveElm ( arrObj[tid][j].obj, left ,top); 513 514 // 高さ計算 515 target_height = target_height + arrObj[tid][j].margin + arrObj[tid][j].height; 516 517 // hiddenの値を書き換え 518 var top_id = "top_" + arrObj[tid][j].id; 519 document.form1[top_id].value = top; 520 521 } 522 } 523 524 // ドロップターゲットの高さ調整 525 function fnSetTargetHeight(){ 526 527 var NaviHeight = defNavi; 528 var MainHeadHeight = defMainNavi; 529 var MainFootHeight = defMainNavi; 530 var UnusedHeight = defUnused; 531 532 // 高さ計算 533 for ( var cnt = 0; cnt < all_elms.length; cnt++ ) { 534 var target_height = 0; 535 536 // classが drop_target の場合のみ処理を行う 537 if ( getAttrValue ( all_elms[cnt], 'class' ) == 'drop_target' ) { 538 var tid = getAttrValue ( all_elms[cnt], 'tid' ); 539 540 for ( var j = 0; j < arrObj[tid].length; j++ ) { 541 target_height = target_height + arrObj[tid][j].margin + arrObj[tid][j].height; 542 } 543 544 // 下の幅 545 target_height = target_height + 20; 546 547 // 左右ナビ、未使用領域の高さを保持 548 if (tid == 'LeftNavi' || tid == 'RightNavi' || tid == 'Unused') { 549 if (NaviHeight < target_height) { 550 NaviHeight = target_height; 551 } 552 } 553 554 // メイン上部領域の高さを保持 555 if (tid == 'MainHead') { 556 if (target_height > defMainNavi) { 557 MainHeadHeight = target_height; 558 } 559 } 560 561 // メイン下部領域の高さを保持 562 if (tid == 'MainFoot') { 563 if (target_height > defMainNavi) { 564 MainFootHeight = target_height; 565 } 566 } 567 } 568 } 569 570 // メイン領域の高さを保持 571 // alert(NaviHeight+"/"+MainHeadHeight+"/"+MainFootHeight); 572 MainHeight = NaviHeight - ( MainHeadHeight + MainFootHeight ); 573 if (MainHeight < defMain) { 574 MainHeight = defMain; 575 } 576 577 // メイン部分のほうが大きい場合には左右ナビも大きくする 578 if (NaviHeight < MainHeadHeight + MainFootHeight + MainHeight) { 579 NaviHeight = MainHeadHeight + MainFootHeight + MainHeight; 580 } 581 // 変更 582 for ( var cnt = 0; cnt < all_elms.length; cnt++ ) { 583 var target_height = 0; 584 585 // classが drop_target の場合のみ処理を行う 586 if ( getAttrValue ( all_elms[cnt], 'class' ) == 'drop_target' ) { 587 var tid = getAttrValue ( all_elms[cnt], 'tid' ); 588 589 // tidによって処理を分ける 590 if (tid == 'LeftNavi' || tid == 'RightNavi') { 591 target_height = NaviHeight; 592 }else if (tid == 'MainHead' ) { 593 target_height = MainHeadHeight; 594 }else if (tid == 'MainFoot') { 595 target_height = MainFootHeight; 596 }else if (tid == 'Unused'){ 597 target_height = NaviHeight+100; 598 } 599 600 all_elms[cnt].style.height = target_height; 601 } 602 } 603 604 // メインテーブルの高さも変更 605 for (var i = 0; i < all_td.length; i++) { 606 name = getAttrValue ( all_td[i], 'name' ); 607 if (name == 'Main') { 608 all_td[i].height = MainHeight-2; 609 } 610 } 611 } 612 613 //ウインドウサイズ取得 614 function GetWindowSize(type){ 615 var ua = navigator.userAgent; // ユーザーエージェント 616 var nWidth, nHeight; // サイズ 617 var nHit = ua.indexOf("MSIE"); // 合致した部分の先頭文字の添え字 618 var bIE = (nHit >= 0); // IE かどうか 619 var bVer6 = (bIE && ua.substr(nHit+5, 1) == "6"); // バージョンが 6 かどうか 620 var bStd = (document.compatMode && document.compatMode=="CSS1Compat"); // 標準モードかどうか 621 622 switch(type){ 623 case "width": 624 if(bIE){ 625 if (bVer6 && bStd) { 626 return document.documentElement.clientWidth; 627 } else { 628 return document.body.clientWidth; 629 } 630 }else if(document.layers){ 631 return(innerWidth); 632 }else{ 633 return(-1); 634 } 635 break; 636 case "height": 637 if(bIE){ 638 if (bVer6 && bStd) { 639 return document.documentElement.clientHeight; 640 } else { 641 return document.body.clientHeight; 642 } 643 return(document.body.clientHeight); 644 }else if(document.layers){ 645 return(innerHeight); 646 }else{ 647 return(-1); 648 } 649 break; 650 default: 651 return(-1); 652 break; 653 } 654 } 655 656 // ウィンドウサイズが変更になったときは全てのオブジェクトも移動する 657 function fnMoveObject() { 658 659 // ウィンドウの幅変更比率を取得 660 var moveX = GetWindowSize("width") - scrX; 661 var BlankX = ( GetWindowSize("width") - 878 ) / 2 662 663 for ( var i = 0; i < all_elms.length; i++) { 664 if (all_elms[i].style.left != "" ) { 665 666 var elm_class = getAttrValue ( all_elms[i], 'class' ); 667 668 if (elm_class == 'drop_target') { 669 var tid = getAttrValue ( all_elms[i], 'tid' ); 670 671 if (tid == 'LeftNavi') { 672 LeftMargin = marginLeftNavi; 673 }else if (tid == 'RightNavi') { 674 LeftMargin = marginRightNavi; 675 }else if (tid == 'MainHead' || tid == 'MainFoot') { 676 LeftMargin = marginMain; 677 }else{ 678 LeftMargin = marginUnused; 679 } 680 681 if (BlankX > 0) { 682 all_elms[i].style.left = BlankX + LeftMargin + 'px'; 683 }else{ 684 all_elms[i].style.left = LeftMargin + 'px'; 685 } 686 } 687 } 688 } 689 690 scrX = GetWindowSize("width"); 691 scrY = GetWindowSize("height"); 692 693 fnSortObj(); 694 } 695 // 画面のロードイベントに関連付け 696 addEvent ( window, 'load', init, false ); 67 $(window).bind('load',function(){ 68 setTimeout(function(){ 69 $('#overlay').fadeOut(function(){ 70 $('body').css('overflow', 'auto'); 71 }); 72 }, 750); 73 }); 74 })(jQuery);
Note: See TracChangeset
for help on using the changeset viewer.