2013. 11. 27.

HTML 레이어(layer). div 특정 위치에 겹쳐 띄우기. absolute와 relative 값 차이.

  공지사항이나 전달사항을 알리는데 창을 띄워서 팝업창을 사용할 수 있고, 한 화면 내에서 조그맣게 레이어(layer) 형식으로 필요한 정보를 전달 할 수도 있습니다. 허나 요즘은 창을 새로 띄우는 형식의 팝업창은 잘 사용되지 않죠. 브라우저 내의 팝업 차단 기능도 그렇고, 실제로 그다지 관심도 없는데 창이 무자비하게 뜨면 불괘하기도 합니다.

  레이어 라는 단어는 겹쳐서 포갠다는 느낌이 강하게 드네요. 이미지 편집툴을 사용할때도 정말 많이 접하게 되는게 레이어 입니다. HTML에서도 layer 태그가 있었습니다만, HTML5 에서부터 사용이 권장 되지 않습니다. 이런걸 Deprecated 됐다고 하지요.

  div 태그를 이용해서 원하는 위치에 레이어처럼 나타내 보도록 하겠습니다. div 태그의 style 속성 값에서 position, left, top, width, height 이 다섯가지만 있으면 원하는 곳 어디든 레이어를 띄워 줄 수 있습니다.

  position 값으로 다섯가지를 줄 수 있지만, absoluterelative 만 사용해도 무방 합니다.
  left 값은 왼쪽을 기준으로 얼마만큼 떨어져 있는가를 나타내는 값 입니다.
  top은 left 처럼 위에서 얼마나 떨어뜨리는가를 나타냅니다.
  width 값은 div 의 가로 크기, height는 div의 세로 크기를 의미 합니다.

  예제로 확인해 보도록 하겠습니다. 코드 하이라이트를 써서, 소스를 긁어 갈 수 있도록 하려고 했으나... 오늘따라 소스 처리 하는데 뭔가 애로사항이 많네요. 해당 소스 파일을 첨부 하려고 했는데 블로그스팟은 파일 첨부를 할 수 없는건가요; 허허.


  여기서는 position 값 absolute와 relative 두 가지만 눈 여겨 보시면 될듯 합니다. 부모 div와 자식 div가 있고, 자식 div 들의 position 값을 다르게 줘 봤습니다. 아래 결과 사진 캡처를 확인해 보시면 바로 아실 수 있으실꺼라 생각 합니다.



  absolute와 relative 속성 차이가 자식 div의 위치는 변경 시키진 않았지만, 부모 div의 내용물의 위치가 차이가 있네요. 오른쪽의 부모 div 3의 공란의 높이가 자식 div의 높이와 일치해 보입니다. 이제 대충 감이 오네요. position 속성의 값을 relative 로 두게 되면, 자식 div가 부모 div내에서 공간을 차지하게 됩니다. 그려내고자 하는 그림에 맞게 적절하게 써주면 되겠습니다.

  아참, 중요한 설명 하나를 빼먹었습니다. div style 속성 값중 z-index 라는 항목이 있는데요. 이 값은 div들 끼리 겹쳤을때 어떤 div를 위에 보여주기 위해 올리고, 어떤 div를 아래에 보여주기 위해 내리는지를 나타내는 값입니다. 이 값이 큰 div가 가장 위로 올라와서 브라우저에 보이는 div가 됩니다. 예제에서 div1과 3은 z-index 값이1, div2와 4는 z-index 값이 2로 설정 되어 있습니다. div2와 4의 z-index값이 부모 값 보다 크니 부모의 위에 나오게 되는 거겠죠. 작으면 부모 div에 가려져셔 보이지 않게 됩니다.


* 참조 사이트 링크
div tag
http://www.w3schools.com/tags/tag_div.asp
z-index
http://www.w3schools.com/cssref/pr_pos_z-index.asp

2013. 11. 26.

심플한 랜덤 지역별 채팅 어플. 즐거운 채팅 즐챗.


즐거운 채팅 즐챗은 간단하게 사용 할 수 있는 깔끔한 무작위 채팅 어플(앱) 입니다. 기본적으로 전체 지역이 설정 되어 채팅이 되며, 채팅 하고자 하는 지역을 선택하여 무작위 채팅을 시작 할 수도 있습니다.  상대방을 배려하는 대화, 매너있는 대화로 즐거운 대화를 만들어 갑시다.

* 상대방에게 사진을 전송하는 기능은 의도되지 않은 방향으로 사용 될 수 있어 추가할 계획이 없습니다.
* 대화하는 동안 모든 내용은 암호화 되어 처리되며 대화 종료나 앱을 종료 할 때 모두 삭제 처리 됩니다.
* 즐거운 채팅 즐챗은 스마트 기기의 고유값으로 사용자를 구분 합니다.
* 그 외 다른 개인정보는 일절 수집하거나 사용하지 않습니다.


# 구글 플레이 링크
https://play.google.com/store/apps/details?id=com.damnation.KINchat&hl=ko

# 검색 키워드
채팅, 랜덤채팅, 랜덤 채팅, 지역별채팅, 지역별 채팅, 만남, 무작위 채팅, 대화

# 스크린샷



2013. 11. 25.

(안드로이드, 아이폰 등) 스마트폰 모바일 접속 구분 소스 코드 모음.

안드로이드나 아이폰 등 모바일 기기의 브라우저 에서 접속한 사용자에게 PC용 웹페이지가 아닌 모바일 전용 페이지를 보여주는 게 상대적으로 작은 화면의 스마트기기엔 효과적일 것입니다.

모바일 환경에서 접속한 것인지 PC 환경인지 구분해주는 코드들은 잠깐 시간을 투자해 검색해보면 그리 어렵지 않게 구할 수 있습니다. 하지만 웹페이지들은 다양한 프로그래밍 언어로 제작되고,  다양한 언어의 웹페이지들을 운영하고 계신 경우라면 해당 언어에 맞는 코드를 찾는 게 나름 귀찮기도 하고 골치가 아플 때가 있습니다. 언어 별로 모바일과 PC를 구분해주는 코드를 제공해주는 편한 사이트에 어쩌다가 닿게 됐는데 정말 만족스럽더군요.
http://detectmobilebrowsers.com/

메인 페이지를 보면 여러가지 언어들의 아이콘들이 있습니다. 원하는 언어를 클릭해 보시면 텍스트(txt) 파일을 다운로드 할 수 있습니다. 모바일 환경을 판단 해주는 코드인데요. 적당한 곳에 복사해 넣기만 하면 됩니다.

코드를 보시면 마지막 부분에 http://detectmobilebrowser.com/mobile 이렇게 주소가 나와 있는데, 이 주소를 적당하게 자신에 맞게 변경해 주시면 됩니다. 기본적으로 모바일 환경일 때 페이지 이동에 대한 동작만 합니다. 다른 추가적인 작업이 필요하신 분은 필요에 맞게 수정하시면 될 듯 합니다.

자바스크립트의 객체를 반복문(for)으로 필드들 값 출력 해보기.

다른 프로그래밍 언어와 다르게 자바스크립트는 class문이 없는 프로토타입 기반의 언어입니다. 자바나 PHP에서 처럼 객체 정의하고 사용 하는데 익숙한 분들은 아마 저처럼 햇갈려 하시지 않을까 하는 생각이 듭니다. 자바스크립트 문법이 아직 익숙하지 않아 객체 관련해서 코드를 보는데 애를 좀 먹었습니다. 사실 객체니 뭐니 해봤자 변수와 함수들 모아놓은게 객체 일 뿐이니 간단하고 쉽게 생각 합시다.

객체를 생성하는데 여러가지 방법이 있습니다. 아무래도 자세히 알려면 책을 한 권 구입 해야할 것 같네요. 여기선 포스팅 제목처럼 객체 내 필드들의 값을 찍어 보는 방법에 대해서만 알아 보도록 합시다.

var o = {
    r: 'some value',
    t: 'some other value'
};

var o = new Object();
o.r = 'some value';
o.t = 'some other value';

동일한 객체를 만드는 두 가지 방법 입니다. 좀 더 찾아보니 객체 생성하는 방법들 부터 다양한게 머리가 지끈 지끈 하네요... 객체 내부를 돌아다니는 문법은 자바(Java)에서 향상된 for문 이라고 불리는 구문과 왠지 닮아 보입니다.

//Java 향상된 for 문
for( String name : nameArray ){
    System.out.println( name );
}

nameArray[1]을 name에 대입시켜서 반복문이 한 번 돌아가고, nameArray[2]를 name에 대입시켜서 또 반복문이 한 번 돌아가고 이렇게 배열의 끝까지 탐색 합니다. 자바스크립트에서도 이와 비슷한 느낌의 구문이 있네요. 물론 배열을 탐색하는 것과 객체 내 필드들을 탐색 하는 것은 다르긴 하지만, 자바스크립트가 워낙 그런 경계들이 애매모호한 느낌이라... 저만 그렇게 느끼는 건가요!? 아무튼...

for (myKey in myObj){
    alert ("myObj["+myKey +"] = "+myObj[myKey]);
}

myObj 객체 안의 녀석들을 myKey에 하나씩 담아 줍니다. 녀석이라고 표현한 이유는 저기서 받아오는 myObj는 단순한 변수 일수도 있고, 함수 이기도 하고 다른 객체 일 수도 있어서 딱히 무엇이라고 할 수가 없네요. 역시 경계선이 애매모호 합니다.


스택오버플로우 출처.
http://stackoverflow.com/questions/418799/what-does-colon-do-in-javascript

PHP 양력 날짜를 음력 날짜로 변환해주는 함수.

달력에 보면 조그맣게 음력 날짜가 표시되어 있습니다. 우리나라도 아직까지 음력으로 생일이나 기념일을 하시는 분들이 많이 계시죠. 음력에 대한 지식이 전무했던 지라... 전 그저 양력을 음력으로 변환해 주는 함수가 존재하고 양력 날짜 인수만 갖다 넣으면 음력 날짜가 뿅! 하고 나올 줄만 알았습니다. :-(

제가 원했던 것은 20131125 라는 양력 날짜를 넣으면 20131023 이란 음력 날짜를 반환해주는 함수였을 뿐인데... 이게 간단한 문제가 아닌거 같더군요. 양력을 음력으로 바꾸는데는 간단한 수식으로 해결 할 수가 없다고 합니다. 천체의 운행을 기법으로 하는.... 뭐...

이것저것 함수들을 찾아보니 일정 기간의 음력을 데이터베이스 처럼 입력해 놓고 처리하는 방식이고, 특정 년도 이전까지만 유효하게끔 되어 있습니다. 그 만큼 골치아프고 어려운가 봅니다... 게다가 양/음력 날짜를 변환해주는 웹페이지들도 있던데 변환 시 날짜가 아주 엉망으로 나오는 곳도 한 두 군데가 아니더군요.

습관처럼 구글에서 영어로 검색을 한참동안 했는데, 검색을 하면 할 수록 감이 더 안잡히는 불상사가 발생 합니다. 음력이라기에 lunar date 란 검색어로, 양력은 solar date 검색어로 이리저리 찾아봤습니다만... islamic calendar(이슬람 달력)과 chinese calendar(중국 달력) 이 연관되서 나오기 시작하고, Gregorian 날짜와 Julian 날짜 뭐... 하하... 이슬람력이 중국으로 그리고 우리나라로 온 것 같고...

깊은 절망에 빠져들게 만들었던 검색결과의 링크들 입니다.
현재 시간을 Lunar Standard Time 으로 바꿔 줍니다. 46-09-16은 도무지 무슨 날짠지 모르겠네요...
http://random.kakaopor.hu/lunar-date-function-for-php-time-on-the-moon-lst
http://lunarclock.org/convert-to-lunar-standard-time.php

해당 날짜에 맞는 달의 상태를 계산에 줍니다. 보름달인지 반달인지 그런거요. 밑에 것도...
http://jivebay.com/calculating-the-moon-phase/
http://www.phpclasses.org/package/1201-PHP-Calculates-the-phase-of-the-Moon.html

위에서 말한 Gregorian, Julian 녀석들 자바스크립트 라이브러린듯 합니다.
http://stackoverflow.com/questions/12637268/convert-julian-date-to-solar-date-in-javascript
http://jesusnjim.com/common/julian-gregorian.html#tog


영혼 없는 검색질 중 문득 든 생각이 한국어페이지로 검색 하는게 더 나을꺼 같다는 생각이 들더군요. 한국어 웹페이지를 검색하니, 답이 보이기 시작 합니다. 동일한 소스를 여러곳에서 찾았는데 아무리 봐도 해당 블로그는 소스 출처가 아닌 것 같더군요. 긁어서 붙여넣은 모습이 보여서 해당 소스의 출처는 찾질 못했습니다. 혹시 출처를 아시는 분 계시면 알려 주시면 바로 반영 하도록 하겠습니다.

잡소리가 엄청나게 길었네요. 아래 소스를 적당하게 붙여넣으시고 사용하시면 됩니다. 벽에 걸려있는 달력이랑 비교해보니 잘 맞게 나오더라구요. 만족 합니다. 반환되는 객체의 time 필드가 time() 함수를 호출 했을때 반환 값 형식인 timestamp 인듯 합니다. date() 함수로 포멧을 주고 변환해주면 음력 날짜를 간단하게 얻을 수 있습니다.

<?
function sunlunar_data() {
return
"1212122322121-1212121221220-1121121222120-2112132122122-2112112121220-2121211212120-2212321121212-2122121121210-2122121212120-1232122121212-1212121221220-1121123221222-1121121212220-1212112121220-2121231212121-2221211212120-1221212121210-2123221212121-2121212212120-1211212232212-1211212122210-2121121212220-1212132112212-2212112112210-2212211212120-1221412121212-1212122121210-2112212122120-1231212122212-1211212122210-2121123122122-2121121122120-2212112112120-2212231212112-2122121212120-1212122121210-2132122122121-2112121222120-1211212322122-1211211221220-2121121121220-2122132112122-1221212121120-2121221212110-2122321221212-1121212212210-2112121221220-1231211221222-1211211212220-1221123121221-2221121121210-2221212112120-1221241212112-1212212212120-1121212212210-2114121212221-2112112122210-2211211412212-2211211212120-2212121121210-2212214112121-2122122121120-1212122122120-1121412122122-1121121222120-2112112122120-2231211212122-2121211212120-2212121321212-2122121121210-2122121212120-1212142121212-1211221221220-1121121221220-2114112121222-1212112121220-2121211232122-1221211212120-1221212121210-2121223212121-2121212212120-1211212212210-2121321212221-2121121212220-1212112112210-2223211211221-2212211212120-1221212321212-1212122121210-2112212122120-1211232122212-1211212122210-2121121122210-2212312112212-2212112112120-2212121232112-2122121212110-2212122121210-2112124122121-2112121221220-1211211221220-2121321122122-2121121121220-2122112112322-1221212112120-1221221212110-2122123221212-1121212212210-2112121221220-1211231212222-1211211212220-1221121121220-1223212112121-2221212112120-1221221232112-1212212122120-1121212212210-2112132212221-2112112122210-2211211212210-2221321121212-2212121121210-2212212112120-1232212122112-1212122122120-1121212322122-1121121222120-2112112122120-2211231212122-2121211212120-2122121121210-2124212112121-2122121212120-1212121223212-1211212221220-1121121221220-2112132121222-1212112121220-2121211212120-2122321121212-1221212121210-2121221212120-1232121221212-1211212212210-2121123212221-2121121212220-1212112112220-1221231211221-2212211211220-1212212121210-2123212212121-2112122122120-1211212322212-1211212122210-2121121122120-2212114112122-2212112112120-2212121211210-2212232121211-2122122121210-2112122122120-1231212122212-1211211221220-2121121321222-2121121121220-2122112112120-2122141211212-1221221212110-2121221221210-2114121221221";
}

function SolaToLunar($yyyymmdd) {
$getYEAR = substr($yyyymmdd,0,4);
$getMONTH = substr($yyyymmdd,4,2);
$getDAY = substr($yyyymmdd,6,2);

$arrayDATASTR = sunlunar_data();
$arrayDATA = explode("-",$arrayDATASTR);
$arrayLDAYSTR="31-0-31-30-31-30-31-31-30-31-30-31";
$arrayLDAY = explode("-",$arrayLDAYSTR);
$dt = $arrayDATA;



for ($i=0;$i<=168;$i++) {
  $dt[$i] = 0;
  for ($j=0;$j<12;$j++) {
    switch (substr($arrayDATA[$i],$j,1)) {

    case 1:
      $dt[$i] += 29;
      break;

    case 3:
      $dt[$i] += 29;
      break;

    case 2:
      $dt[$i] += 30;
      break;

    case 4:
      $dt[$i] += 30;
      break;
    }
  }

  switch (substr($arrayDATA[$i],12,1)) {

  case 0:
    break;

  case 1:
    $dt[$i] += 29;
    break;

  case 3:
    $dt[$i] += 29;
    break;

  case 2:
    $dt[$i] += 30;
    break;

  case 4:
    $dt[$i] += 30;
    break;
  }
}

$td1 = 1880 * 365 + (int)(1880/4) - (int)(1880/100) + (int)(1880/400) + 30;
$k11 = $getYEAR - 1;
$td2 = $k11 * 365 + (int)($k11/4) - (int)($k11/100) + (int)($k11/400);

if ($getYEAR % 400 == 0 || $getYEAR % 100 != 0 && $getYEAR % 4 == 0) {
  $arrayLDAY[1] = 29;

} else {
  $arrayLDAY[1] = 28;
}

if ($getMONTH > 13) {
  $gf_sol2lun = 0;
}

if ($getDAY > $arrayLDAY[$getMONTH-1]) {
  $gf_sol2lun = 0;
}

for ($i=0;$i<=$getMONTH-2;$i++) {
  $td2 += $arrayLDAY[$i];
}

$td2 += $getDAY;
$td = $td2 - $td1 + 1;
$td0 = $dt[0];

for ($i=0;$i<=168;$i++) {
  if ($td <= $td0) {
    break;
  }
  $td0 += $dt[$i+1];
}

$ryear = $i + 1881;
$td0 -= $dt[$i];
$td -= $td0;

if (substr($arrayDATA[$i], 12, 1) == 0) {
  $jcount = 11;

} else {
  $jcount = 12;
}

$m2 = 0;

for ($j=0;$j<=$jcount;$j++) { // 달수 check, 윤달 > 2 (by harcoon)
  if (substr($arrayDATA[$i],$j,1) <= 2) {
    $m2++;
    $m1 = substr($arrayDATA[$i],$j,1) + 28;
    $gf_yun = 0;
  } else {
    $m1 = substr($arrayDATA[$i],$j,1) + 26;
    $gf_yun = 1;
  }
  if ($td <= $m1) {
    break;
  }
  $td = $td - $m1;
}

$k1=($ryear+6) % 10;
$syuk = $arrayYUK[$k1];
$k2=($ryear+8) % 12;
$sgap = $arrayGAP[$k2];
$sddi = $arrayDDI[$k2];
$gf_sol2lun = 1;

if($m2<10) $m2="0".$m2;
if($sday<10) $td="0".$td;

$Ary[year]=$ryear;
$Ary[month]=$m2;
$Ary[day]=$td;
$Ary[time]=mktime(0,0,0,$Ary[month],$Ary[day],$Ary[year]);

return $Ary;

}

//사용 예
$lunar_date = SolaToLunar($f_date);
echo date("Y-m-d", $lunar_date[time]);
?>

2013. 11. 21.

내가 만든 앱 마켓에 등록하기. 구글 플레이(PLAY) 개발자 등록을 해보자!

구글 플레이 개발자 계정이 하나 더 필요하게 되었네요. 몇 년 전이라 어떻게 등록했는지 절차가 가물 가물 합니다. 등록 화면도 바뀐 것 같고...  그래서 이렇게 포스팅해 봅니다. 등록 하는데 필요한 비용 25달러는 변하지 않았네요. 등록 할 때 한 번만 내면 됩니다.

등록 하고자 하는 구글 계정으로 로그인 후 아래 링크로 이동 하면 다음과 같은 등록 화면을 만날 수 있습니다. 민감한 개인 정보들은 검은색으로 무식하게 덮어 놨습니다.


검은색으로 칠한 부분에 로그인한 정보가 나타 납니다. 왼쪽 아래쪽에 결제 페이지로 이동 하기를 클릭해서 진행 하시면 됩니다. 다른 내용은 없네요. 왼쪽 아래에 개발자 배포 계약 검토 및 동의 부분에서 체크 해주는 것과 25달러 라는것 뿐입니다.

수수료를 결제할 수 있도록 신용카드를 준비하세요. 라고 했는데 체크카드로도 진행 잘 되네요. visa가 붙은 체크카드면 문제가 없나 봅니다.


요구하는거 적어 주면 됩니다. 카드 번호 적어주면 알아서 카드 종류가 오른쪽에 나오네요. 근데 각 카드 번호가 지구에서 고유한 건가요? 입력란 옆에 visa나 다른 종류들이 희미하게 있고 카드 번호를 입력하면 해당되는 종류가 위 사진처럼 나타나는데 어떻게 visa인걸 아는건지 허허. 카드 번호가 16자리니까 큰 숫자긴 하다만...

카드 유효기간 넣어주고 보안코드는 카드 뒤에 4자리, 3자리 숫자 있는거 중에 3자리 숫자. 그리고 청구지 주소를 넣으라고 합니다. 위 캡처 화면은 카드 정보 수정 화면 입니다. 처음 진행할때 캡처 하는걸 깜빡 했거든요. :-D 근데 별반 다른건 없습니다. 거의 동일 합니다.

청구지 주소라고 되있는데, 대한민국 선택하고, 본인 이름 영어로 적고, 우편번호만 적어 주면 됩니다. 000-000 처럼 우편물에 흔히 보이는 그 우편 번호. 주소 적는건 없는데 주소 얘기가 있어서 처음에 좀 당황했습니다. 허허.


지금까지 입력한 것들이 '결재 수단' 으로 만들어 집니다. 카드 여러개를 등록하면 선택할 수 있나 봅니다. 별거 없네요. 구입을 눌러 줍니다.



이제 구체적인 주소를 물어 봅니다. 아래쪽 7가지 입력란에 적당하게 입력해 주시면 됩니다. 주소는 영어로 입력해 줍니다. 위의 두 번째 캡처사진 처럼 도로명주소로 검색하고 간단하게 영문 주소를 확인 할 수 있습니다.

위 두번째 캡처사진의 주소로 예제를 들자면,
첫번째. 서울, 부산, 울산 ... 셀렉트 박스 형식이니 선택해 줍니다.
두번째. Seongdong-gu, Seoul
세번째. 28, Seoulsup 2-gil
네번째. Seoulsup vila 101ho
다섯번째. 이름이 자동으로 들어가 있습니다. 처음 부분에서 입력한 값이네요.
여섯번째. 우편번호도 이름이랑 같이 입력했었는데, 비어있네요. 예제에선 133-923으로.
일곱번째. 전화번호 입니다. 전 그냥 010...에서 맨 앞에 0만 빼고 그대로 적었습니다. 한국은 국가코드가 +82 입니다. 국가 코드까지 포함한다면 +8210... 이 되겠네요.


슬슬 귀찮고 번거롭네요. 요구 하는게 이렇게 많다니... 그리고 다음으로 진행하는 버튼은 아까부터 "구입" 이네요. 괜히 시비 걸어 봅니다.


이제 다 되 가나 봅니다. 결제 처리 중... 문구만 읽고 아래쪽은 읽지 않은 채 5분 동안 멍하게 있었습니다. 창은 사라지지 않더군요. 백그라운드에서 결제가 처리 중이라니, 등록 계속하기 버튼을 눌러 줍니다.


크흐. 드디어 마지막 입니다. 개발자 이름은 어플을 등록했을때 어플 명 아래쪽에 뜨는 그 이름 입니다. 난 내 이름을 걸겠다! 하시면 이름을 쓰셔도 되고, 사업체 명을 쓰셔도 되구요. 이 메일 주소는 현재 로그인한 이메일 주소 그대로 적어 주시면 됩니다.

위에서 전화번호 적을때 국가코드 없이 적었었는데, 여기서는 국가코드 포함해서 +8210******** 형식으로 적어 줬습니다. 보시는 바와 같이 국가코드를 꼭 포함하라고 되어 있네요. 흐음. 이런 저런거 기입 하는걸 좋아 하지 않는 지라 마음이 좋지 않습니다.


등록 완료 버튼을 누르시면 개발자 등록은 정말 이제 끝이 납니다. 노란색으로 알림창이 떠있네요. 최대 48시간 걸린다고 합니다. 제가 토요일날 등록 한 걸로 기억 합니다. 주말이니 주말은 빼고 월요일 부터 계산한다고 하면 화요일쯤 되리라 생각 했지요. 정말 화요일 오후 늦게 등록 되었다는 메일이 왔습니다.

결제가 진행 중이어도, 마켓에 올릴 수만 없을 뿐이고 바로 그 직전까지 모두 작성해 놓을 수 있습니다. 헌데 등록한다고 진을 빼서 아무것도 하기 싫더라구요. 허허. :-D

2013. 11. 20.

HTML 폼(form) 크롬에서 두번 눌러야 제출(submit) 될때.

기존 소스를 좀 건드려야 돼서 수정하고 테스트 하다가, 어이없게 시간을 뺏긴 경우가 있어서 포스팅 하나 해 봅니다. 간단한 form과 자바스크립트 함수 입니다.
<form action="javascript:check_before_submit(this);">
...
<input type="image" ... >
</form>
<script language="JavaScript">
function check_before_submit( f ){
    ...
    f.action = "http://...";
    f.submit(); // or return true;
}
</script>
form안의 image 타입의 input은 submit 버튼 역할을 합니다. 버튼을 누르면 action 속성이 향하는 자바스크립트 함수를 호출 하겠죠. 함수 내에서 action 속성을 변경하고 form의 submit() 함수를 호출 합니다.

IE에서 탈이 없길래 form 부분은 보지도 않았습니다. 크롬에서 테스트 중에 버튼을 처음 눌렀을 때는 아무 반응이 없고, 두 번째 눌렀을 때 반응이 오더군요. 괴상하다 싶어 뒤져보니 소스가 저렇게 돼있었네요.

크롬에서 action 속성이 가리키는 함수에서 action 값을 바꾸면 에러가 발생하는 걸까요. 자세한 건 모르겠지만, 바로 아래 submit() 함수는 실행이 되지 않네요. return 구문으로 바꿔도 동일 합니다.

그래서 처음 눌렀을 때 함수 호출을 통해 action 속성을 바꾸고, 두 번째 클릭했을 때 바로 바뀐 값으로 submit 되는 거라 추측이 되네요. 아래처럼 수정하면 IE나 크롬이나 문제 없이 잘 됩니다. form의 action 속성은 onsubmit으로. 자바스크립트 함수는 true값을 리턴 하는 것으로!
<form onsubmit="return check_before_submit(this);">
...
<input type="image" ... >
</form>
<script language="JavaScript">
function check_before_submit( f ){
    ...
    f.action = "http://...";
    return true;
}
</script>

2013. 11. 18.

JQUERY iframe 또는 팝업창에서 부모 엘리먼트 참조하기.

팝업창이나 한 페이지에서 iframe을 이용해서 다른 페이지를 불러 왔을때 부모의 엘리먼트 값을 참조하거나 바꿔줘야 하는 경우가 있습니다.

팝업창의 경우에 window.opener.함수(매개변수, ...); 와 같이 부모가 가지고 있는 함수를 호출하면서 필요한 인자를 넘겨 부모측에서 처리하게 하면 되고, iframe의 경우엔 window.parent.함수(매개변수,  ...); 처럼 parent를 호출해서 처리하면 됩니다.

뭐 그리 대단한 연산이 있는 것도 아닌데, 자식 창에서 처리해서 부모 창에 반영 되게 하려고 바꾸려던 찰나에 꼭 jquery 문장으로 쓰고 싶다는 생각이 듭니다. 코딩 하다보면 효율이고 나발이고 왠지 싫은게 있고 꼭 이렇게 하고 싶을 때가 생기더라구요. 허허.

JQUERY로 저 문장을 어떻게 바꾸면 좋을까...
$("# ID " ).val( ... ); 이렇게 적어놓고 어떻게 부모창의 엘리먼트에 접근 해야 하나 찾아 봤습니다.
http://stackoverflow.com/questions/726816/how-to-write-this-in-jquery-window-parent-document-getelementbyidparentprice

window.parent.document.getElementById(' ID ').innerHTML 
$('#ID', window.parent.document).html(); //JQUERY :-D

오호라. jquery selector 셀렉터 두번째 인자로 엘리먼트를 찾을 범위(?)를 줄 수 있다는 걸 알았네요. 만족스러운 검색을 마치고 적용해 보았습니다만 말을 듣지 않네요. 또 이리 저리 찾아 보다가...
http://stackoverflow.com/questions/2167455/how-to-access-parent-window-object-using-jquery

window.opener.$("#ID") ...

window객체의 parent는 iframe에서, opener는 팝업창에서 사용 합니다. opener를 parent로 바꿔 봅니다. IE, Chrome에서 잘 돌아 갑니다만... 마음에 들지 않습니다... 처음 찾은 저 코드가 왜 안되는지 마냥 궁금합니다. 그리고 괜히 변태같은 고집이 피어 오르네요. 일단 일은 해야되니 미뤄 놓고 시간 날때 틈틈히 찾아 봤습니다.
http://stackoverflow.com/questions/1133276/how-to-access-parent-document-elements-using-jquery-in-firefox

셀렉터에 파라미터를 2개 사용하는 문장에 대한 질문이고, IE와 Chrome에선 말을 듣지 않으나 firefox에서는 된다고 합니다. 만약 firefox에서 된다면 빌어먹을 브라우저 때문이군! 이렇게 생각하며 접어 버릴 생각으로 firefox를 깔아 봅니다. 그리고 확인해 봅니다! 안됩니다... :-O

http://stackoverflow.com/questions/9031031/jquery-selector-context
좀 더 뒤적거리다가 결국 포기 합니다. 마지막 링크에선 이런 글이 있네요.

so $('span', this) is equivalent to $(this).find('span').

으으음. 셀렉터에서 두번째 파라미터를 줘봤자 내부적으로는 find() 함수를 위와 같이 써서 처리 한답니다. 그래서 $(window.parent.document).find("#ID")... 로 변경해봤으나! 여전히 안됩니다.

* jquery 라이브러리 버전이 문젠가 싶어서 바꿔봤으나 실망만... 아아. 이번 변태같은 고집은 꺾을 수 밖에 없네요... 누가 아신다면 가르쳐 주세요...

PHP 오늘 어제 내일 날짜 구하기 date() mktime() time() 함수.

PHP에서 특정 날짜를 구하는 데는 date()와 mktime() 함수만 알고 있으면 걱정 없습니다. date() 함수는 2가지의 인수를 가집니다. 첫 번째 인수는 시간을 어떻게 출력할 것 인가에 대한 포맷입니다.
년도만 출력할 수 도 있고, 현재 시간만 출력 할 수도 있습니다. date("Y") 는 현재 년도를, date("G")는 현재 시간을(0 - 23시간) 출력해 줍니다.

그럼 기준이 되는 시간은 무엇일까 하는 생각이 듭니다. 두 번째 인수가 기준이 되는 시간 입니다. 두 번째 인수는 넣어도 되고 넣지 않아도 됩니다. 없을 경우 time() 함수의 결과 값이 기본 값으로 들어 갑니다. time()함수는 1970년 1월 1일부터 지금 이 순간 까지 경과한 시간을 초로 반환해 주는 함수 입니다.

date("Ymd") 라고 하면 오늘 날짜를 구할 수 있겠네요. 결과는 20131118 입니다. 두 번째 인수가 안 들어 갔으니 기본 값으로 현재 시간이 들어가는 거구요. 결국 date()는 특정 시간을 어떤 형태로 출력해 주는지 정해 주는 녀석인 것 같습니다.
http://php.net/manual/kr/function.date.php

그럼 어제와 내일 날짜를 구하기 위해선 두 번째 인수를 계산해서 넣어줘야 됩니다. mktime()은 1970년 1월 1일부터 특정 날짜까지 경과한 초를 반환해 줍니다. 인수 없이 mktime()을 호출하면 time()을 호출한 것과 결과가 같습니다.

mktime(시간, 분, 초, 달, 일, 년, is_dst) 의 형식을 가집니다. 마지막 인수는 시간대와 관련된 인수인 듯 합니다 만, PHP5.1 부터 더 이상 사용을 권장하지 않는다고 합니다. mktime() 함수의 인수들은 어떻게 넣느냐. 각 자리마다 구하고 싶은 값들을 넣으면 됩니다. 시간은 0부터 23까지. 분과 초는 0부터 59까지...
http://php.net/manual/en/function.mktime.php

이 함수는 똘똘 합니다. 만약 분을 60이라고 넣으면 알아서 시간 값을 1 올리고 분은 1이 됩니다. 달과 일의 경우도 말일이 28일, 29일, 30일, 31일의 경우가 있는데, 해당 년도와 해당 달을 참고해서 알아서 처리해 줍니다. 구글링을 통해서 찾아 볼 수 있는 PHP관련 날짜 함수는 이런 성질을 이용해서 작성 되어 있습니다.

이제 아래 코드가 한 눈에 들어오리라 생각 합니다.
date("Ymd", mktime(0,0,0, date("m"), date("d")-1, date("Y"))); //어제
date("Ymd", mktime(0,0,0, date("m"), date("d")+1, date("Y"))); //내일
위 코드에서 날짜 포맷 부분을 date("Ymd H:i:s", ... ); 시분초가 나오게 해보면 00:00:00이 나옵니다. mktime()의 1~3 인수를 0으로 줬기 때문인데요. date() 함수를 이용해서 시분초에 해당하는 값을 넣어주면 됩니다.

시분초를 포함한 최종 코드는 아래와 같습니다.
date("Ymd H:i:s", mktime(date("H"), date("i"), date("s"), 
                         date("m"), date("d")-1, date("Y")));
date("Ymd H:i:s", mktime(date("H"), date("i"), date("s"), 
                         date("m"), date("d")+1, date("Y")));

* 특정 날짜에서 전날, 다음날을 구하고 싶다? 날짜 형식은 20131118 이라고 가정. 다른 거 없이 날짜를 쪼개서 적당하게 넣어 주기만 하면 됩니다. 구분자가 포함됐으면 없애버리고 처리하면 되겠죠.
function get_yesterday( $day ){

    $y = substr( $day, 0, 4 );
    $m = substr( $day, 4, 2 );
    $d = substr( $day, 6, 2 );

    return date("Ymd", mktime(0,0,0, $m, $d-1, $y));
}
날짜 구하기. 간단하고 편하네요 :D

2013. 11. 13.

HTML window 객체의 pageYOffset와 outerHeight 값이 undefined.

현재 창의 높이(height)와 현재 얼마만큼 스크롤이 됐는지(offset) 을 구해야 하는데 자꾸 값은 안주고 undefined만 내뱉어서 당황 스럽습니다.

window.pageYOffset은 스크롤바의 offset을 반환 합니다. 크롬에서는 값이 제대로 나오지만 IE8에서는 도통 나오질 않고 undefined만 확인 할 수 있죠. IE10에서는 문제 없이 잘 나옵니다.
https://developer.mozilla.org/en-US/docs/Web/API/Window.scrollY
var y = (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
크로스 브라우징을 위한 코드 입니다. pageYOffset의 값이 없을때, 같은 값이 들어있는 다른 이름의 변수들을 참조 하네요. 위의 코드를 사용하면 모든 브라우저에서 원하는 값을 가져올 수 있습니다.

다음 window.outerHeight는 현재 창의 높이 입니다. 스크롤바는 상관없이 눈에 보이는 현재 높이 값 입니다. 창에서 주소표시줄과 같은 높이들도 포함된 값입니다. 이 값도 IE8에서는 undefined만 뱉어 냅니다. 아. 찢어발기고 싶은 IE8. 허접쓰레기 같은 그림판 캡처를 첨부 합니다. window.innerHeight는 html이 표시되는 부분의 높이값만 가집니다.

왼쪽이 크롬, 오른쪽이 IE8 입니다.

http://www.w3schools.com/jsref/obj_window.asp
첫번째 값은 스크롤 offset값.
두번째 값은 창 높이.
세번째부터 다섯번째 값은 첫번째 값과 같은 변수들 입니다.

w3schools 만을 참고해서 하다보면 IE8에서 곤란해지는 일이 종종 발생 합니다. 캡처를 확인해보면 IE8은 완전 반대로 값을 출력해 주네요. 하아.

매번 이렇게 헤매야 할까요. 이런거 신경 안쓰게 해주는 JQUERY로 같은 결과 값을 얻어 보도록 하죠. JQUERY를 사용하면 IE8에서도 문제 없이 값을 가져 올 수 있습니다.
$(window).scrollTop() == window.pageYOffset //그리고 3 - 5번째 값들
$(window).height()    == window.innerHeight
크로스 브라우징을 생각해서 JQUERY를 사용하도록 합시다아. 머리아프지 말고... 헌데 만능은 아니더라고 하더군요. 그저 믿고 있다가 크게 한방 당하신 분이 계시더라는...


* "좋은 것이 빠지고 난 뒤에 남은 허름한 물건"을 뜻하는 '허섭스레기'. 지난 8월 31일에 바뀐 표준어 규정에 따라 '허접쓰레기'도 표준말이 되었다고 합니다.

2013. 11. 12.

다크나이트 라이즈 브루스 웨인의 저택. 노팅엄 월라튼 공원.



영화 다크나이트 라이즈(dark knight rises)에서 배트맨(브루스 웨인) 저택의 촬영지가 궁금하여 구글 지도를 통해 눈으로나마 여행을 떠나보려 합니다. 촬영 장소인 대저택의 명칭은 Wollaton Hall이고 영국에 위치해 있습니다. 아래 지도에서 A 말풍선 위치 입니다.

예전에 영국에 배낭여행겸 갔을때는 런던에만 머물러 있었습니다. 대부분을 걸어서만 다녔고, 지인들과 함께 이동할땐 지하철을 타기도 했었죠. 다리가 아주 아주 아주 아팠던 기억이 나네요. 많이 걸어 보긴 했지만 이번 목적지까지 걷진 못할것 같네요.


세인트 판크라스(st. pancras) 역에서 기차를 타고 이동해야 합니다. 영국 여행할때 워털루 역 근처에 짐을 뿌려놓고 걸어다닌 덕에, 하루에도 몇 번씩 빅벤과 런던아이를 봤던 기억이 나네요. 파리로 이동할때 유로스타를 타고 이동했는데, 워털루 역에서 세인트 판크라스 역까지 걸어 갔었습니다. 지도로 보면 그냥 쭉 가버리면 될 것 같았는데 정말 많이 해맸다는... 한 두시간 정도 걸은거 같네요. 무거운 가방도 메고...



하. 여길 다시 보니 반갑네요. 세인트 판크라스 역까지 걸어가는 길에 역인줄 알고 들어가서 몇 분을 해맸던 곳입니다. 호텔 인가요?


기차표를 예매를 해야겠네요. 뭐든지 미리 예약해야 싸게 먹히는건 진리인듯 합니다. 세인트 판크라스 역에서 노팅엄 역까지 가는 티켓 예매. 지금 글 작성하는 날짜 바로 그 다음 날짜로 해서 캡쳐를 해봤습니다. 그런것 치고는 그리 비싼편은 아니네요. 여기저기 블로그들 보니 미리 예약해서 10파운드로 예매하셨다는 분들도 계시더라구요.


위 링크 타고 들어가셔서 예매 하시면 될 듯 합니다. 갑자기 예전에 런던에서 파리갈때 유로스타 기차표를 어디서 예매했는지 기억이 안나서 당황스럽네요. 인터파크였나... 무튼 저 영어 활자가 눈을 어지럽히는 곳에서 예매 하지 않은건 확실 합니다. 하하.

자! 이제 머릿속으로 예매도 했고 기차도 탑승하고 내려보도록 하죠. 예전에도 그랬고 지금도 그렇고, 여행 준비는 전지전능한 구글 맵으로 합니다. 처음 가보는 곳이니 구글 스트리트 뷰로 눈에 좀 미리 익히는 거죠.


노팅엄 역에 내리면 이런가 봅니다. 한번 봐두면 아무래도 처음 도착 했을때 마음이 편하더라구요. 눈으로 숙소도 잡아보면 좋겠지만, 바로 이동 해보도록 합니다. 목적지인 월라튼 홀(Wollaton Hall)은 공원 안에 있었네요.


저희는 지금 '노팅엄' 하얀 레이블에 있는 겁니다. 아아. 멀고 머네요. 이정도면 걸어가도 될꺼 같은데? 허나 치밀하게 교통편도 알아봅니다.


검은색으로 표시된 부분은 걸어야 하는 부분입니다. A 말풍선이 노팅엄역을 나타내고, B 말풍선이 목적지를 나타냅니다. 파란색으로 표시된 부분은 버스를 타고 이동하는 구간이구요. i4 버스를 이용 하나 봅니다. 노선 번호가 독특 하네요. 구글맵이 알려준 소요시간은 24분 이었습니다. 허나 전 45분 거리를 2시간에 가는 놀라운 능력을 가지고 있죠.


내부 사진도 있어면 좋으련만, 아쉽네요. 아무튼 Sandiacre방면으로 가나 봅니다. 그림에 포함된 노선 정보 라는 사이트를 참고하셔도 될듯 하고(저 주소는 캡쳐하면서 알았네요) 따로 검색한 링크는 요기.
http://www.stapleford-notts.co.uk/trent-barton-i4-bus-timetable.htm

점점 피곤해지고 돈은 점점 줄어 들고 있습니다만, 목적지도 다가오고 있네요! 버스타면 가장 두려운게 어디서 내려야 하는지 모르겠다는것 아닐까요. 전 스마트폰 로밍해가서 지도로 위치 확인하고 내렸었습니다. 허나 어마어마한 속도 때문에 속이 썩어 들어가던 기억이 납니다...

타이밍 좋게, 정확한 곳에 내렸나 봅니다. 내리면 이런 모습이 눈에 보이리라 믿습니다.


발에 힘이 다시 불끈 하고 생기면서 열심히 걸어 들어갑니다. 공원이라 경치도 좋고 걷기도 좋으리라 생각합니다. 이리저리 사진도 찍고 눈알도 굴려가며 이제 목적지에 도착 합니다!


아아. 직접 가서 눈으로 보고 싶네요. 언제 갈진 모르지만 그 날을 위해 이렇게 계획을 짜 봅니다. 다들 즐거운 여행 하세요~


# 영화를 캡쳐해서 첨부하고 싶었으나, 저작권 문제가 무서워 포기 합니다...

* 첫번째 사진 출처.
http://www.gardenvisit.com/garden/wollaton_hall_garden

* 기차편 캡쳐.
http://nationalrail.co.uk/

* 그 외 구글 지도에서 캡쳐.
https://maps.google.com/

2013. 11. 11.

안드로이드 기본 브라우저와 크롬. fieldset 라디오 버튼 onchage 이벤트 차이.

웹페이지를 안드로이드 내장 기본 브라우저와 크롬에서 테스트 하는데, 어느 한쪽에서 이벤트가 발생하지 않는 일이 생겨 좀 찾아봤습니다. 관련 부분은 언제나 그렇듯 간단한 녀석.
<fieldset onchange="myFunc();" >

    <input type="radio" name="RB" id="a" value="value_a"/>
    <label for="a">a</label>

    <input type="radio" name="RB" id="b" value="value_b"  />
    <label for="b">b</label>

</fieldset>
myFunc()의 함수에는 간단하게 alert()으로 현재 선택된 라디오 버튼의 value를 출력해 주는 것이라 가정 합니다.

크롬에서는 라디오 버튼을 조작할때 마다 정상적으로 myFunc()가 호출 됩니다. 그러나 안드로이드 기본 내장 브라우저에서는 도통 응답이 없네요. fieldset 태그를 안드로이드 기본 브라우저에서 100% 지원하지 않는 것 같아서 이런 저런 이벤트 함수를 넣어서 확인해 봤습니다.

disable="disable" 속성을 추가해 봤는데, 크롬에서 정상적으로 disable 비활성화가 됐으나 안드로이드 기본 브라우저는 아무런 반응이 없습니다. 안드로이드 기본 브라우저에서 fieldset 태그를 완전히 배제한 것일까요.

onmouseup()의 경우에는 두 브라우저 모두 반응이 없습니다만, onmousedown()의 경우는 안드로이드 기본 브라우저에서만 이벤트가 발생 합니다. 하하 거참 햇갈리네요.  모바일 웹뷰에서의 터치 이벤트가 HTML의 어떤 이벤트로 전달 되는지 궁금 하네요.

브라우저마다 조금씩 다른건 별 수 없습니다만 신경쓰이는 것도 별 수 없나 봅니다.
http://www.w3schools.com/tags/tag_fieldset.asp
http://www.w3schools.com/tags/ref_eventattributes.asp

결국 fieldset은 별 쓸모 없이 붙어 있게 되었고, 이벤트는 아래와 같이 처리 했습니다. input 태그에서 onchage 속성은 두 브라우저 모두 동일하게 반응 하더군요.
<fieldset>

  <input onchange="myFunc();" type="radio" name="RB" id="a" value="value_a"/>
  <label for="a">a</label>

  <input onchange="myFunc();" type="radio" name="RB" id="b" value="value_b"/>
  <label for="b">b</label>

</fieldset>
http://www.w3schools.com/tags/ev_onchange.asp

* 아, 그리고 위에서 확인했던 이벤트 onmouse*() 함수들은 같은 크롬이라도 모바일과 데스트탑이 결과가 다릅니다. 확인할 엄두가 안나서 포기...

* 안드로이드 4.4(kitkat) 부터는 기본 내장 브라우저가 크롬이 된다고 합니다. 모바일 브라우저 종류도 많은데 한 가지라도 준다고 하니 그건 마음에 드네요.
http://www.android.com/versions/kit-kat-4-4/

2013. 11. 8.

폰갭(phonegap) 웹뷰와 일반 웹뷰 구분하기. 안드로이드 코드에서 웹뷰로 자바스크립트 함수 호출하기.

제목이 두개가 되었네요. 폰갭을 사용한 어플에서의 웹뷰와, 일반 모바일 브라우저 웹뷰를 구분하기 위해 찾아보다가 찾은 방법이 뒷 제목 입니다.

웹사이트에서 안드로이드 기기 카메라를 사용하기 위해 폰갭 플랫폼을 가져와서 안드로이드 앱을 만들었습니다. 구성은 웹 언어로 되어있고 포장은 폰갭과 안드로이드로 한 하이브리드 앱이죠.

허나 해당 웹사이트에서 필요로 했던 기능은, 안드로이드 기기 카메라 제어 단 하나 였습니다. 그 외의 모든 것들은 데스크탑 또는 모바일의 브라우저에서도 다 가능한 것들이구요.

웹사이트 소스에 폰갭( cordova.js ) 라이브러리를 불러 오는 것은 문제가 없습니다만, 해당 라이브러리가 포함 되어 있는 페이지를 데스크탑이나 모바일의 브라우저로 불러오면 페이지 이동이 발생할 때 마다 다이얼로그가 떠서 도무지 뭘 할 수가 없습니다. 안드로이드 어플 단에서 필요로 하는 정보를 가져 오는 것 같은데, 환경이 다르니 그런 거겠죠.

조건절 하나면 해결 될 것 같습니다. 사용한 웹 언어나 자바스크립트에서 지금 실행 환경이 안드로이드 앱상 인지, 일반 웹뷰인지 판단해서 폰갭 라이브러리를 불러 오거나 그러지 않으면 되겠죠.

처음 생각했던 것은, 모바일과 데스크탑의 구분이었습니다.
$mobile = !!(FALSE !== strstr(strtolower($_SERVER['HTTP_USER_AGENT']), 'mobile'));
//모바일 기기에서 접근할때 $mobile > 0 이됩니다.
$mobile변수로 조건문을 만들어 라이브러리를 불러올지 결정했었죠. 이것의 문제는 폰갭 웹뷰나 일반 브라우저 웹뷰나 둘다 mobile 값이기 때문에 구분이 안된다는 것입니다.

그래서 안드로이드 어플단의 자바 코드로 처리를 해줍니다.
안드로이드 4.3, 폰갭 2.9.0 환경 입니다.
public class MainActivity extends DroidGap {

    @Override
public void onCreate(Bundle savedInstanceState) {
  
        super.onCreate(savedInstanceState);     
        super.loadUrl("http:// URL ");
      
         //여기서부터
        class JsObject {
            @JavascriptInterface
            public String toString() { return "injectedObject"; }
         }
         appView.addJavascriptInterface(new JsObject(), "injectedObject");
         //여기까지
    }
}
주석사이의 코드.
http://developer.android.com/reference/android/webkit/WebView.html#addJavascriptInterface(java.lang.Object, java.lang.String)

다른것들은 아무것도 하지 않은 폰갭을 사용한 어플의 가장 간단한 모습입니다. 주석 사이의 코드만 추가해주면 원하는 결과를 가질 수 있습니다.

설명하자면 window 객체( 브라우저 객체, 곧 웹뷰의 객체 )에 사용자 정의 객체를 추가해 주는 겁니다. window 객체에 대해 자세한 내용은 아래 링크 참고.
http://www.w3schools.com/jsref/obj_window.asp

안드로이드 어플을 실행했을 때만 저 사용자 객체가 추가 되므로, 웹페이지 소스에서 저 객체가 있는지 없는지 판단만으로도 문제를 해결 할 수 있습니다.

사용자 객체를 추가했으니 이제 자바스크립트에서 어떻게 사용하는지 알아 봅시다.
<head>
<script type="text/javascript">

if( window.injectedObject.toString() == "injectedObject" ){

      var js = document.createElement("script");
      js.type = "text/javascript";
      js.src = "./cordova.js";
      document.head.appendChild(js);
}
</script>
</head>
동적으로 js 파일 로드 하기.
http://stackoverflow.com/questions/950087/how-to-include-a-javascript-file-in-another-javascript-file

자바스크립트 코드에서 보는 것 처럼, window에 추가된 사용자 객체의 함수를 호출하고 그 반환된 값을 비교하는 조건문 입니다. 안드로이드 어플이 아닌 일반 브라우저에서 실행이 된다면? 저 값은 아무것도 없을테고 폰갭 라이브러리가 로드되지 않는 겁니다.

웹소스로 여러 모바일 OS에 맞는 앱을 만들 수 있다는 편리한 폰갭이지만 성격상 솔직히 그냥 귀찮습니다.

* 안드로이드 코드 단에서  sendJavascript() 함수를 사용한, 비슷해 보이는 방법도 있는듯 합니다. 포스팅된 방법으로 해결이 안되신다면 아래 링크를 한번 참조 해보심이...
http://www.jumpbyte.com/2012/phonegap-native-to-javascript/

* 그 외 참고 사이트.
http://stackoverflow.com/questions/15852499/javascript-calls-from-android-using-phonegap

2013. 11. 1.

HTML STYLE CSS 인쇄시 페이지 기본 여백 설정하기.

이전 포스트에서 크롬과 익스플로러에서 각각 인쇄 미리보기 페이지가 팝업 되게 하는 자바스크립트 소스를 봤었습니다. 각각 띄워놓고 보니 여백이 달라서 다른 페이지 처럼 보입니다.

인쇄가 될때 문서의 기본 여백을 설정해 줘야 겠습니다. 간단 하네요.
인쇄하고자 하는 페이지에서 아래와 같이 style 태그를 추가해 줍니다.
<style type="text/css" media="print">   
    @page{  size:auto; margin : 15mm;  }
</style>
크롬 인쇄 미리보기에서 여백이 '기본값' 일때 저 값이 적용 되네요.
익스플로러에서 여백이 제대로 들어가나 확인해보니 19mm가 되있더군요. 적용이 안되나 싶어서 여백 설정 창에서 확인을 눌러보니 문서 내 여백이 커집니다. 이미 15mm로 적용이 되어 있었던 겁니다.

여백값은 margin 값을 변경해 주면 됩니다.

꿀같은 출처는 역시 스택오버플로우.
http://stackoverflow.com/questions/1960939/disabling-browser-print-options-headers-footers-margins-from-page

자바스크립트 크롬 Chrome과 익스플로러 Explorer에서 인쇄 미리보기 창 띄우기.

크롬에서 인쇄를 하려고 하면 기본으로 미리보기 화면이 나오게 됩니다. 허나 익스플로러에서는 시스템 대화상자를 통한 무심한 창이 팝업 되죠. 크롬과 마찬가지로 익스플로러에서도 인쇄 미리보기가 존재 합니다.
<script type="text/javascript">
    window.print();
</script>
크롬에서는 인쇄 페이지 기본이 미리보기니까 걱정 없고, 익스플로러를 생각해 봅시다.
아래의 자바스크립트 소스로 익스플로러에서 인쇄 미리보기를 팝업 할 수 있습니다.
<script type="text/javascript">
function preview_print(){
   var OLECMDID = 7;
   var PROMPT = 1;
   var WebBrowser = '<OBJECT ID="WebBrowser1" WIDTH=0 HEIGHT=0 CLASSID="CLSID:8856F961-340A-11D0-A96B-00C04FD705A2"></OBJECT>';
   document.body.insertAdjacentHTML('beforeEnd', WebBrowser);
   WebBrowser1.ExecWB( OLECMDID, PROMPT);
}
</script>
다소 괴상해 보이긴 합니다.
insertAdjacentHTML()과 ExecWB()는 아래 링크를 참조.
http://msdn.microsoft.com/en-us/library/ie/ms536452(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/aa752087.aspx

insertAdjacentHTML() 함수는 특정 엘리먼트에 HTML 소스를 집어 넣어 주는 녀석 입니다. 첫번쨰 파라미터에서는 삽입 될 위치를 지정해 주는데 4가지가 있습니다.

<!-- beforebegin --> <p> <!-- afterbegin --> foo <!-- beforeend --> </p> <!-- afterend --> 

시작태그앞, 시작태그뒤, 종료태그앞, 종료태그뒤를 나타내네요.

대게 인쇄 페이지가 팝업으로 뜨고, 자동으로 인쇄 미리 보기 페이지가 나타나게끔 많이 합니다. 크롬은 자체적으로 현재 페이지에서 레이어 같은 걸로 처리 해놨던데... 익스플로러에선 대부분 인쇄하기 위해서 별도의 창을 마련 하더군요.

해당 함수가 있어야 하는 위치가 있습니다.
insertAdjacentHTML() 함수는 페이지 로딩중에는 쓸 수 없다고 합니다. 따라서 우리는 onload 이벤트에서 실행이 되도록 해야 합니다.
<script type="text/javascript">
window.onload = function(){
    preview_print(); //익스플로러
    window.print(); //크롬
};
</script>
저렇게 내버려 둘순 없으니, 브라우저에 맞게 함수를 실행 시켜야 겠네요.
navigator는 브라우저의 정보를 담고 있는 객체로, 이 녀석의 값을 참조해서 구분해 내면 됩니다.
http://www.w3schools.com/jsref/obj_navigator.asp
<script type="text/javascript">
window.onload = function(){
    if( navigator.userAgent.indexOf("MSIE") > 0 ){
        preview_print();
    } else if( navigator.userAgent.indexOf("Chrome") > 0){
        window.print();
    }
};
</script>
이렇게 하면 완성. 헌데 익스플로러 상단의 노란 상태바가 나타나면서 경고 메세지를 보여 주네요. 도구 - 인터넷 옵션 - 보안 - 신뢰할 수 있는 사이트에 해당 사이트를 추가 해주면 더이상 뜨지 않네요.

자동으로 미리보기를 띄우기 위해 스크립트를 사용해서 이런거고, 사용자가 직접 익스플로러 웹페이지에서 마우스 우클릭으로 인쇄 미리보기를 하면 뜨지 않습니다.

경고 문이 뜨면 신뢰할 수 있는 사이트에 추가 하라고 메세지라도 띠워줘야되려나...

PHP에서 인코딩한 문자열을 JAVASCRIPT에서 디코딩 하기.

PHP의 변수를 자바스크립트 함수의 매개변수로 전달 해야 할 경우가 있다. 매개변수로 전달되는 값에 따라 자바스크립트 오류가 발생하기도 한다. 도대체 왜 그런 걸까.

<a href="#" onClick="myFunction('<?php echo $value; ?>')">
    클릭!
</a>

function myFunction( form ){
    //처리.
}

대략 이런 경우가 있다고 해보자. 저 $value값에 따옴표라던가, 어떤 값이 들어가면 제대로 함수가 실행이 안된다. $value값을 <ega>\"ag 라 가정하자. 페이지를 불러와서 해당 링크를 클릭해보면 아무런 반응이 없다. 왜그럴까?

PHP는 서버단에서 실행되는 언어다. 문제 확인을 위해 페이지가 다 로딩 된 후 소스보기로 HTML 소스를 확인해보자.

<a href="#" onClick="myFunction(' <ega>"ag ')">

확인해본 소스는 이렇다. 함수 안의 매개변수에 포함된 " 큰따옴표가 함수를 중간에서 잘라 끝내 버린 격이 돼버린 것.

그래서 필요한 게 인코딩이다. 저런 특수 문자들을 희한한 문자들로 바꿔 준다.
인코딩된 문자열을 받은 myFunction() 함수는 디코딩 함수를 통해 원래 값을 가져오면 된다.
아래는 인코딩과 디코딩을 사용하여 상단 예제를 바꾼 것이다.

<a href="#" onClick="myFunction('<?php echo rawUrlEncode($value); ?>')">

function myFunction( form ){
    form = decodeURIComponent(form) ;
    //처리.
}

PHP에서 rawUrlEncode()는 자바스크립트의 encodeURIComponent()와 같고,
PHP에서 rawUrlDecode()는 자바스크립트의 decodeURIComponent()와 같다.

출처는 역시 스택오버플로우.
http://stackoverflow.com/questions/1105434/php-javascript-url-encoding