'03.HTML 4.X, HTML5, XML...'에 해당되는 글 234건

  1. 2014.11.22 jQuery 현재날짜 세팅
  2. 2014.08.20 Understanding and Solving Internet Explorer Leak Patterns
  3. 2014.02.22 Javascript Closures
  4. 2014.02.22 [펌]자바스크립트의 메모리관리
  5. 2013.12.24 HTML - The <object> Element
  6. 2013.12.24 autoplay a wav file on html code
  7. 2013.10.04 javascript 자식창에 파라미터 전달 및 부모창 호출
  8. 2013.06.18 google SWFObject
  9. 2013.02.13 [펌] 자바스크립트 페이지에 오류가있을때 alert창 띄우기
  10. 2012.12.17 [펌] [공유] 코어 자바스크립트 - 강좌 모음
  11. 2012.03.15 javascript close 사용시 안내문구 없애는 방법
  12. 2012.01.31 Simple을 사용하여 XML 직렬화하기
  13. 2012.01.31 XStream을 통해 XML 다루기
  14. 2012.01.27 초간단 xml 파싱
  15. 2012.01.26 Serializing an object to XML
  16. 2012.01.26 자바 객체 <-> XML 변환
  17. 2012.01.26 JAXB를 활용한 Java 객체의 XML 자동 변환 1
  18. 2012.01.26 How to create XML file in Java – (JDOM Parser)
  19. 2012.01.26 How to modify XML file in Java – (JDOM Parser)
  20. 2012.01.26 How to read XML file in Java – (JDOM Parser)
  21. 2011.06.12 ie fe div 가운데 영역 보이기
  22. 2011.06.11 ie9 에서 smarteditor 영역이 보이지 않을경우...
  23. 2011.06.11 [tomcat 4.x -> 5.x 올리기 -2-] Attribute value java.net.URLEncoder.encode("한글") is quoted h " which must be escaped when used within the value
  24. 2011.05.09 Apache HTTP Server Version 2.3 문서
  25. 2010.12.30 자바스크립트 사용 예
  26. 2010.11.25 CookieUtil.js
  27. 2010.11.25 nice.nuguya.oivs.crypto.js
  28. 2010.10.26 길이체크 정규식 (아이디 비번 길이 확인)
  29. 2010.10.19 [jQuery 기본 강좌]1-3 jquery 자동완성 autocomplete 기능 쉽게 적용하기
  30. 2010.10.19 Javascript에서 String을 Number타입으로 바꾸기
반응형


$(document).ready(function() {     $('#date').val($.datepicker.formatDate($.datepicker.ATOM, new Date())); });

 


Posted by 1010
03.HTML 4.X, HTML5, XML...2014. 8. 20. 13:53
반응형

출처 : http://bryan7.tistory.com/202


IE Memory Leak – jQuery Fix


http://kossovsky.net/index.php/2009/07/ie-memory-leak-jquery-garbage-collector/


댓글에 보니 jQuery 를 수정해서 문제를 해결했다는 얘기도 있긴 했지만, 내가 해 봤을 때는 별 효과가 없었다.


IE memory leak


http://epro.tistory.com/6


1. 원인은?

Understanding and Solving Internet Explorer Leak Patterns를 참고해 보면 순환참조 부분이 가장 의심이 되었다.
Ajax를 편하게 쓰기 위해 XMLHttpRequest를 생성해주는 function을 만들어 두고 필요할때 불러서 쓰곤 했는데, 이 부분에서 문제가 있는 듯 했다.
local variable은 function이 종결되면 가비지컬렉터에 의해 삭제되어야 하는데, parameter로 다른 function에 참조되어 있을 경우- 이런 경우를 순환참조라고 하는 것 같다 - 는 leak의 원인이 된다고 한다. (어설픈 해석이다. 대충 이런 뜻인 것 같다)

.... It isn't immediately obvious that parent function parameters and local variables will be frozen in time, referenced, and held until the closure itself is released. .... Because we've added a closure, a second reference is made, and that second reference won't be released until the closure is also released. .....

정확한 내용은 Reference의 Closures부분을 참조할 것
그래서 지역변수로 선언된 XMLHttpRequest를 전역변수로 빼고 비교해 보기로 했다.


Screencast: Diagnosing JavaScript Memory Leaks in IE


http://www.barelyfitz.com/screencast/javascript/memory-leak/


[스크립트] Script 메모리 누수에 대한 TIP


http://www.phpschool.com/gnuboard4/bbs/board.php?bo_table=tipntech&wr_id=71441


JavaScript and memory leaks


Memory leaks

http://javascript.info/tutorial/memory-leaks


Understanding and Solving Internet Explorer Leak Patterns

http://msdn.microsoft.com/en-us/library/ms976398.aspx


IE9 이하에서 (IE9 포함) Memory Leak 이 발생하는 경우 -


[2013-12-24]

5초마다 한번씩 반복적으로 ajax로 호출을 하니까 chrome 브라우저에서는 괜찮은데, IE 8, 9 에서는 메모리 증가 현상이 뚜렷했다. 저녁에 웹페이지를 켜 놓은 상태에서 퇴근하고, 아침에 출근해 보면 IE가 먹통이 되었다.

나는 처음에는 ajax 의 반복 호출로 인해 메모리가 조금씩 쌓였을 것이라고 생각했는데, ajax 에서 아무 일도 안 한 상태로 반복 호출해보니 메모리 증가 현상이 없었다. 


ajax 로 서버에서 리스트를 받아서 웹페이지에서 table 태그를 지우고, 다시 써 넣는 작업을 하고 있다.


원인은 <a> 태그 안에 onclick='...' 으로 문자열로 넣은 부분 때문이었다.

IE 9 버전 이하에서는 웹브라우저의 Garbage Collector 의 버그 때문에 이런 경우 onclick 안의 function 의 참조 때문에 화면에서 지워진 태그가 Garbage Collect 되지 않는 것 같다.


Chrome Browser 와 IE 11 브라우저에서는 메모리 증가 현상이 없었다.


해결책은 다음 코드와 같이 onclick='...' 으로 문자열을 적어 넣지 말고, jquery의 bind() 메서드를 사용하면 된다.


  1. // [2013-12-24] Heeseok
  2. // 다음과 같이 하면 IE 9 이하에서 Memory Leak 이 발생하므로 bind 메서드를 써준다.
  3. //td.html("<a href='javascript:" + fnGoDetail + "()' onclick='" + fnGoDetail + "(this);return false;'>" + list[r][col] + "</a>");
  4. td.html("<a href='javascript:" + fnGoDetail + "()'>" + list[r][col] + "</a>");
  5. td.find('a').bind("click", function() {
  6.     eval(fnGoDetail + "(this)");
  7.     return false;
  8. });


IE Process의 Memory 를 30초 단위로 파일로 저장하는 배치 파일


@echo off

SET count=0

SET mem=tasklist /fi ^"imagename eq iexplore.exe^" /NH

echo --------------------------------------------------------------------------- >> memory_iexplore.log

:start

SET /A count+=1

echo %date% %time% (%count%) >> memory_iexplore.log

%mem% >> memory_iexplore.log

echo --------------------------------------------------------------------------- >> memory_iexplore.log

TIMEOUT 30

goto start


배치 파일명: memory_iexplore.cmd
저장하는 로그 파일명: memory_chrome.log
파일에 저장되는 내용:

--------------------------------------------------------------------------- 
2013-12-24 19:08:11.08 (1) 

iexplore.exe                  1836 Console                    1     27,908 K
iexplore.exe                  6764 Console                    1    175,692 K
--------------------------------------------------------------------------- 
2013-12-24 19:08:41.15 (2) 

iexplore.exe                  1836 Console                    1     27,908 K
iexplore.exe                  6764 Console                    1    178,324 K
--------------------------------------------------------------------------- 

실행되는 모습:


IE Process의 메모리가 증가하는지 쉽게 확인하는 법


Process Explorer 에서 iexplore.exe 프로세스를 찾아서 마우스로 오른쪽 클릭하고, Properties... 메뉴 선택.

Performance Graph 탭을 보면 IE Process만 사용하는 CPU, Private Bytes, I/O 를 볼 수 있다.



Memory Leak 확인 예제 #1

테스트한 브라우저: IE9

테스트 결과: 어느 정도 급격하게 증가한 이후에는 증가하지 않는다.

29.6 MB => 220.2 MB => 411.8 MB => 411.8 MB => 411.9 MB


  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <script type="text/javascript">
  5.     function LeakMemory(){
  6.         var parentDiv = document.createElement("div");
  7.         parentDiv.onclick=function() {
  8.           foo();
  9.         };

  10.         parentDiv.bigString =
  11.           new Array(1000).join(new Array(20000).join("XXXXX"));

  12.         alert('Leak Memory Done');
  13.     }

  14. </script>
  15. </head>
  16. <body>
  17. <input type="button" value="Memory Leaking Insert" onclick="LeakMemory()" />
  18. </body>
  19. </html>



Memory Leak 확인 예제 #2

테스트한 브라우저: IE9

테스트 결과: 어느 정도 메모리가 증가한 이후로는 더 이상 증가하지 않았다. (메모리가 많이 증가했다가 alert 버튼을 누르고 나면 다시 원상태로 돌아옴.)

28.1 MB => 39.0 MB => 36.4 MB => 38.4 MB => 37.6 MB => 37.5 MB


  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <script type="text/javascript">
  5.     function leak() {
  6.       var e = document.createElement('div');
  7.       var x = { elementReference: e };
  8.       e.jsReference = x;
  9.     }

  10.     function test() {
  11.       for (var i = 0; i < 1000000; i++)
  12.         leak();
  13.       alert('Done');
  14.     }
  15. </script>
  16. </head>
  17. <body>
  18. <input type="button" value="Circular Reference" onclick="test()" />
  19. </body>
  20. </html>


Posted by 1010
반응형

Javascript Closures

Introduction

Closure
A "closure" is an expression (typically a function) that can have free variables together with an environment that binds those variables (that "closes" the expression).

Closures are one of the most powerful features of ECMAScript (javascript) but they cannot be property exploited without understanding them. They are, however, relatively easy to create, even accidentally, and their creation has potentially harmful consequences, particularly in some relatively common web browser environments. To avoid accidentally encountering the drawbacks and to take advantage of the benefits they offer it is necessary to understand their mechanism. This depends heavily on the role of scope chains in identifier resolution and so on the resolution of property names on objects.

The simple explanation of a Closure is that ECMAScript allows inner functions; function definitions and function expressions that are inside the function bodes of other functions. And that those inner functions are allowed access to all of the local variables, parameters and declared inner functions within their outer function(s). A closure is formed when one of those inner functions is made accessible outside of the function in which it was contained, so that it may be executed after the outer function has returned. At which point it still has access to the local variables, parameters and inner function declarations of its outer function. Those local variables, parameter and function declarations (initially) have the values that they had when the outer function returned and may be interacted with by the inner function.

Unfortunately, properly understanding closures requires an understanding of the mechanism behind them, and quite a bit of technical detail. While some of the ECMA 262 specified algorithms have been brushed over in the early part of the following explanation, much cannot be omitted or easily simplified. Individuals familiar with object property name resolution may skip that section but only people already familiar with closures can afford to skip the following sections, and they can stop reading now and get back to exploiting them.

The Resolution of Property Names on Objects

ECMAScript recognises two categories of object, "Native Object" and "Host Object" with a sub-category of native objects called "Built-in Object" (ECMA 262 3rd Ed Section 4.3). Native objects belong to the language and host objects are provided by the environment, and may be, for example, document objects, DOM nodes and the like.

Native objects are loose and dynamic bags of named properties (some implementations are not that dynamic when it comes to the built in object sub-category, though usually that doesn't matter). The defined named properties of an object will hold a value, which may be a reference to another Object (functions are also Objects in this sense) or a primitive value: String, Number, Boolean, Null or Undefined. The Undefined primitive type is a bit odd in that it is possible to assign a value of Undefined to a property of an object but doing so does not remove that property from the object; it remains a defined named property, it just holds the value undefined.

The following is a simplified description of how property values are read and set on objects with the internal details brushed over to the greatest extent possible.

Assignment of Values

Named properties of objects can be created, or values set on existing named properties, by assigning a value to that named property. So given:-

var objectRef = new Object(); //create a generic javascript object.

A property with the name "testNumber" can be created as:-

objectRef.testNumber = 5;
/* - or:- */
objectRef["testNumber"] = 5;

The object had no "testNumber" property prior to the assignment but one is created when the assignment is made. Any subsequent assignment does not need to create the property, it just re-sets its value:-

objectRef.testNumber = 8;
/* - or:- */
objectRef["testNumber"] = 8;

Javascript objects have prototypes that can themselves be objects, as will be described shortly, and that prototype may have named properties. But this has no role in assignment. If a value is assigned and the actual object does not have a property with the corresponding name a property of that name is created and the value is assigned to it. If it has the property then its value is re-set.

Reading of Values

It is in reading values from object properties that prototypes come into play. If an object has a property with the property name used in the property accessor then the value of that property is returned:-

/* Assign a value to a named property. If the object does not have a
   property with the corresponding name prior to the assignment it
   will have one after it:-
*/
objectRef.testNumber = 8;

/* Read the value back from the property:- */

var val = objectRef.testNumber;
/* and  - val - now holds the value 8 that was just assigned to the
   named property of the object. */
   

But all objects may have prototypes, and prototypes are objects so they, in turn, may have prototypes, which may have prototypes, and so on forming what is called the prototype chain. The prototype chain ends when one of the objects in the chain has a null prototype. The default prototype for the Object constructor has a null prototype so:-

var objectRef = new Object(); //create a generic javascript object.

Creates an object with the prototype Object.prototype that itself has a null prototype. So the prototype chain for objectRef contains only one object: Object.prototype. However:-

/* A "constructor" function for creating objects of a -
   MyObject1 - type.
*/
function MyObject1(formalParameter){
    /* Give the constructed object a property called - testNumber - and
       assign it the value passed to the constructor as its first
       argument:-
    */
    this.testNumber = formalParameter;
}

/* A "constructor" function for creating objects of a -
   MyObject2 - type:-
*/
function MyObject2(formalParameter){
   /* Give the constructed object a property called - testString -
      and assign it the value passed to the constructor as its first
      argument:-
    */
    this.testString = formalParameter;
}

/* The next operation replaces the default prototype associated with
   all MyObject2 instances with an instance of MyObject1, passing the
   argument - 8 - to the MyObject1 constructor so that its -
   testNumber - property will be set to that value:-
*/
MyObject2.prototype = new MyObject1( 8 );

/* Finally, create an instance of - MyObject2 - and assign a reference
   to that object to the variable - objectRef - passing a string as the
   first argument for the constructor:-
*/

var objectRef = new MyObject2( "String_Value" );

The instance of MyObject2 referred to by the objectRef variable has a prototype chain. The first object in that chain is the instance of MyObject1 that was created and assigned to the prototype property of the MyObject2 constructor. The instance of MyObject1 has a prototype, the object that was assigned to the function MyObject1's prototype property by the implementation. That object has a prototype, the default Object prototype that corresponds with the object referred to by Object.prototype. Object.prototype has a null prototype so the prototype chain comes to an end at this point.

When a property accessor attempts to read a named property form the object referred to by the variable objectRef the whole prototype chain can enter into the process. In the simple case:-

var val = objectRef.testString;

- the instance of MyObject2 referred to by objectRef has a property with the name "testString" so it is the value of that property, set to "String_Value", that is assigned to the variable val. However:-

var val = objectRef.testNumber;

- cannot read a named property form the instance of MyObject2 itself as it has no such property but the variable val is set to the value of 8 rather than undefined because having failed to find a corresponding named property on the object itself the interpreter then examines the object that is its prototype. Its prototype is the instance of MyObject1 and it was created with a property named "testNumber" with the value 8 assigned to that property, so the property accessor evaluates as the value 8. Neither MyObject1 or MyObject2 have defined a toString method, but if a property accessor attempts to read the value of a toString property from objectRef:-

var val = objectRef.toString;

- the val variable is assigned a reference to a function. That function is the toString property of Object.prototype and is returned because the process of examining the prototype of objectRef, when objectRef turns out not to have a "toString" property, is acting on an object, so when that prototype is found to lack the property its prototype is examined in turn. Its prototype is Object.prototype, which does have a toString method so it is a reference to that function object that is returned.

Finally:-

var val = objectRef.madeUpProperty;

- returns undefined, because as the process of working up the prototype chain finds no properties on any of the object with the name "madeUpPeoperty" it eventually gets to the prototype of Object.prototype, which is null, and the process ends returning undefined.

The reading of named properties returns the first value found, on the object or then from its prototype chain. The assigning of a value to a named property on an object will create a property on the object itself if no corresponding property already exists.

This means that if a value was assigned as objectRef.testNumber = 3 a "testNumber" property will be created on the instance of MyObject2 itself, and any subsequent attempts to read that value will retrieve that value as set on the object. The prototype chain no longer needs to be examined to resolve the property accessor, but the instance of MyObject1 with the value of 8 assigned to its "testNumber" property is unaltered. The assignment to the objectRef object masks the corresponding property in its prototype chain.

Note: ECMAScript defines an internal [[prototype]] property of the internal Object type. This property is not directly accessible with scripts, but it is the chain of objects referred to with the internal [[prototype]] property that is used in property accessor resolution; the object's prototype chain. A public prototype property exists to allow the assignment, definition and manipulation of prototypes in association with the internal [[prototype]] property. The details of the relationship between to two are described in ECMA 262 (3rd edition) and are beyond the scope of this discussion.

Identifier Resolution, Execution Contexts and scope chains

The Execution Context

An execution context is an abstract concept used by the ECMSScript specification (ECMA 262 3rd edition) to define the behaviour required of ECMAScript implementations. The specification does not say anything about how execution contexts should be implemented but execution contexts have associated attributes that refer to specification defined structures so they might be conceived (and even implemented) as objects with properties, though not public properties.

All javascript code is executed in an execution context. Global code (code executed inline, normally as a JS file, or HTML page, loads) gets executed in global execution context, and each invocation of a function (possibly as a constructor) has an associated execution context. Code executed with the eval function also gets a distinct execution context but as eval is never normally used by javascript programmers it will not be discussed here. The specified details of execution contexts are to be found in section 10.2 of ECMA 262 (3rd edition).

When a javascript function is called it enters an execution context, if another function is called (or the same function recursively) a new execution context is created and execution enters that context for the duration of the function call. Returning to the original execution context when that called function returns. Thus running javascript code forms a stack of execution contexts.

When an execution context is created a number of things happen in a defined order. First, in the execution context of a function, an "Activation" object is created. The activation object is another specification mechanism. It can be considered as an object because it ends up having accessible named properties, but it is not a normal object as it has no prototype (at least not a defined prototype) and it cannot be directly referenced by javascript code.

The next step in the creation of the execution context for a function call is the creation of an arguments object, which is an array-like object with integer indexed members corresponding with the arguments passed to the function call, in order. It also has length and callee properties (which are not relevant to this discussion, see the spec for details). A property of the Activation object is created with the name "arguments" and a reference to the arguments object is assigned to that property.

Next the execution context is assigned a scope. A scope consists of a list (or chain) of objects. Each function object has an internal [[scope]] property (which we will go into more detail about shortly) that also consists of a list (or chain) of objects. The scope that is assigned to the execution context of a function call consists of the list referred to by the [[scope]] property of the corresponding function object with the Activation object added at the front of the chain (or the top of the list).

Then the process of "variable instantiation" takes place using an object that ECMA 262 refers to as the "Variable" object. However, the Activation object is used as the Variable object (note this, it is important: they are the same object). Named properties of the Variable object are created for each of the function's formal parameters, and if arguments to the function call correspond with those parameters the values of those arguments are assigned to the properties (otherwise the assigned value is undefined). Inner function definitions are used to create function objects which are assigned to properties of the Variable object with names that correspond to the function name used in the function declaration. The last stage of variable instantiation is to create named properties of the Variable object that correspond with all the local variables declared within the function.

The properties created on the Variable object that correspond with declared local variables are initially assigned undefined values during variable instantiation, the actual initialisation of local variables does not happen until the evaluation of the corresponding assignment expressions during the execution of the function body code.

It is the fact that the Activation object, with its arguments property, and the Variable object, with named properties corresponding with function local variables, are the same object, that allows the identifier arguments to be treated as if it was a function local variable.

Finally a value is assigned for use with the this keyword. If the value assigned refers to an object then property accessors prefixed with the this keyword reference properties of that object. If the value assigned (internally) is null then the this keyword will refer to the global object.

The global execution context gets some slightly different handling as it does not have arguments so it does not need a defined Activation object to refer to them. The global execution context does need a scope and its scope chain consists of exactly one object, the global object. The global execution context does go through variable instantiation, its inner functions are the normal top level function declarations that make up the bulk of javascript code. The global object is used as the Variable object, which is why globally declared functions become properties of the global object. As do globally declared variables.

The global execution context also uses a reference to the global object for the this object.

scope chains and [[scope]]

The scope chain of the execution context for a function call is constructed by adding the execution context's Activation/Variable object to the front of the scope chain held in the function object's [[scope]] property, so it is important to understand how the internal [[scope]] property is defined.

In ECMAScript functions are objects, they are created during variable instantiation from function declarations, during the evaluation of function expressions or by invoking the Function constructor.

Function objects created with the Function constructor always have a [[scope]] property referring to a scope chain that only contains the global object.

Function objects created with function declarations or function expressions have the scope chain of the execution context in which they are created assigned to their internal [[scope]] property.

In the simplest case of a global function declaration such as:-

function exampleFunction(formalParameter){
    ...   // function body code
}

- the corresponding function object is created during the variable instantiation for the global execution context. The global execution context has a scope chain consisting of only the global object. Thus the function object that is created and referred to by the property of the global object with the name "exampleFunction" is assigned an internal [[scope]] property referring to a scope chain containing only the global object.

A similar scope chain is assigned when a function expression is executed in the global context:-

var exampleFuncRef = function(){
    ...   // function body code
}

- except in this case a named property of the global object is created during variable instantiation for the global execution context but the function object is not created, and a reference to it assigned to the named property of the global object, until the assignment expression is evaluated. But the creation of the function object still happens in the global execution context so the [[scope]] property of the created function object still only contains the global object in the assigned scope chain.

Inner function declarations and expressions result in function objects being created within the execution context of a function so they get more elaborate scope chains. Consider the following code, which defines a function with an inner function declaration and then executes the outer function:-

function exampleOuterFunction(formalParameter){
    function exampleInnerFuncitonDec(){
        ... // inner function body
    }
    ...  // the rest of the outer function body.
}

exampleOuterFunction( 5 );

The function object corresponding with the outer function declaration is created during variable instantiation in the global execution context so its [[scope]] property contains the one item scope chain with only the global object in it.

When the global code executes the call to the exampleOuterFunction a new execution context is created for that function call and an Activation/Variable object along with it. The scope of that new execution context becomes the chain consisting of the new Activation object followed by the chain refereed to by the outer function object's [[scope]] property (just the global object). Variable instantiation for that new execution context results in the creation of a function object that corresponds with the inner function definition and the [[scope]] property of that function object is assigned the value of the scope from the execution context in which it was created. A scope chain that contains the Activation object followed by the global object.

So far this is all automatic and controlled by the structure and execution of the source code. The scope chain of the execution context defines the [[scope]] properties of the function objects created and the [[scope]] properties of the function objects define the scope for their execution contexts (along with the corresponding Activation object). But ECMAScript provides the with statement as a means of modifying the scope chain.

The with statement evaluates an expression and if that expression is an object it is added to the scope chain of the current execution context (in front of the Activation/Variable object). The with statement then executes another statement (that may itself be a block statement) and then restores the execution context's scope chainto what it was before.

A function declaration could not be affected by a with statement as they result in the creation of function objects during variable instantiation, but a function expression can be evaluated inside a with statement:-

/* create a global variable - y - that refers to an object:- */
var y = {x:5}; // object literal with an - x - property
function exampleFuncWith(){
    var z;
    /* Add the object referred to by the global variable - y - to the
       front of he scope chain:-
    */
    with(y){
        /* evaluate a function expression to create a function object
           and assign a reference to that function object to the local
           variable - z - :-
        */
        z = function(){
            ... // inner function expression body;
        }
    }
    ... 
}

/* execute the - exampleFuncWith - function:- */
exampleFuncWith();

When the exampleFuncWith function is called the resulting execution context has a scope chain consisting of its Activation object followed by the global object. The execution of the with statement adds the object referred to by the global variable y to the front of that scope chain during the evaluation of the function expression. The function object created by the evaluation of the function expression is assigned a [[scope]] property that corresponds with the scope of the execution context in which it is created. A scope chain consisting of object y followed by the Activation object from the execution context of the outer function call, followed by the global object.

When the block statement associated with the with statement terminates the scope of the execution context is restored (the y object is removed), but the function object has been created at that point and its [[scope]] property assigned a reference to a scope chain with the y object at its head.

Identifier Resolution

Identifiers are resolved against the scope chain. ECMA 262 categorises this as a keyword rather than an identifier, which is not unreasonable as it is always resolved dependent on the this value in the execution context in which it is used, without reference to the scope chain.

Identifier resolution starts with the first object in the scope chain. It is checked to see if it has a property with a name that corresponds with the identifier. Because the scope chain is a chain of objects this checking encompasses the prototype chain of that object (if it has one). If no corresponding value can be found on the first object in the scope chain the search progresses to the next object. And so on until one of the objects in the chain (or one of its prototypes) has a property with a name that corresponds with the identifier or the scope chain is exhausted.

The operation on the identifier happens in the same way as the use of property accessors on objects described above. The object identified in the scope chain as having the corresponding property takes the place of the object in the property accessor and the identifier acts as a property name for that object. The global object is always at the end of the scope chain.

As execution contexts associated with function calls will have the Activation/Variable object at the front of the chain, identifiers used in function bodies are effectively first checked to see whether they correspond with formal parameters, inner function declaration names or local variables. Those would be resolved as named properties of the Activation/Variable object.

Closures

Automatic Garbage Collection

ECMAScript uses automatic garbage collection. The specification does not define the details, leaving that to the implementers to sort out, and some implementations are known to give a very low priority to their garbage collection operations. But the general idea is that if an object becomes un-referable (by having no remaining references to it left accessible to executing code) it becomes available for garbage collection and will at some future point be destroyed and any resources it is consuming freed and returned to the system for re-use.

This would normally be the case upon exiting an execution context. The scope chain structure, the Activation/Variable object and any objects created within the execution context, including function objects, would no longer be accessible and so would become available for garbage collection.

Forming Closures

A closure is formed by returning a function object that was created within an execution context of a function call from that function call and assigning a reference to that inner function to a property of another object. Or by directly assigning a reference to such a function object to, for example, a global variable, a property of a globally accessible object or an object passed by reference as an argument to the outer function call. e.g:-

function exampleClosureForm(arg1, arg2){
    var localVar = 8;
    function exampleReturned(innerArg){
        return ((arg1 + arg2)/(innerArg + localVar));
    }
    /* return a reference to the inner function defined as -
       exampleReturned -:-
    */
    return exampleReturned;
}

var globalVar = exampleClosureForm(2, 4);

Now the function object created within the execution context of the call to exampleClosureForm cannot be garbage collected because it is referred to by a global variable and is still accessible, it can even be executed with globalVar(n).

But something a little more complicated has happened because the function object now referred to by globalVar was created with a [[scope]] property referring to a scope chain containing the Activation/Variable object belonging to the execution context in which it was created (and the global object). Now the Activation/Variable object cannot be garbage collected either as the execution of the function object referred to by globalVar will need to add the whole scope chain from its [[scope]] property to the scope of the execution context created for each call to it.

A closure is formed. The inner function object has the free variables and the Activation/Variable object on the function's scope chain is the environment that binds them.

The Activation/Variable object is trapped by being referred to in the scope chain assigned to the internal [[scope]] property of the function object now referred to by the globalVar variable. The Activation/Variable object is preserved along with its state; the values of its properties. Scope resolution in the execution context of calls to the inner function will resolve identifiers that correspond with named properties of that Activation/Variable object as properties of that object. The value of those properties can still be read and set even though the execution context for which it was created has exited.

In the example above that Activation/Variable object has a state that represents the values of formal parameters, inner function definitions and local variables, at the time when the outer function returned (exited its execution context). The arg1 property has the value 2,the arg2 property the value 4, localVar the value 8 and an exampleReturned property that is a reference to the inner function object that was returned form the outer function. (We will be referring to this Activation/Variable object as "ActOuter1" in later discussion, for convenience.)

If the exampleClosureForm function was called again as:-

var secondGlobalVar = exampleClosureForm(12, 3);

- a new execution context would be created, along with a new Activation object. And a new function object would be returned, with its own distinct [[scope]] property referring to a scope chain containing the Activation object form this second execution context, with arg1 being 12 and arg2 being 3. (We will be referring to this Activation/Variable object as "ActOuter2" in later discussion, for convenience.)

A second and distinct closure has been formed by the second execution of exampleClosureForm.

The two function objects created by the execution of exampleClosureForm to which references have been assigned to the global variable globalVar and secondGlobalVar respectively, return the expression ((arg1 + arg2)/(innerArg + localVar)). Which applies various operators to four identifiers. How these identifiers are resolved is critical to the use and value of closures.

Consider the execution of the function object referred to by globalVar, as globalVar(2). A new execution context is created and an Activation object (we will call it "ActInner1"), which is added to the head of the scope chain referred to the [[scope]] property of the executed function object. ActInner1 is given a property named innerArg, after its formal parameter and the argument value 2 assigned to it. The scope chain for this new execution context is: ActInner1-> ActOuter1-> global object.

Identifier resolution is done against the scope chain so in order to return the value of the expression ((arg1 + arg2)/(innerArg + localVar)) the values of the identifiers will be determined by looking for properties, with names corresponding with the identifiers, on each object in the scope chain in turn.

The first object in the chain is ActInner1 and it has a property named innerArg with the value 2. All of the other 3 identifiers correspond with named properties of ActOuter1; arg1 is 2, arg2 is 4 and localVar is 8. The function call returns ((2 + 4)/(2 + 8)).

Compare that with the execution of the otherwise identical function object referred to by secondGlobalVar, as secondGlobalVar(5). Calling the Activation object for this new execution context "ActInner2", the scope chain becomes: ActInner2-> ActOuter2-> global object. ActInner2 returns innerArg as 5 and ActOuter2 returns arg1, arg2 and localVar as 12, 3 and 8 respectively. The value returned is ((12 + 3)/(5 + 8)).

Execute secondGlobalVar again and a new Activation object will appear at the front of the scope chain but ActOuter2 will still be next object in the chain and the value of its named properties will again be used in the resolution of the identifiers arg1, arg2 and localVar.

This is how ECMAScript inner functions gain, and maintain, access to the formal parameters, declared inner functions and local variables of the execution context in which they were created. And it is how the forming of a closure allows such a function object to keep referring to those values, reading and writing to them, for as long as it continues to exist. The Activation/Variable object from the execution context in which the inner function was created remains on the scope chain referred to by the function object's [[scope]] property, until all references to the inner function are freed and the function object is made available for garbage collection (along with any now unneeded objects on its scope chain).

Inner function may themselves have inner functions, and the inner functions returned from the execution of functions to form closures may themselves return inner functions and form closures of their own. With each nesting the scope chain gains extra Activation objects originating with the execution contexts in which the inner function objects were created. The ECMAScript specification requires a scope chain to be finite, but imposes no limits on their length. Implementations probably do impose some practical limitation but no specific magnitude has yet been reported. The potential for nesting inner functions seems so far to have exceeded anyone's desire to code them.

What can be done with Closures?

Strangely the answer to that appears to be anything and everything. I am told that closures enable ECMAScript to emulate anything, so the limitation is the ability to conceive and implement the emulation. That is a bit esoteric and it is probably better to start with something a little more practical.

Example 1: setTimeout with Function References

A common use for a closure is to provide parameters for the execution of a function prior to the execution of that function. For example, when a function is to be provided as the first argument to the setTimout function that is common in web browser environments.

setTimeout schedules the execution of a function (or a string of javascript source code, but not in this context), provided as its first argument, after an interval expressed in milliseconds (as its second argument). If a piece of code wants to use setTimeout it calls the setTimeout function and passes a reference to a function object as the first argument and the millisecond interval as the second, but a reference to a function object cannot provide parameters for the scheduled execution of that function.

However, code could call another function that returned a reference to an inner function object, with that inner function object being passed by reference to the setTimeout function. The parameters to be used for the execution of the inner function are passed with the call to the function that returns it. setTimout executes the inner function without passing arguments but that inner function can still access the parameters provided by the call to the outer function that returned it:-

function callLater(paramA, paramB, paramC){
    /* Return a reference to an anonymous inner function created
       with a function expression:-
    */
    return (function(){
        /* This inner function is to be executed with - setTimeout
           - and when it is executed it can read, and act upon, the
           parameters passed to the outer function:-
        */
        paramA[paramB] = paramC;
    });
}

...

/* Call the function that will return a reference to the inner function
   object created in its execution context. Passing the parameters that
   the inner function will use when it is eventually executed as
   arguments to the outer function. The returned reference to the inner
   function object is assigned to a local variable:-
*/
var functRef = callLater(elStyle, "display", "none");
/* Call the setTimeout function, passing the reference to the inner
   function assigned to the - functRef - variable as the first argument:-
*/
hideMenu=setTimeout(functRef, 500);

Example 2: Associating Functions with Object Instance Methods

There are many other circumstances when a reference to a function object is assigned so that it would be executed at some future time where it is useful to provide parameters for the execution of that function that would not be easily available at the time of execution but cannot be known until the moment of assignment.

One example might be a javascript object that is designed to encapsulate the interactions with a particular DOM element. It has doOnClick, doMouseOver and doMouseOut methods and wants to execute those methods when the corresponding events are triggered on the DOM element, but there may be any number of instances of the javascript object created associated with different DOM elements and the individual object instances do not know how they will be employed by the code that instantiated them. The object instances do not know how to reference themselves globally because they do not know which global variables (if any) will be assigned references to their instances.

So the problem is to execute an event handling function that has an association with a particular instance of the javascript object, and knows which method of that object to call.

The following example uses a small generalised closure based function that associates object instances with element event handlers. Arranging that the execution of the event handler calls the specified method of the object instance, passing the event object and a reference to the associated element on to the object method and returning the method's return value.

/* A general function that associates an object instance with an event
   handler. The returned inner function is used as the event handler.
   The object instance is passed as the - obj - parameter and the name
   of the method that is to be called on that object is passed as the -
   methodName - (string) parameter.
*/
function associateObjWithEvent(obj, methodName){
    /* The returned inner function is intended to act as an event
       handler for a DOM element:-
    */
    return (function(e){
        /* The event object that will have been parsed as the - e -
           parameter on DOM standard browsers is normalised to the IE
           event object if it has not been passed as an argument to the
           event handling inner function:-
        */
        e = e||window.event;
        /* The event handler calls a method of the object - obj - with
           the name held in the string - methodName - passing the now
           normalised event object and a reference to the element to
           which the event handler has been assigned using the - this -
           (which works because the inner function is executed as a
           method of that element because it has been assigned as an
           event handler):-
        */
        return obj[methodName](e, this);
    });
}

/* This constructor function creates objects that associates themselves
   with DOM elements whose IDs are passed to the constructor as a
   string. The object instances want to arrange than when the
   corresponding element triggers onclick, onmouseover and onmouseout
   events corresponding methods are called on their object instance.
*/
function DhtmlObject(elementId){
    /* A function is called that retrieves a reference to the DOM
       element (or null if it cannot be found) with the ID of the
       required element passed as its argument. The returned value
       is assigned to the local variable - el -:-
    */
    var el = getElementWithId(elementId);
    /* The value of - el - is internally type-converted to boolean for
       the - if - statement so that if it refers to an object the
       result will be true, and if it is null the result false. So that
       the following block is only executed if the - el - variable
       refers to a DOM element:-
    */
    if(el){
        /* To assign a function as the element's event handler this
           object calls the - associateObjWithEvent - function
           specifying itself (with the - this - keyword) as the object
           on which a method is to be called and providing the name of
           the method that is to be called. The - associateObjWithEvent
           - function will return a reference to an inner function that
           is assigned to the event handler of the DOM element. That
           inner function will call the required method on the
           javascript object when it is executed in response to
           events:-
        */
        el.onclick = associateObjWithEvent(this, "doOnClick");
        el.onmouseover = associateObjWithEvent(this, "doMouseOver");
        el.onmouseout = associateObjWithEvent(this, "doMouseOut");
        ...
    }
}
DhtmlObject.prototype.doOnClick = function(event, element){
    ... // doOnClick method body.
}
DhtmlObject.prototype.doMouseOver = function(event, element){
    ... // doMouseOver method body.
}
DhtmlObject.prototype.doMouseOut = function(event, element){
    ... // doMouseOut method body.
}

And so any instances of the DhtmlObject can associate themselves with the DOM element that they are interested in without any need to know anything about how they are being employed by other code, impacting on the global namespace or risking clashes with other instances of the DhtmlObject.

Example 3: Encapsulating Related Functionality

Closures can be used to create additional scopes that can be used to group interrelated and dependent code in a way that minimises the risk of accidental interaction. Suppose a function is to build a string and to avoid the repeated concatenation operations (and the creation of numerous intermediate strings) the desire is to use an array to store the parts of the string in sequence and then output the results using the Array.prototype.join method (with an empty string as its argument). The array is going to act as a buffer for the output, but defining it locally to the function will result in its re-creation on each execution of the function, which may not be necessary if the only variable content of that array will be re-assigned on each function call.

One approach might make the array a global variable so that it can be re-used without being re-created. But the consequences of that will be that, in addition to the global variable that refers to the function that will use the buffer array, there will be a second global property that refers to the array itself. The effect is to render the code less manageable, as, if it is to be used elsewhere, its author has to remember to include both the function definition and the array definition. It also makes the code less easy to integrate with other code because instead of just ensuring that the function name is unique within the global namespace it is necessary to ensure that the Array on which it is dependent is using a name that is unique within the global namespace.

A Closure allows the buffer array to be associated (and neatly packaged) with the function that is dependent upon it and simultaneously keep the property name to which the buffer array as assigned out of the global namespace and free of the risk of name conflicts and accidental interactions.

The trick here is to create one additional execution context by executing a function expression in-line and have that function expression return an inner function that will be the function that is used by external code. The buffer array is then defined as a local variable of the function expression that is executed in-line. That only happens once so the Array is only created once, but is available to the function that depends on it for repeated use.

The following code creates a function that will return a string of HTML, much of which is constant, but those constant character sequences need to be interspersed with variable information provided as parameter to the function call.

A reference to an inner function object is returned from the in-line execution of a function expression and assigned to a global variable so that it can be called as a global function. The buffer array is defined as a local variable in the outer function expression. It is not exposed in the global namespace and does not need to be re-created whenever the function that uses it is called.

/* A global variable - getImgInPositionedDivHtml - is declared and
   assigned the value of an inner function expression returned from
   a one-time call to an outer function expression.

   That inner function returns a string of HTML that represents an
   absolutely positioned DIV wrapped round an IMG element, such that
   all of the variable attribute values are provided as parameters
   to the function call:-
*/
var getImgInPositionedDivHtml = (function(){
    /* The - buffAr - Array is assigned to a local variable of the
       outer function expression. It is only created once and that one
       instance of the array is available to the inner function so that
       it can be used on each execution of that inner function.

       Empty strings are used as placeholders for the date that is to
       be inserted into the Array by the inner function:-
    */
    var buffAr = [
        '<div id="',
        '',   //index 1, DIV ID attribute
        '" style="position:absolute;top:',
        '',   //index 3, DIV top position
        'px;left:',
        '',   //index 5, DIV left position
        'px;width:',
        '',   //index 7, DIV width
        'px;height:',
        '',   //index 9, DIV height
        'px;overflow:hidden;\"><img src=\"',
        '',   //index 11, IMG URL
        '\" width=\"',
        '',   //index 13, IMG width
        '\" height=\"',
        '',   //index 15, IMG height
        '\" alt=\"',
        '',   //index 17, IMG alt text
        '\"><\/div>'
    ];
    /* Return the inner function object that is the result of the
       evaluation of a function expression. It is this inner function
       object that will be executed on each call to -
       getImgInPositionedDivHtml( ... ) -:-
    */
    return (function(url, id, width, height, top, left, altText){
        /* Assign the various parameters to the corresponding
           locations in the buffer array:-
        */
        buffAr[1] = id;
        buffAr[3] = top;
        buffAr[5] = left;
        buffAr[13] = (buffAr[7] = width);
        buffAr[15] = (buffAr[9] = height);
        buffAr[11] = url;
        buffAr[17] = altText;
        /* Return the string created by joining each element in the
           array using an empty string (which is the same as just
           joining the elements together):-
        */
        return buffAr.join('');
    }); //:End of inner function expression.
})();
/*^^- :The inline execution of the outer function expression. */

If one function was dependent on one (or several) other functions, but those other functions were not expected to be directly employed by any other code, then the same technique could be used to group those functions with the one that was to be publicly exposed. Making a complex multi-function process into an easily portable and encapsulated unit of code.

Other Examples

Probably one of the best known applications of closures is Douglas Crockford's technique for the emulation of private instance variables in ECMAScript objects. Which can be extended to all sorts of structures of scope contained nested accessibility/visibility, including the emulation of private static members for ECMAScript objects.

The possible application of closures are endless, understanding how they work is probably the best guide to realising how they can be used.

Accidental Closures

Rendering any inner function accessible outside of the body of the function in which it was created will form a closure. That makes closures very easy to create and one of the consequences is that javascript authors who do not appreciate closures as a language feature can observe the use of inner functions for various tasks and employ inner functions, with no apparent consequences, not realising that closures are being created or what the implications of doing that are.

Accidentally creating closures can have harmful side effects as the following section on the IE memory leak problem describes, but they can also impact of the efficiency of code. It is not the closures themselves, indeed carefully used they can contribute significantly towards the creation of efficient code. It is the use of inner functions that can impact on efficiency.

A common situation is where inner functions are used is as event handlers for DOM elements. For example the following code might be used to add an onclick handler to a link element:-

/* Define the global variable that is to have its value added to the
   - href - of a link as a query string by the following function:-
*/
var quantaty = 5;
/* When a link passed to this function (as the argument to the function
   call - linkRef -) an onclick event handler is added to the link that
   will add the value of a global variable - quantaty - to the - href -
   of that link as a query string, then return true so that the link
   will navigate to the resource specified by the - href - which will
   by then include the assigned query string:-
*/
function addGlobalQueryOnClick(linkRef){
    /* If the - linkRef - parameter can be type converted to true
       (which it will if it refers to an object):-
    */
    if(linkRef){
        /* Evaluate a function expression and assign a reference to the
           function object that is created by the evaluation of the
           function expression to the onclick handler of the link
           element:-
        */
        linkRef.onclick = function(){
            /* This inner function expression adds the query string to
               the - href - of the element to which it is attached as
               an event handler:-
            */
            this.href += ('?quantaty='+escape(quantaty));
            return true;
        };
    }
}

Whenever the addGlobalQueryOnClick function is called a new inner function is created (and a closure formed by its assignment). From the efficiency point of view that would not be significant if the addGlobalQueryOnClick function was only called once or twice, but if the function was heavily employed many distinct function objects would be created (one for each evaluation of the inner function expression).

The above code is not taking advantage of the fact that inner functions are becoming accessible outside of the function in which they are being created (or the resulting closures). As a result exactly the same effect could be achieved by defining the function that is to be used as the event handler separately and then assigning a reference to that function to the event handling property. Only one function object would be created and all of the elements that use that event handler would share a reference to that one function:-

/* Define the global variable that is to have its value added to the
   - href - of a link as a query string by the following function:-
*/
var quantaty = 5;

/* When a link passed to this function (as the argument to the function
   call - linkRef -) an onclick event handler is added to the link that
   will add the value of a global variable - quantaty - to the - href -
   of that link as a query string, then return true so that the link
   will navigate to the resource specified by the - href - which will
   by then include the assigned query string:-
*/
function addGlobalQueryOnClick(linkRef){
    /* If the - linkRef - parameter can be type converted to true
       (which it will if it refers to an object):-
    */
    if(linkRef){
        /* Assign a reference to a global function to the event
           handling property of the link so that it becomes the
           element's event handler:-
        */
        linkRef.onclick = forAddQueryOnClick;
    }
}
/* A global function declaration for a function that is intended to act
   as an event handler for a link element, adding the value of a global
   variable to the - href - of an element as an event handler:-
*/
function forAddQueryOnClick(){
    this.href += ('?quantaty='+escape(quantaty));
    return true;
}

As the inner function in the first version is not being used to exploit the closures produced by its use, it would be more efficient not to use an inner function, and thus not repeat the process of creating many essentially identical function objects.

A similar consideration applies to object constructor functions. It is not uncommon to see code similar to the following skeleton constructor:-

function ExampleConst(param){
    /* Create methods of the object by evaluating function expressions
       and assigning references to the resulting function objects
       to the properties of the object being created:-
    */
    this.method1 = function(){
        ... // method body.
    };
    this.method2 = function(){
        ... // method body.
    };
    this.method3 = function(){
        ... // method body.
    };
    /* Assign the constructor's parameter to a property of the object:-
    */
    this.publicProp = param;
}

Each time the constructor is used to create an object, with new ExampleConst(n), a new set of function objects are created to act as its methods. So the more object instances that are created the more function objects are created to go with them.

Douglas Crockford's technique for emulating private members on javascript objects exploits the closure resulting form assigning references to inner function objects to the public properties of a constructed object from within its constructor. But if the methods of an object are not taking advantage of the closure that they will form within the constructor the creation of multiple function objects for each object instantiation will make the instantiation process slower and more resources will be consumed to accommodate the extra function objects created.

In that case it would be more efficient to create the function object once and assign references to them to the corresponding properties of the constructor's prototype so they may be shared by all of the objects created with that constructor:-

function ExampleConst(param){
    /* Assign the constructor's parameter to a property of the object:-
    */
    this.publicProp = param;
}
/* Create methods for the objects by evaluating function expressions
   and assigning references to the resulting function objects to the
   properties of the constructor's prototype:-
*/
ExampleConst.prototype.method1 = function(){
    ... // method body.
};
ExampleConst.prototype.method2 = function(){
    ... // method body.
};
ExampleConst.prototype.method3 = function(){
    ... // method body.
};

The Internet Explorer Memory Leak Problem

The Internet Explorer web browser (verified on versions 4 to 6 (6 is current at the time of writing)) has a fault in its garbage collection system that prevents it from garbage collecting ECMAScript and some host objects if those host objects form part of a "circular" reference. The host objects in question are any DOM Nodes (including the document object and its descendants) and ActiveX objects. If a circular reference is formed including one or more of them, then none of the objects involved will be freed until the browser is closed down, and the memory that they consume will be unavailable to the system until that happens.

A circular reference is when two or more objects refer to each other in a way that can be followed and lead back to the starting point. Such as object 1 has a property that refers to object 2, object 2 has a property that refers to object 3 and object 3 has a property that refers back to object 1. With pure ECMAScript objects as soon as no other objects refer to any of objects 1, 2 or 3 the fact that they only refer to each other is recognised and they are made available for garbage collection. But on Internet Explorer, if any of those objects happen to be a DOM Node or ActiveX object, the garbage collection cannot see that the circular relationship between them is isolated from the rest of the system and free them. Instead they all stay in memory until the browser is closed.

Closures are extremely good at forming circular references. If a function object that forms a closure is assigned as, for example, and event handler on a DOM Node, and a reference to that Node is assigned to one of the Activation/Variable objects in its scope chain then a circular reference exists. DOM_Node.onevent -> function_object.[[scope]] -> scope_chain -> Activation_object.nodeRef -> DOM_Node. It is very easy to do, and a bit of browsing around a site that forms such a reference in a piece of code common to each page can consume most of the systems memory (possibly all).

Care can be taken to avoid forming circular references and remedial action can be taken when they cannot otherwise be avoided, such as using IE's onunload event to null event handling function references. Recognising the problem and understanding closures (and their mechanism) is the key to avoiding this problem with IE.

comp.lang.javascript FAQ notes T.O.C.

  • Written by Richard Cornford. March 2004.
  • With corrections and suggestions by:-
    • Martin Honnen.
    • Yann-Erwan Perio (Yep).
    • Lasse Reichstein Nielsen. (definition of closure)
    • Mike Scirocco.
    • Dr John Stockton.
    • Garrett Smith.

 

Posted by 1010
반응형

자바스크립트의 메모리관리

개요

C 언어같은 저급 언어는 메모리 관리를 위해 malloc() 과 free()를 사용한다. 반면, 자바스크립트는 무언가가 생성되었을 때(오브젝트나 문자열 등) 메모리를 할당하고 쓸모 없어졌을 때 '자동으로' free 한다. '자동으로' 라는 말에는 혼란의 여지가 있다. 이는 자바스크립트를 포함한 여러 고급 언어 개발자들에게 메모리 관리가 불가능하다는 인상을 준다. 하지만 실상은 그렇지 않다.  

메모리 생존주기

메모리 생존주기는 프로그래밍 언어와 관계없이 비슷하다.

  1. 필요할때 할당한다.
  2. 사용한다. (읽기, 쓰기)
  3. 필요없어지면 해제한다. 

첫 번째 부분과 두 번째 부분은 모든 언어에서 분명하게 기술되지만 마지막 부분은 조금 다르다. 저급 언어에서는 분명히 기술되지만 자바스크립트 같은 고급 언어에서는 분명하게 기술되지 않는다(역자: 명시적으로 free를 하지 않는다는 의미). 

자바스크립트에서 메모리 할당

값 초기화

자바스크립트에서는 프로그래머들이 일일히 메모리 할당을 하는 수고를 덜어주기위해 값을 선언할 때 메모리를 할당한다. 

var n = 123; // 정수를 담기 위한 메모리 할당
var s = "azerty"; // 문자열을 담기 위한 메모리 할당

var o = {
  a: 1,
  b: null
}; // 오브젝트와 그 오브젝트에 포함된 값들을 담기 위한 메모리 할당

var a = [1, null, "abra"]; // (오브젝트 처럼) 배열과 배열에 담긴 값들을 위한 메모리 할당

function f(a){
  return a + 2;
} // 함수를 위한 할당(함수는 '호출가능한' 오브젝트이다)

// 함수식 또한 오브젝트를 담기위한 메모리를 할당한다. 
someElement.addEventListener('click', function(){
  someElement.style.backgroundColor = 'blue';
}, false);

함수 호출을 통한 할당

몇 가지 함수에서도 메모리 할당이 일어난다. 

var d = new Date();
var e = document.createElement('div'); // DOM 엘리먼트를 위해 메모리를 할당한다.

몇 가지 메쏘드도 새로운 값이나 오브젝트를 담기 위해 메모리 할당이 일어난다.

var s = "azerty";
var s2 = s.substr(0, 3); // s2는 새로운 문자열
// 자바스크립트에서 문자열은 immutable 값이기 때문에 메모리를 새로 할당하지 않고 단순히 [0, 3] 이라는 범위만 저장한다. 

var a = ["ouais ouais", "nan nan"];
var a2 = ["generation", "nan nan"];
var a3 = a.concat(a2); // 4개의 원소를 가진 새로운 배열

값 사용

값 사용이란 기본적으로는 할당된 메모리를 읽고 쓰는 것을 의미한다. 변수나 오브젝트 속성 값을 읽고 쓸때 값 사용이 일어난다. 또 함수 호출시 함수에 인수를 넘길때도 일어난다. 

할당된 메모리가 더 이상 필요없을 때 해제하기

이 단계에서 대부분의 문제가 발생한다. "할당된 메모리가 더 이상 필요없을 때"를 알아내기가 힘들기 때문이다. 이제까지는 개발자들이 메모리가 필요없어질 때를 정하고 free하곤 했다. 

고급 언어 인터프리터는 "가비지 콜렉터"라는 소프트웨어를 가지고 있다. 가비지 콜렉터란 메모리 할당을 추적하고 할당된 메모리가 더 이상 필요 없어졌을 때 해제하는 작업을 한다. 이 작업은 근사적인 작업이다. 왜냐하면 일반적인 경우에 어떤 메모리가 필요없는지 알아내는 것은 알고리즘으로 풀 수 없는 비결정적인 문제이기 때문이다. (역자: 세상에 존재하는 모든 가비지 콜렉터는 안전하지만 완전하지 않다. 가비지 콜렉터는 항상 필요없어진 메모리만을 해제하지만 모든 필요없어진 메모리를 해제하는건 아니다)

가비지 콜렉션

위에서 언급한 것처럼 "더 이상 필요없는" 모든 메모리를 찾는건 비결정적이다. 따라서 몇 가지 제한을 두어 "더 이상 필요없는 모든 메모리"가 아니라 "더 이상 필요없는 몇몇 메모리"를 찾아보자. 몇 개의 가비지 콜렉션 알고리즘을 소개하고 한계점을 알아볼 것이다.

참조

가비지 콜렉션 알고리즘의 핵심 개념은 참조이다. A라는 메모리를 통해 (명시적이든 암시적이든) B라는 메모리에 접근할 수 있다면 "B는 A에 참조된다" 라고 한다. 예를 들어 모든 자바스크립트 오브젝트는 prototype 을 암시적으로 참조하고 그 오브젝트의 속성을 명시적으로 참조한다.

앞으로 "오브젝트"라는 어휘의 의미를 넓혀서 기존의 자바스크립트 오브젝트뿐만 아니라 함수 스코프도 포괄하자.

참조-세기(Reference-counting) 가비지 콜렉션

참조-세기 알고리즘은 가장 무난한 알고리즘이다. 이 알고리즘은 "더 이상 필요없는 오브젝트"를 "어떤 다른 오브젝트도 참조하지 않는 오브젝트"라고 정의한다. 어떤 오브젝트를 참조하는 다른 오브젝트가 하나도 없다면 그 오브젝트에 대해 가비지 콜렉션을 수행한다.

예제

var o = { 
  a: {
    b:2
  }
}; // 2개의 오브젝트가 생성되었다. 하나의 오브젝트는 다른 오브젝트의 속성으로 참조된다.
// 나머지 하나는 'o' 변수에 할당되었다.
// 명백하게 가비지 콜렉션 수행될 메모리는 하나도 없다.


var o2 = o; // 'o2' 변수는 위의 오브젝트를 참조하는 두 번째 변수이다.
o = 1; // 이제 'o2' 변수가 위의 오브젝트를 참조하는 유일한 변수가 되었다.

var oa = o2.a; // 위의 오브젝트의 'a' 속성을 참조했다.
// 이제 'o2.a'는 두 개의 참조를 가진다. 'o2'가 속성으로 참조하고 'oa'라는 변수가 참조한다.

o2 = "yo"; // 이제 맨 처음 'o' 변수가 참조했던 오브젝트를 참조하는 오브젝트는 없다(역자: 참조하는 유일한 변수였던 o2에 다른 값을 대입했다)
// 이제 오브젝트에 가비지 콜렉션이 수행될 수 있을까?
// 아니다. 오브젝트의 'a' 속성이 여전히 'oa' 변수에 의해 참조되므로 메모리를 해제할 수 없다.

oa = null; // 'oa' 변수에 다른 값을 할당했다. 이제 맨 처음 'o' 변수가 참조했던 오브젝트를 참조하는 다른 변수는 없으므로 가비지 콜렉션이 수행된다.

한계: 순환

이 알고리즘은 두 오브젝트가 서로를 참조하면 문제가 발생한다. 두 오브젝트 모두 필요 없어졌더라도 가비지 콜렉션을 수행할 수 없다.

function f(){
  var o = {};
  var o2 = {};
  o.a = o2; // o는 o2를 참조한다.
  o2.a = o; // o2는 o를 참조한다.

  return "azerty";
}

f();
// 두 오브젝트가 만들어지고 서로를 참조해서 순환이 일어났다.
// 함수가 종료되고 나면 사실상 두 오브젝트는 의미가 없어지므로 가비지 콜렉션이 수행되어야 한다.
// 그러나 위의 참조-세기 알고리즘에서는 두 오브젝트 모두 참조를 가지고 있기 때문에 둘 다 가비지 콜렉션이 일어나지 않는다.

실제 예제

인터넷 익스플로러 6, 7 은 DOM 오브젝트에 대해 참조-세기 알고리즘으로 가비지 콜렉션을 수행한다. 흔히, 이 두 브라우저에서는 다음과 같은 패턴의 메모리 누수가 발생한다. 

var div = document.createElement("div");
div.onclick = function(){
  doSomething();
}; // div 오브젝트는 이벤트 핸들러를 'onclick' 속성을 통해 참조한다.
// 이벤트 핸들러의 스코프에도 div 오브젝트가 있으므로 div 오브젝트에 접근할 수 있다. 따라서 이벤트 핸들러도 div 오브젝트를 참조한다.
// 순환이 발생했고 메모리 누수가 일어난다.

표시하고-쓸기(Mark-and-sweep) 알고리즘

이 알고리즘은 "더 이상 필요없는 오브젝트"를 "닿을 수 없는 오브젝트"로 정의한다.

이 알고리즘은 roots 라는 오브젝트의 집합을 가지고 있다(자바스크립트에서는 전역 변수들을 의미한다). 주기적으로 가비지 콜렉터는 roots로 부터 시작하여 roots가 참조하는 오브젝트들, roots가 참조하는 오브젝트가 참조하는 오브젝트들... 을 닿을 수 있는 오브젝트라고 표시한다. 그리고 닿을 수 있는 오브젝트가 아닌 닿을 수 없는 오브젝트에 대해 가비지 콜렉션을 수행한다.

이 알고리즘은 위에서 설명한 참조-세기 알고리즘보다 효율적이다. 왜냐하면 "참조되지 않는 오브젝트"는 모두 "닿을 수 없는 오브젝트" 이지만 역은 성립하지 않기 때문이다. 위에서 반례인 순환 참조하는 오브젝트들을 설명했다.

2012년 기준으로 모든 최신 브라우저들은 가비지 콜렉션에서 표시하고-쓸기 알고리즘을 사용한다. 지난 몇 년간 연구된 자바스크립트 가비지 콜렉션 알고리즘의 개선들은 모두 이 알고리즘에 대한 것이다. 개선된 알고리즘도 여전히 "더 이상 필요없는 오브젝트"를 "닿을 수 없는 오브젝트"로 정의하고 있다.

순환 참조는 이제 문제가 되지 않는다.

첫 번째 예제에서 함수가 리턴되고 나서 두 오브젝트는 닿을 수 없다. 따라서 가비지 콜렉션이 일어난다.

두 번째 예제에서도 마찬가지다. div 변수와 이벤트 핸들러가 roots로 부터 닿을 수 없어지면 순환 참조가 일어났음에도 불구하고 가비지 콜렉션이 일어난다.

한계: 오브젝트들은 명시적으로 닿을 수 없어져야 한다.

이 한계가 지적되었지만 실제로는 사람들은 이 문제를 비롯한 가비지 콜렉션에 별 관심이 없다.

더 보기

출처 : https://developer.mozilla.org/ko/docs/JavaScript/Memory_Management

Posted by 1010
반응형

The purpose of the <object> element is to support HTML helpers (plug-ins).


HTML Helpers (Plug-ins)

A helper application is a small computer program that extends the standard functionality of the browser. Helper applications are also called plug-ins.

Plug-ins are often used by browsers to play audio and video.

Examples of well-known plug-ins are Adobe Flash Player and QuickTime.

Plug-ins can be added to Web pages through the <object> tag or the <embed> tag. 

Most plug-ins allow manual (or programmed) control over settings for volume, rewind, forward, pause, stop, and play.


What is The Best Way to Play Audio/Video in HTML?

For the best way to embed audio or video in your Web page, please read the next chapters.


QuickTime - Play WAV Audio

Example

<object width="420" height="360"
classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B"
codebase="http://www.apple.com/qtactivex/qtplugin.cab">
<param name="src" value="liar.wav">
<param name="controller" value="true">
</object>

Try it yourself »


 


QuickTime - Play MP4 Video

Example

<object width="420" height="360"
classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B"
codebase="http://www.apple.com/qtactivex/qtplugin.cab">
<param name="src" value="movie.mp4">
<param name="controller" value="true">
</object>

Try it yourself »


 


Adobe Flash Player - Play SWF Video

Example

<object width="400" height="40"
classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
codebase="http://fpdownload.macromedia.com/
pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0">
< param name="SRC" value="bookmark.swf">
< embed src="bookmark.swf" width="400" height="40">
< /embed>
< /object>

Try it yourself »


 


Windows Media Player - Play WMV Movie

The example below shows the suggested code used to display a Windows Media file.

Example

<object width="100%" height="100%"
type="video/x-ms-asf" url="3d.wmv" data="3d.wmv"
classid="CLSID:6BF52A52-394A-11d3-B153-00C04F79FAA6">
<param name="url" value="3d.wmv">
<param name="filename" value="3d.wmv">
<param name="autostart" value="1">
<param name="uiMode" value="full">
<param name="autosize" value="1">
<param name="playcount" value="1">
<embed type="application/x-mplayer2" src="3d.wmv" width="100%" height="100%" autostart="true" showcontrols="true" pluginspage="http://www.microsoft.com/Windows/MediaPlayer/"></embed>
</object>

Try it yourself »


 


Plug-ins

Plug-ins can be used for many purposes: to display maps, scan for viruses, verify your bank id, and much more. The restrictions are few.

 

출처 : http://www.w3schools.com/html/html_object.asp

Posted by 1010
반응형

<!DOCTYPE html>
 <html>
 <body>

<object type="audio/x-wav" data="http://www.hydrotoys.com/wavs/Beavis_cornholio.wav" width="320" height="260">
<param name="autostart" value="true" />
<param name="controller" value="false" />
<param name="src" value="http://www.hydrotoys.com/wavs/Beavis_cornholio.wav">
</object>

<audio src="http://www.hydrotoys.com/wavs/Beavis_cornholio.wav" type="audio/x-wav" controls autoplay="autoplay">
<p>Your browser does not support the audio element </p>
<source src="http://www.hydrotoys.com/wavs/Beavis_cornholio.wav"/>
</audio>

</body>
</html>

출처 :http://stackoverflow.com/questions/12973877/autoplay-a-wav-file-on-html-code

 

Posted by 1010
반응형

부모

var retValue;
var myObject = new Object();
myObject.tempid = id; // 넘길 값

retValue = window.showModalDialog("팝업페이지", window, "dialogWidth:850px; dialogHeight:500px; center:yes; help:no; resizable:yes; scroll:no; status:no;");

function test(){

}

자식
var oMyObject = window.dialogArguments;// 팝업 실행 하는 페이지에서 값을 받아옴

temp(oMyObject.id); // 값을 넘겨줌..

부모창에 함수호출

oMyObject.test();

Posted by 1010
반응형

 

swfobject_2_2.zip

 

What is SWFObject?

SWFObject 2:

  • Offers two optimized Flash Player embed methods; a markup based approach and a method that relies on JavaScript
  • Offers a JavaScript API that aims to provide a complete tool set for embedding SWF files and retrieving Flash Player related information
  • Utilizes only one small JavaScript file (10Kb / GZIPed: 3.9Kb)
  • Is the successor of SWFObject 1.5, UFO and the Adobe Flash Player Detection Kit
  • Intends to unify all existing Flash Player embed methods and provide a new standard for embedding Adobe Flash Player content

Why should you use SWFObject?

SWFObject 2:

  • Is more optimized and flexible than any other Flash Player embed method around
  • Offers one solution for everybody: It shouldn't matter if you are an HTML, Flash, or JavaScript developer, there should be something in it for everyone
  • Breaks the cycle of being locked into vendor specific markup and promotes the use of web standards and alternative content
  • Uses unobtrusive JavaScript and JavaScript best practices
  • Is easy to use

The A List Apart article Flash Embedding Cage Match describes the full rationale behind SWFObject 2.

Why does SWFObject use JavaScript?

SWFObject 2 primarily uses JavaScript to overcome issues that cannot be solved by markup alone; it:

  • Detects the Flash Player version and determines whether Flash content or alternative content should be shown, to avoid that outdated Flash plug-ins break Flash content
  • Offers functionality to revert to alternative content in case of an outdated plug-in by means of a DOM manipulation (Note: if no Flash plug-in is installed the HTML object element automatically falls back to its nested alternative content)
  • Offers the option to use Adobe Express Install to download the latest Flash Player
  • Offers a JavaScript API to perform common Flash Player and Flash content related tasks

Should I use the static or dynamic publishing method?

SWFObject 2 offers two distinct methods to embed Flash Player content:

  1. The static publishing method embeds both Flash content and alternative content using standards compliant markup, and uses JavaScript to resolve the issues that markup alone cannot solve
  2. The dynamic publishing method is based on marked up alternative content and uses JavaScript to replace this content with Flash content if the minimal Flash Player version is installed and enough JavaScript support is available (similar like previous versions of SWFObject and UFO)

The advantages of the static publishing method are:

  1. The actual authoring of standards compliant markup is promoted
  2. Best embed performance
  3. The mechanism of embedding Flash content does not rely on a scripting language, so your Flash content can reach a significant bigger audience:
    • If you have the Flash plug-in installed, but have JavaScript disabled or a use a browser that doesn't support JavaScript, you will still be able to see your Flash content
    • Flash will now also run on a device like Sony PSP, which has very poor JavaScript support
    • Automated tools like RSS readers are able to pick up Flash content

The advantages of the dynamic publishing method are:

  1. It integrates very well with scripted applications and enables the use of dynamic variables (flashvars)
  2. It avoids click-to-activate mechanisms to activate active content in Internet Explorer 6/7 and Opera 9+. Please note that Microsoft has phased out most active content from its Internet Explorer browsers

How to embed Flash Player content using SWFObject static publishing

STEP 1: Embed both Flash content and alternative content using standards compliant markup

SWFObject's base markup uses the nested-objects method (with proprietary Internet Explorer conditional comments. See Flash Embedding Cage Match) to ensure the most optimal cross-browser support by means of markup only, while being standards compliant and supporting alternative content (See Flash Embed Test Suite):

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title>SWFObject - step 1</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
</head>
<body>
<div>

<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="780" height="420">
<param name="movie" value="myContent.swf" />
<!--[if !IE]>-->
<object type="application/x-shockwave-flash" data="myContent.swf" width="780" height="420">
<!--<![endif]-->
<p>Alternative content</p>
<!--[if !IE]>-->
</object>
<!--<![endif]-->
</object>

</div>
</body>
</html>

NOTE: The nested-objects method requires a double object definition (the outer object targeting Internet Explorer and the inner object targeting all other browsers), so you need to define your object attributes and nested param elements twice.

Required attributes:

  • classid (outer object element only, value is always clsid:D27CDB6E-AE6D-11cf-96B8-444553540000)
  • type (inner object element only, value is always application/x-shockwave-flash)
  • data (inner object element only, defines the URL of a SWF)
  • width (both object elements, defines the width of a SWF)
  • height (both object elements, defines the height of a SWF)

Required param element:

  • movie (outer object element only, defines the URL of a SWF)

NOTE: We advise not to use the codebase attribute to point to the URL of the Flash plugin installer on Adobe's servers, because this is illegal according to the specifications which restrict its access to the domain of the current document only. We recommend the use of alternative content with a subtle message that a user can have a richer experience by downloading the Flash plugin instead.

How can you use HTML to configure your Flash content?

You can add the following often-used optional attributes to the object element:

  • id
  • name
  • class
  • align

You can use the following optional Flash specific param elements (more info):

Why should you use alternative content?

The object element allows you to nest alternative content inside of it, which will be displayed if Flash is not installed or supported. This content will also be picked up by search engines, making it a great tool for creating search-engine-friendly content. Summarizing, you should use alternative content when you like to create content that is accessible for people who browse the Web without plugins, create search-engine-friendly content or tell visitors that they can have a richer user experience by downloading the Flash plug-in.

STEP 2: Include the SWFObject JavaScript library in the head of your HTML page

The SWFObject library consists of one external JavaScript file. SWFObject will be executed as soon as it is read and will perform all DOM manipulations as soon as the DOM is loaded - for all browsers that support this, like IE, Firefox, Safari and Opera 9+ - or otherwise as soon as the onload event fires:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title>SWFObject - step 2</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />

<script type="text/javascript" src="swfobject.js"></script>

</head>
<body>
<div>
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="780" height="420">
<param name="movie" value="myContent.swf" />
<!--[if !IE]>-->
<object type="application/x-shockwave-flash" data="myContent.swf" width="780" height="420">
<!--<![endif]-->
<p>Alternative content</p>
<!--[if !IE]>-->
</object>
<!--<![endif]-->
</object>
</div>
</body>
</html>

STEP 3: Register your Flash content with the SWFObject library and tell SWFObject what to do with it

First add a unique id to the outer object tag that defines your Flash content. Second add the swfobject.registerObject method:

  1. The first argument (String, required) specifies the id used in the markup.
  2. The second argument (String, required) specifies the Flash player version your content is published for. It activates the Flash version detection for a SWF to determine whether to show Flash content or force alternative content by doing a DOM manipulation. While Flash version numbers normally consist of major.minor.release.build, SWFObject only looks at the first 3 numbers, so both "WIN 9,0,18,0" (IE) or "Shockwave Flash 9 r18" (all other browsers) will translate to "9.0.18". If you only want to test for a major version you can omit the minor and release numbers, like "9" instead of "9.0.0".
  3. The third argument (String, optional) can be used to activate Adobe express install and specifies the URL of your express install SWF file. Express install displays a standardized Flash plugin download dialog instead of your Flash content when the required plugin version is not available. A default expressInstall.swf file is packaged with the project. It also contains the corresponding expressInstall.fla and AS files (in the SRC directory) to let you create your own custom express install experience. Please note that express install will only fire once (the first time that it is invoked), that it is only supported by Flash Player 6.0.65 or higher on Win or Mac platforms, and that it requires a minimal SWF size of 310x137px.
  4. The fourth argument (JavaScript function, optional) can be used to define a callback function that is called on both success or failure of creating a Flash plug-in <object> on the page (see API documentation)
  5. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
    <head>
    <title>SWFObject - step 3</title>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
    <script type="text/javascript" src="swfobject.js"></script>

    <script type="text/javascript">
    swfobject
    .registerObject("myId", "9.0.115", "expressInstall.swf");
    </script>

    </head>
    <body>
    <div>

    <object id="myId" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="780" height="420">

    <param name="movie" value="myContent.swf" />
    <!--[if !IE]>-->
    <object type="application/x-shockwave-flash" data="myContent.swf" width="780" height="420">
    <!--<![endif]-->
    <p>Alternative content</p>
    <!--[if !IE]>-->
    </object>
    <!--<![endif]-->
    </object>
    </div>
    </body>
    </html>

TIPS

  • Use the SWFObject HTML and JavaScript generator to help you author your code
  • Just repeat steps 1 and 3 to embed multiple SWF files into one HTML page
  • The easiest way to reference the active object element is by using the JavaScript API: `swfobject.getObjectById(objectIdStr)

How to embed Flash Player content using SWFObject dynamic publishing

STEP 1: Create alternative content using standards compliant markup

SWFObject's dynamic embed method follows the principle of progressive enhancement and replaces alternative HTML content for Flash content when enough JavaScript and Flash plug-in support is available. First define your alternative content and label it with an id:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title>SWFObject dynamic embed - step 1</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
</head>
<body>

<div id="myContent">
<p>Alternative content</p>
</div>

</body>
</html>

STEP 2: Include the SWFObject JavaScript library in the head of your HTML page

The SWFObject library consists of one external JavaScript file. SWFObject will be executed as soon as it is read and will perform all DOM manipulations as soon as the DOM is loaded - for all browsers that support this, like IE, Firefox, Safari and Opera 9+ - or otherwise as soon as the onload event fires:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title>SWFObject dynamic embed - step 2</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />

<script type="text/javascript" src="swfobject.js"></script>

</head>
<body>
<div id="myContent">
<p>Alternative content</p>
</div>
</body>
</html>

STEP 3: Embed your SWF with JavaScript

swfobject.embedSWF(swfUrl, id, width, height, version, expressInstallSwfurl, flashvars, params, attributes, callbackFn) has five required and five optional arguments:

  1. swfUrl (String, required) specifies the URL of your SWF
  2. id (String, required) specifies the id of the HTML element (containing your alternative content) you would like to have replaced by your Flash content
  3. width (String, required) specifies the width of your SWF
  4. height (String, required) specifies the height of your SWF
  5. version (String, required) specifies the Flash player version your SWF is published for (format is: "major.minor.release" or "major")
  6. expressInstallSwfurl (String, optional) specifies the URL of your express install SWF and activates Adobe express install. Please note that express install will only fire once (the first time that it is invoked), that it is only supported by Flash Player 6.0.65 or higher on Win or Mac platforms, and that it requires a minimal SWF size of 310x137px.
  7. flashvars (Object, optional) specifies your flashvars with name:value pairs
  8. params (Object, optional) specifies your nested object element params with name:value pairs
  9. attributes (Object, optional) specifies your object's attributes with name:value pairs
  10. callbackFn (JavaScript function, optional) can be used to define a callback function that is called on both success or failure of creating a Flash plug-in <object> on the page (see API documentation)

NOTE: You can omit the optional parameters, as long as you don't break the parameter order. If you don't want to use an optional parameter, but would like to use a following optional parameter, you can simply pass false as its value. For the flashvars, params and attributes JavaScript Objects, you can also pass an empty object instead: {}.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title>SWFObject dynamic embed - step 3</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<script type="text/javascript" src="swfobject.js"></script>

<script type="text/javascript">
swfobject
.embedSWF("myContent.swf", "myContent", "300", "120", "9.0.0");
</script>

</head>
<body>
<div id="myContent">
<p>Alternative content</p>
</div>
</body>
</html>

How can you configure your Flash content?

You can add the following often-used optional attributes to the object element:

  • id (NOTE: when undefined, the object element automatically inherits the id from the alternative content container element)
  • align
  • name
  • styleclass (see note about class)
  • class

Note: class is a reserved ECMA4 keyword and will throw errors in Internet Explorer unless it is surrounded by quotation marks (e.g. "class" or 'class'). For this reason, swfobject provides the styleclass keyword as a safe alternative syntax for class; if you use styleclass, swfobject will automatically insert it as class for you.

Example:

var attributes = {
id
: "myId",
align
: "left",
styleclass
: "myclass"
};

If you would rather use class instead of styleclass, wrap the word class in quotes like this:

var attributes = {
id
: "myId",
align
: "left",
"class": "myclass"
};

You can use the following optional Flash specific param elements (more info):

How do you use JavaScript Objects to define your flashvars, params and object's attributes?

You can best define JavaScript Objects using the Object literal notation, which looks like:

<script type="text/javascript">

var flashvars = {};
var params = {};
var attributes = {};

swfobject
.embedSWF("myContent.swf", "myContent", "300", "120", "9.0.0","expressInstall.swf", flashvars, params, attributes);

</script>

You can add your name:value pairs while you define an object (note: please make sure not to put a comma behind the last name:value pair inside an object)

<script type="text/javascript">

var flashvars = {
name1
: "hello",
name2
: "world",
name3
: "foobar"
};
var params = {
menu
: "false"
};
var attributes = {
id
: "myDynamicContent",
name
: "myDynamicContent"
};

swfobject
.embedSWF("myContent.swf", "myContent", "300", "120", "9.0.0","expressInstall.swf", flashvars, params, attributes);

</script>

Or add properties and values after its creation by using a dot notation:

<script type="text/javascript">

var flashvars = {};
flashvars
.name1 = "hello";
flashvars
.name2 = "world";
flashvars
.name3 = "foobar";

var params = {};
params
.menu = "false";

var attributes = {};
attributes
.id = "myDynamicContent";
attributes
.name = "myDynamicContent";

swfobject
.embedSWF("myContent.swf", "myContent", "300", "120", "9.0.0","expressInstall.swf", flashvars, params, attributes);

</script>

Which can also be written as (the less readable shorthand version for the die-hard scripter who love one-liners):

<script type="text/javascript">

swfobject
.embedSWF("myContent.swf", "myContent", "300", "120", "9.0.0","expressInstall.swf", {name1:"hello",name2:"world",name3:"foobar"}, {menu:"false"}, {id:"myDynamicContent",name:"myDynamicContent"});

</script>

If you don't want to use an optional argument you can define it as false or as an empty Object (NOTE: from SWFObject 2.1 onwards you can also use null or 0):

<script type="text/javascript">

var flashvars = false;
var params = {};
var attributes = {
id
: "myDynamicContent",
name
: "myDynamicContent"
};

swfobject
.embedSWF("myContent.swf", "myContent", "300", "120", "9.0.0","expressInstall.swf", flashvars, params, attributes);

</script>

The flashvars Object is a shorthand notation that is there for your ease of use. You could potentially ignore it and specify your flashvars via the params Object:

<script type="text/javascript">

var flashvars = false;
var params = {
menu
: "false",
flashvars
: "name1=hello&name2=world&name3=foobar"
};
var attributes = {
id
: "myDynamicContent",
name
: "myDynamicContent"
};

swfobject
.embedSWF("myContent.swf", "myContent", "300", "120", "9.0.0","expressInstall.swf", flashvars, params, attributes);

</script>

TIPS

SWFObject 1.5 to SWFObject 2 migration tips

  1. SWFObject 2 is NOT backwards compatible with SWFObject 1.5
  2. It is now preferred to insert all script blocks in the head of your HTML page. Adding your scripts in the body of your page may have visual impact (e.g. flashes of replaced alternative content), because your JavaScript code will be executed in a later stage (the exact impact depends on your implementation)
  3. The library itself is now written in lowercase: swfobject instead of SWFObject
  4. Methods can only be accessed via the library (instead via a SWFObject instance in SWFObject 1.5)
  5. The JavaScript API is entirely different and more elaborate
  6. SWFObject 2 replaces your entire alternative HTML content block, including the referenced HTML container element, for Flash content when enough JavaScript and Flash support is available, while SWFObject 1.5 only replaces the content inside the referenced HTML container. When you don't specify an id attribute, the object element will automatically inherit the id of the HTML container element of your alternative content.

UFO to SWFObject 2 migration tips

  1. SWFObject 2 replaces your entire alternative HTML content block, including the referenced HTML container element, for Flash content when enough JavaScript and Flash support is available, while UFO only replaces the content inside the referenced HTML container. When you don't specify an id attribute, the object element will automatically inherit the id of the HTML container element of your alternative content.
  2. UFO's setcontainercss feature has not been incorporated in SWFObject 2, however it can easily be replicated by using the SWFObject JavaScript API, see: swfobject.createCSS(selStr, declStr)

Does SWFObject 2 support MIME type application/xhtml+xml?

SWFObject 2 does NOT support XML MIME types, which is a design decision.

There are a number of reasons why we are not supporting this:

  • Only a very small (non-significant) amount of web authors is using it
  • We are unsure if it is the direction to go. Internet Explorer does not support it and all other major browser vendors are aiming their arrows at a new standard way of HTML parsing (with HTML 5), which departs from the current W3C vision of parsing HTML as XML
  • We save a considerate amount of file size and effort (testing, issue resolving) by not supporting it

Tutorials (beginner level)

Comments

The comments functionality on this wiki has been switched off to avoid spam and abuse.

If you have any questions/comments about SWFObject or its documentation, or have problems with an implementation:

  1. Please make sure you have read our FAQ
  2. Use the SWFObject discussion group

If you find any bugs or want to request a future enhancement, you can fill in an issue report on the SWFObject issues page

Posted by 1010
반응형

출처 : http://roughexistence.tistory.com/67

 

window객체의 onerror를 사용하시면 됩니다.

웹페이지에 아래 예제에서 처럼 빨간부분의 코드를 추가하시면 됩니다.

"엑세스가 거부되었습니다"도 잡힙니다.

<script type="text/javascript">
window.onerror=function(msg,file,line) {
alert("오류메세지\t"+msg+"\n"+"파일위치\t"+file+"\n"+"라인번호\t"+line);
return true; //true를 return하면 오류메세지를 발생시키지 않음
}
</script>
<script type="text/javascript">
var obj='myobj; //테스트를 위해 오류를 발생시킨 부분
</script>

다른 방법 정리
window.onerror = ErrorSetting

var e_msg="";
var e_file="";
var e_line="";

function ErrorSetting(msg, file_loc, line_no) {
e_msg=msg;
e_file=file_loc;
e_line=line_no;
return true;
}

Posted by 1010
반응형

팝업창을 닫으려고 window.close 와 self.close 를 사용하니..

창을 닫겠습니까?! 라는 경고창이 뜬다.. ㅠㅠ

사용자 왈.. 이거 안보이게 해줄수 있나요?! 흠....

겁나 검색 해보니.. 나왔다... 퍼옴...

window.open('','').close(); 이걸로 해결 했심둥...ㅋㅋ

이유는 IE 보안정책?!!!

6버전?!(아직 쓰시는분 있나?!) 과 7버전 이상의 보안정책 다르다네..

- 해결방법
IE6버전은 window.close(); 사용해도 됨(안되면 어쩔수 없구..ㅠㅠ).
IE7버전 이상은 window.open('','').close(); 이걸로...ㅎㅎ


출처 : http://jjun7983.tistory.com/141#comment10522579
Posted by 1010
반응형

Simple이란?

Simple은 XML의 직렬화 및 역직렬화 프로세스를 단순화하는 데 사용되는 Java 프레임워크이다. 이름에서 알 수 있듯이 Simple을 사용하는 개발자는 POJO(plain old Java object)를 XML 문서로 변환하는 직렬화 프로세스를 단순화할 수 있다. Simple은 그 반대의 기능도 제공한다. 즉, XML 문서를 POJO로 변환할 수 있으며 이 프로세스를 역직렬화라고 한다.

Simple은 그 이름에 걸맞게 어노테이션을 사용하여 직렬화 또는 역직렬화 프로세스를 수행한다. POJO는 해당 XML 문서의 표시 방법에 따라 어노테이트된다. 일부 필드는 속성으로 어노테이트되고 다른 필드는 요소로 어노테이트된다. 클래스는 일반적으로 루트 요소로 어노테이트된다. 직렬화 프로세스 동안 어노테이션을 해석하고 해당 XML 문서를 생성하는 지루한 프로세스는 프레임워크에 의해 자동으로 처리된다. 또한 어노테이션은 XML 문서가 POJO로 변환되는 역직렬화 프로세스 동안에도 해석된다.

Simple을 사용하면 여러 가지 장점을 얻을 수 있다. 첫 번째 장점은 애플리케이션을 빠르게 개발할 수 있다는 것이다. Simple은 매우 단순하므로 과도한 학습 곡선 또는 개발 오버헤드 없이도 XML 직렬화 및 역직렬화를 사용하는 강력한 애플리케이션을 빠르게 구현할 수 있다.

Simple의 다음 장점은 구성이 필요하지 않다는 것이다. 앞에서 언급한 대로 Simple은 어노테이션을 사용한다. 이러한 어노테이션은 일반적으로 이러한 특성을 가진 프레임워크에 사용되는 XML 기반 구성 파일 대신 사용된다.

마지막으로 Simple을 사용하는 애플리케이션의 풋프린트에 최소한의 공간만 추가된다는 장점이 있다. 즉, 239KB에 불과한 JAR(Java Archive) 파일만 추가된다. 또한 Simple은 다른 프레임워크와 마찬가지로 다른 JAR 파일을 사용하지 않는다.

Simple 다운로드하기

Simple을 사용하려면 먼저 참고자료에 나열되어 있는 Simple 웹 사이트로 이동하여 아카이브를 다운로드해야 한다. 하지만 이 프로세스와 관련하여 좋은 소식과 나쁜 소식이 있다. 좋은 소식은 아카이브라 무료라는 것이고 나쁜 소식은 아카이브가 .tar.gz 형식이라는 것이다. 따라서 Microsoft® Windows® 기본 아카이브 추출기로는 이 아카이브를 열 수가 없기 때문에 WinZip 또는 유사한 아카이브 유틸리티가 필요하다.

파일을 추출한 후 jar 디렉토리를 보면 하나의 JAR 파일(simple-xml-2.1.4.jar)이 있다. 이 파일은 컴파일 시간 및 런타임에 클래스 경로에 있어야 하는 JAR 파일이다.

직렬화하기

오브젝트를 XML 문서로 직렬화하는 작업은 매우 간단하다. 다음 두 단계만 수행하면 된다.

  1. 적절한 어노테이션을 사용하여 POJO를 작성한다.
  2. 직렬화 프로세스를 실제로 수행하는 몇 줄의 코드를 작성한다.

이 기사에서는 필자의 기사에서 자주 사용되는 테마인 루어를 다시 한번 테마로 사용할 것이며 Listing 1이 바로 루어에 대한 정보를 나타내는 POJO이다.


Listing 1. Lure 클래스
@Root
public class Lure {

     @Attribute
     private String type;
	
     @Element
     private String company;
	
     @Element
     private int quantityInStock;
	
     @Element
     private String model;

     public String getType() {
		return type;
     }

     public void setType(String type) {
          this.type = type;
     }

     public String getCompany() {
          return company;
     }

     public void setCompany(String company) {
          this.company = company;
     }

     public int getQuantityInStock() {
          return quantityInStock;
     }

     public void setQuantityInStock(int quantityInStock) {
          this.quantityInStock = quantityInStock;
     }

     public String getModel() {
          return model;
     }

     public void setModel(String model) {
          this.model = model;
     }
}

이 POJO에는 복잡한 내용이 하나도 없다. 처음 봤을 때 어노테이션 부분이 익숙하지 않을 수도 있겠지만 이 또한 의도적인 것이다. Simple 프레임워크가 그 이름에 걸맞다고 한 필자의 말을 떠올려 보라.

@Root 어노테이션은 XML 문서의 루트 요소를 설명한다. 모든 XML 문서에는 루트 요소가 필요하므로 이 어노테이션을 반드시 포함시켜야 한다.

type 필드 위의 @Attribute 어노테이션은 해당 필드를 속성으로 식별한다. 이 속성은 루트 요소에 속성으로 추가된다.

마지막으로 남아 있는 @Element 어노테이션은 company, quantityInStockmodel이라는 세 필드의 바로 위에 사용된다. 이러한 필드는 XML 문서 내의 요소를 나타낸다.

POJO의 나머지 부분은 JavaBean 표준에 따라 접근자와 변경자로 구성되어 있다.

이제 POJO가 완료되었으므로 직렬화 코드를 작성할 차례이다. Listing 2에서 이 직렬화 코드를 볼 수 있다.


Listing 2. LureExample 클래스
public static void main(String[] args) {
     try {
          Serializer serializer = new Persister();
          Lure lure = new Lure();
          lure.setCompany("Donzai");
          lure.setModel("Marlin Buster");
          lure.setQuantityInStock(23);
          lure.setType("Trolling");
		
          File result = new File("lure.xml");
          serializer.write(lure, result);
     } catch (Exception e) {
          e.printStackTrace();
     }
}

이 코드에서는 가장 먼저 Persister 오브젝트를 인스턴스화한다. 이 클래스는 Simple 프레임워크의 일부이고 Serializer 인터페이스를 구현한다.

그런 다음 Lure 오브젝트를 인스턴스화하고 필드를 적절히 설정한다. 여기에서는 루어를 제조하는 회사의 이름이 Donzai이고 모델 이름이 Marlin Buster이다. 재고량은 23개이다. 마지막으로 루어의 유형은 Trolling이다.

그런 다음 XML 문서가 될 파일의 이름을 사용하여 File 오브젝트를 인스턴스화한다. 이 경우에는 파일 이름이 lure.xml이다.

마지막으로 직렬 변환기를 호출하여 파일을 작성한다. write() 메소드에 두 개의 매개변수가 제공된다. 첫 번째 매개변수는 POJO이고 두 번째 매개변수는 File 오브젝트이다.

이제 이 코드를 실행할 수 있다. Listing 2는 Java 애플리케이션이므로 자주 사용하는 IDE(Integrated Development Environment)를 사용하여 코드를 실행할 수 있다. simple-xml-2.1.4.jar이 클래스 경로에 있는지 확인한다. Eclipse를 사용하는 경우에는 파일을 마우스 오른쪽 단추로 클릭하고 Run As를 선택한 다음 표시되는 메뉴에서 Java Application을 선택하면 된다.

애플리케이션이 정상적으로 작동했다면 Listing 3과 같은 결과 XML 문서가 생성되어야 한다. (당연히 정상적으로 작동되어야 하며 정말 간단한 작업이다.)


Listing 3. LureExample 출력
<lure type="Trolling">
   <company>Donzai</company>
   <quantityInStock>23</quantityInStock>
   <model>Marlin Buster</model>
</lure>

Listing 3에서는 두 가지 사항에 주목해야 한다. 첫 번째는 루어 유형이 루트 요소의 속성이라는 것이다. 이는 @Element가 아닌 @Attribute를 사용하여 POJO의 type 필드를 어노테이트했기 때문에 완벽하게 작동한다.

결과 XML과 관련하여 또 하나 중요한 점은 요소 이름이 JavaBean 표준을 따른다는 것이다. 예를 들어, 루트 요소는 lure이고 클래스 이름은 Lure이다. 세 개의 하위 요소 이름도 해당 필드 이름과 완벽하게 일치한다. 다시 한번 말해서, 이 방법을 사용하면 루트 요소 이름과 하위 요소 이름이 서로 다른 패턴을 따르지 않아도 되기 때문에 이는 매우 실용적인 방법이다.

역직렬화하기

오브젝트를 직렬화하는 작업이 매우 쉬웠던 것처럼 역직렬화하는 방법도 매우 쉽다.

역직렬화는 XML 문서를 POJO로 변환하는 프로세스이다. 한 가지 좋은 점은 조금 전에 작성한 XML 문서를 역직렬화 작업에 사용할 수 있다는 것이다.

Listing 4에서는 역직렬화 코드를 보여 준다.


Listing 4. LureExample2 클래스
public static void main(String[] args) {
     try {
          Serializer serializer = new Persister();
          File source = new File("lure.xml");
          Lure lure = serializer.read(Lure.class, source);

          System.out.println(lure.getCompany());
          System.out.println(lure.getModel());
          System.out.println(lure.getQuantityInStock());
          System.out.println(lure.getType());
     } catch (Exception e) {
          e.printStackTrace();
     }
}

먼저 Serializer 인터페이스를 구현하는 Persister 오브젝트를 인스턴스화한다.

File 오브젝트를 인스턴스화하는 행도 익숙해 보이겠지만 이 경우에는 명확한 차이가 있다. Listing 3에서는 존재하지 않는 파일에 대한 File 오브젝트를 인스턴스화했지만 여기에서는 파일이 존재하고 있는 것으로 가정하고 있다. (실제로도 파일이 있어야 한다.)

그런 다음 Serializer 오브젝트의 read 메소드를 호출하여 POJO를 인스턴스화한다. read 메소드는 두 개의 매개변수를 사용한다. 하는 POJO 클래스이고 다른 하나는 데이터가 포함된 XML 파일을 나타내는 File 오브젝트이다.

마지막으로 모든 정보가 올바르게 읽혔는지 확인하기 위해 POJO의 모든 정보를 출력한다.

이 코드를 실행하면 Listing 5와 같은 출력이 표시되어야 한다.


Listing 5. LureExample2 출력
Donzai
Marlin Buster
23
Trolling

전체 트리 직렬화

지금까지 직렬화 및 역직렬화했던 XML 문서는 상당히 단순했다.

하지만 대부분의 XML 문서는 훨씬 더 복잡하다. 일반적으로 이러한 문서에는 중첩 요소뿐만 아니라 여러 개의 하위 요소를 가지고 있는 일대다 반복 요소가 여러 계층으로 포함되어 있다.

다행스럽게도 Simple은 그 이름에 걸맞게 복잡한 문서도 쉽게 처리할 수 있다. POJO 내에서 POJO를 중첩하는 것처럼 간단하게 처리할 수 있다. Listing 6을 살펴보자.


Listing 6. AdvancedLure 클래스
@Attribute
private String type;

@Element
private String company;
	
@Element
private int quantityInStock;
	
@Element
private String model;
	
@Element
private ConfigurationScheme configurationScheme;

Listing 6AdvancedLure 클래스는 Listing 1Lure 클래스와 매우 유사하다. 한 가지 차이점은 configurationScheme라는 또 하나의 필드가 포함되어 있다는 것이다. 구성 스키마는 Listing 7에서 설명하는 또 다른 POJO에 의해 표시된다.


Listing 7. ConfigurationScheme 클래스
@Root
public class ConfigurationScheme {
	
@Element
private String color;
	
@Element
private int size;

여기에서는 간단하게 설명하기 위해 접근자와 변경자를 생략했다.

Listing 7에서는 익숙한 어노테이션을 볼 수 있다. 이러한 어노테이션은 Listing 1에서 사용했던 것과 같은 어노테이션이다.

이제 Listing 8과 같은 결과를 얻을 수 있다.


Listing 8. LureExample3 클래스
public static void main(String[] args) {
     try {
          Serializer serializer = new Persister();
          AdvancedLure lure = new AdvancedLure();
          lure.setCompany("Donzai");
          lure.setModel("Marlin Buster");
          lure.setQuantityInStock(23);
          lure.setType("Trolling");
			
          ConfigurationScheme configurationScheme = new ConfigurationScheme();
          configurationScheme.setColor("Blue");
          configurationScheme.setSize(3);
          lure.setConfigurationScheme(configurationScheme);
			
          File result = new File("advancedlure.xml");
          serializer.write(lure, result);
     } catch (Exception e) {
          e.printStackTrace();
     }
}

Listing 2와 비교했을 때 Listing 8의 큰 차이점은 ConfigurationScheme 오브젝트를 인스턴스화한 다음 AdvancedLure 오브젝트의 해당 필드를 설정한다는 것이다.

이 코드를 실행하면 Listing 9와 같은 출력이 표시되어야 한다.


Listing 9. LureExample3 출력
<advancedLure type="Trolling">
   <company>Donzai</company>
   <quantityInStock>23</quantityInStock>
   <model>Marlin Buster</model>
   <configurationScheme>
      <color>Blue</color>
      <size>3</size>
   </configurationScheme>
</advancedLure>

이 출력을 보면 중첩 요소가 예상대로 정확히 직렬화되었다는 것을 알 수 있다.

열거

XML 문서에는 특정 요소의 열거가 자주 사용된다. 즉, 동일한 요소 이름이 하위 또는 속성 데이터만 변경된 채로 반복해서 자주 사용된다. 다행히도 Simple은 이 상황을 잘 처리할 수 있다.

이 기능을 확인하기 위해 먼저 Inventory라는 새 클래스를 작성한다. 이 클래스에는 재고품이 보관되어 있는 창고의 이름과 해당 재고 창고에서 찾을 수 있는 루어의 목록이 있다(Listing 10 참조).


Listing 10. Inventory 클래스
@Root
public class Inventory {
	
     @ElementList
     private List<AdvancedLure> lures;
	
     @Attribute
     private String warehouse;

이 Listing에서는 @ElementList라는 새 어노테이션을 사용하고 있다. 이 어노테이션은 해당 List 오브젝트가 XML 요소의 열거를 나타낸다는 의미를 지닌다.

이 POJO의 직렬화를 보여 주기 위해 사용된 코드는 더 간단한 POJO(예: Listing 2에서 직렬화했던 POJO)를 직렬화하는 데 사용했던 코드와 마찬가지로 쉽게 이해할 수 있다. Listing 11을 살펴보자.


Listing 11. LureExample4 클래스
Serializer serializer = new Persister();

AdvancedLure lure = new AdvancedLure();
lure.setCompany("Donzai");
lure.setModel("Marlin Buster");
lure.setQuantityInStock(23);
lure.setType("Trolling");
			
ConfigurationScheme configurationScheme = new ConfigurationScheme();
configurationScheme.setColor("Blue");
configurationScheme.setSize(3);
lure.setConfigurationScheme(configurationScheme);
			
			
AdvancedLure lure2 = new AdvancedLure();
lure2.setCompany("Ziggi");
lure2.setModel("Tuna Finder");
lure2.setQuantityInStock(44);
lure2.setType("Trolling");
		
ConfigurationScheme configurationScheme2 = new ConfigurationScheme();
configurationScheme2.setColor("Red");
configurationScheme2.setSize(5);
lure2.setConfigurationScheme(configurationScheme2);
			
List<AdvancedLure> lures = new ArrayList<AdvancedLure>();
lures.add(lure);
lures.add(lure2);
			
Inventory inventory = new Inventory();
inventory.setLures(lures);
inventory.setWarehouse("Midwest");
			
File result = new File("inventory.xml");

serializer.write(inventory, result);

이 코드를 실행하면 inventory.xml이라는 XML 파일이 작성된다. 이 파일의 내용은 Listing 12와 같다.


Listing 12. LureExample4 출력
<inventory warehouse="Midwest">
   <lures>
      <advancedLure type="Trolling">
         <company>Donzai</company>
         <quantityInStock>23</quantityInStock>
         <model>Marlin Buster</model>
         <configurationScheme>
            <color>Blue</color>
            <size>3</size>
         </configurationScheme>
      </advancedLure>
      <advancedLure type="Trolling">
         <company>Ziggi</company>
         <quantityInStock>44</quantityInStock>
         <model>Tuna Finder</model>
         <configurationScheme>
            <color>Red</color>
            <size>5</size>
         </configurationScheme>
      </advancedLure>
   </lures>
</inventory>

이 Listing을 보면 Listing 11에서 인스턴스화하고 작성했던 POJO와 출력이 완전히 같다는 것을 알 수 있다. 두 개의 advancedLure 요소가 있고 각 요소에는 해당 POJO를 채우는 데 사용했던 데이터가 있다. 여기에서도 중첩이 적절히 사용되고 있다.

생성자

코드에서 변경되지 않는 POJO를 사용할 수 있다. 이 경우 setter 메소드를 사용하여 필드 속성을 수정하는 대신 생성자를 사용하여 이러한 값을 설정할 수 있다. Simple은 이 상황을 잘 처리할 수 있다.

이 경우에는 필드 이름 위가 아닌 생성자 매개변수 내에서 어노테이션을 지정한다. 해당 접근자 메소드 위에도 어노테이션이 필요하다. Listing 13을 살펴보자.


Listing 13. Inventory2 클래스
public Inventory2(@ElementList(name="lures") List<AdvancedLure> lures,
 @Attribute(name="warehouse") String warehouse) {
     this.lures = lures;
     this.warehouse = warehouse;
}

@ElementList(name="lures")
public List<AdvancedLure> getLures() {
     return lures;
}

@Attribute(name="warehouse")
public String getWarehouse() {
     return warehouse;
}

어노테이션을 생성자 매개변수의 일부로 지정할 경우에는 매개변수에 해당하는 필드 이름도 지정해야 한다. 첫 번째 매개변수에 대한 필드 이름은 lures이고 두 번째 매개변수에 대한 필드 이름은 warehouse이다.

그런 다음 접근자 메소드 위에 일치하는 어노테이션 및 필드 이름을 제공한다. lures에 대한 getter 바로 위에서 생성자에 사용된 어노테이션과 완전히 일치하는 해당 어노테이션을 볼 수 있다. 이와 마찬가지로 warehouse에 대한 getter 위의 어노테이션도 해당 어노테이션과 완전히 일치한다.

이 코드를 실행하기 위해 먼저 Listing 11을 약간 수정하여 Listing 14의 코드를 포함시킨다.


Listing 14. LureExample5 클래스
Inventory2 inventory = new Inventory2(lures,"MidWest");

여기에서는 Listing 11에서 사용했던 setter 메소드 대신 Listing 14의 코드를 사용하며 나머지 부분은 모두 동일하다.

템플리트 필터

XML 문서를 역직렬화할 때 템플리트 필터 또는 기본값을 사용할 수 있다는 점은 Simple의 또 다른 주요 기능이다.

이제 원래의 lure.xml로 돌아가서 Listing 15처럼 약간만 수정해 보자.


Listing 15. Lure2.xml 문서
<lure type="Trolling">
   <company>${lure.company}</company>
   <quantityInStock>23</quantityInStock>
   <model>Marlin Buster</model>
</lure>

이 문서의 company 요소에는 실제 회사의 이름 대신 Apache Ant 유형의 변수 선언이 포함되어 있으며 변수의 이름은 lure.company이다.

템플리트 필터를 사용하면 런타임에 변수 선언을 실제 값으로 대체하여 설정할 수 있다. 이를 수행하는 쉬운 방법으로는 변수 이름과 해당 값을 연결하는 Map 오브젝트를 사용하는 것이다. 그런 다음 Map 오브젝트를 사용하여 Simple 프레임워크에서 Filter 오브젝트를 생성한다. 그런 다음 Filter 오브젝트를 사용하여 Persister 오브젝트를 생성한다. Listing 16을 살펴보자.


Listing 16. LureExample6 클래스
Map<String,String> map = new HashMap<String,String>();
map.put("lure.company", "Monmouth");
Filter filter = new MapFilter(map);
			
Serializer serializer = new Persister(filter);
File source = new File("lure2.xml");

Lure lure = serializer.read(Lure.class, source);

System.out.println(lure.getCompany());
System.out.println(lure.getModel());
System.out.println(lure.getQuantityInStock());
System.out.println(lure.getType());

Listing 16Listing 2와 크게 다르지 않다. 주요 차이점은 String 값을 String 키에 연결하는 HashMap이 인스턴스화된다는 것이다. 이 경우 String 키는 예상대로 Listing 15에서 사용했던 변수 이름인 lure.company이다. 여기에서는 앞에서 보았던 XML 문서에 있던 값인 Donzai대신 Monmouth라는 값을 이 키에 지정한다.

이 코드를 실행하면 Listing 17과 같은 출력이 표시되어야 한다.


Listing 17. LureExample6 출력
Monmouth
Marlin Buster
23
Trolling

이 출력을 보면 템플리트 필터가 변수 이름 lure.companyMap 오브젝트에 있는 해당 키 이름에 연결된 실제 값으로 대체했다는 것을 알 수 있다. 이 출력은 예상과 정확히 일치한다.

결론

지금까지 살펴보았듯이 Simple은 강력한 XML 직렬화 및 역직렬화 프레임워크이며 사용하기도 쉽고, 구성도 필요하지 않기 때문에 빠른 개발이 가능하다.

Simple에는 여러 가지 강력한 기능이 있지만 여기에서는 지면의 제약으로 인해 일부 기능만을 살펴보았다. 소프트웨어 개발 작업 중에 XML 직렬화 및 역직렬화가 필요한 개발자라면 Simple을 사용해 보기를 적극 권장한다.



다운로드 하십시오

설명 이름 크기 다운로드 방식
Source code for the examples used in this article Simple.zip 5KB HTTP

다운로드 방식에 대한 정보

Posted by 1010
반응형

오래전부터 XML을 변환하는 데 있어서 XStream을 많이 사용했을 겁니다. 이것을 사용하면 아주 편하게 XML을 제어롤 하게 됩니다.(object를 xml로 or xml을 object로) 그래서 SOAP 인터페이스나 다양한 OPEN API나 멀티미디어 디바이스와의 연동 등에 많이 사용하곤 합니다.

아래의 샘플을 올려놓을테니 한번 실행해 보시고 사용법을 익힌다음 자기의 것으로 만들어 개발에 생산성을 높이는데 일조를 하시면 되겠죠. ^^

1. IXmlRule.java
package com.mimul.xstream;

public interface IXmlRule
{
public String toXML();

}

2. BaseRule.java
package com.mimul.xstream;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.annotations.Annotations;

import java.io.Serializable;
import java.lang.reflect.Field;


public class BaseRule implements Serializable {

/**
* XML 문자열로 변환
*/
protected String toXML() {
XStream xstream = new XStream();
Annotations.configureAliases(xstream, getClass());
Field[] fields = getClass().getDeclaredFields();
for (Field f : fields) {
Annotations.configureAliases(xstream, f.getType());
}
String xmlString = xstream.toXML(this);
xstream = null;
return xmlString;
}

/**
* XML 데이터로부터 Rule Build
*/
public static IXmlRule fromXML(String xmlString, Class clazz) {
XStream xstream = new XStream();
Annotations.configureAliases(xstream, clazz);
Field[] fields = clazz.getDeclaredFields();
for (Field f : fields) {
Annotations.configureAliases(xstream, f.getType());
}
IXmlRule rule = (IXmlRule) xstream.fromXML(xmlString);
xstream = null;
return rule;
}
}

3. Member.java
package com.mimul.xstream;

import com.thoughtworks.xstream.annotations.XStreamAlias;

@XStreamAlias("xstream.Member")
public class Member {

private String accountNo;
private String password;


public String getAccountNo() {
return accountNo;
}

public void setAccountNo(String accountNo) {
this.accountNo = accountNo;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}
}

4. PersonRule.java
package com.mimul.xstream;

import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamImplicit;

import java.util.ArrayList;
import java.util.List;


@XStreamAlias("Person")
public class PersonRule extends BaseRule implements IXmlRule
{
private static final long serialVersionUID = 1L;

public String toXML() {
return super.toXML();
}

private String name;
private int age;
private String occupation;

@XStreamImplicit(itemFieldName = "members")
private List<Member> members;


public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public String getOccupation() {
return occupation;
}

public void setOccupation(String occupation) {
this.occupation = occupation;
}

public List<Member> getMembers() {
return members;
}

public void setMembers(List<Member> members) {
this.members = members;
}

public static void main(String args[])
{
PersonRule person = null;
List<Member> members = null;
Member member = null;

try {
person = new PersonRule();
person.setName("미물");
person.setAge(32);
person.setOccupation("Consultant");

members = new ArrayList<Member>(3);
member = new Member();
member.setAccountNo("mimul");
member.setPassword("mimuladmim");
members.add(member);

member = new Member();
member.setAccountNo("pepsi");
member.setPassword("pepsiadmin");
members.add(member);

member = new Member();
member.setAccountNo("scott");
member.setPassword("tigerda");
members.add(member);

person.setMembers(members);

// Object에서 XML 생성
String xmlString = person.toXML();
System.out.println("XML : " + xmlString);

// XML파일 Object 매핑
PersonRule personRule = (PersonRule) BaseRule.fromXML(xmlString, PersonRule.class);

System.out.println(personRule.getName());
System.out.println(personRule.getAge());
System.out.println(personRule.getOccupation());

for (Member mem : personRule.getMembers()) {
System.out.println(mem.getAccountNo());
System.out.println(mem.getPassword());
}
} catch (Exception e) {
System.out.println(e);
person = null;
members = null;
}
}
}

5. 실행 화면

Xstream
6. JSON 변환 방법을 알려면 여기를 가시면 됩니다.

출처 : http://mimul.com/pebble/default/2007/11/08/1194530400000.html
Posted by 1010
반응형
String t_xmlStr =           
   "<root>" +           
   "<item value=\"돈까스\">" +
   "<item value=\"순대국\">" +
   "<item value=\"짜장면\">" +
   "</item></item></item></root>";
   
  DocumentBuilderFactory t_dbf = null;       
  DocumentBuilder t_db = null;       
  Document t_doc = null;       
  NodeList t_nodes = null;       
  Node t_node = null;       
  Element t_element = null;       
  InputSource t_is = new InputSource();        
  try{           
   t_dbf = DocumentBuilderFactory.newInstance();           
   t_db = t_dbf.newDocumentBuilder();           
   t_is = new InputSource();           
   t_is.setCharacterStream(new StringReader(t_xmlStr));           
   t_doc = (Document) t_db.parse(t_is);           
   t_nodes = t_doc.getElementsByTagName("item");            
   for (int i = 0, t_len = t_nodes.getLength(); i < t_len; i ++){              
    t_element = (Element)t_nodes.item(i);                
    System.out.println(t_element.getAttribute("value"));   
    collection.add(new personVO(t_element.getAttribute("value"), t_element.getAttribute("value"), t_element.getAttribute("value")));
   }       
  }catch (Exception e){           
   e.printStackTrace();       
  }
Posted by 1010
반응형
:http://xstream.codehaus.org/tutorial.html <- 참조

Serializing an object to XML

Let's create an instance of Person and populate its fields:

Person joe = new Person("Joe", "Walnes");
joe.setPhone(new PhoneNumber(123, "1234-456"));
joe.setFax(new PhoneNumber(123, "9999-999"));

Now, to convert it to XML, all you have to do is make a simple call to XStream:

String xml = xstream.toXML(joe);

The resulting XML looks like this:

<person>
  <firstname>Joe</firstname>
  <lastname>Walnes</lastname>
  <phone>
    <code>123</code>
    <number>1234-456</number>
  </phone>
  <fax>
    <code>123</code>
    <number>9999-999</number>
  </fax>
</person>

It's that simple. Look at how clean the XML is.

Posted by 1010
반응형

ThoughtWorks에서 만든 Xstream을 활용한다.
Xstream 최대의 장점은 초 간단...
얼마나 간단하면 튜토리얼이 Two Minute Tutorial 이다.
클래스 패스에 xstream-xxx.jar를 넣고.. 다음 코드를 실행하면..
XStream xstream = new XStream();
Person joe = new Person();
joe.setAge(30);
joe.setName("Joe");
joe.setPhone(new PhoneNumber(123, "1234-456"));
joe.setFax(new PhoneNumber(123, "9999-999"));
String xml = xstream.toXML(joe);
System.out.println(xml);
출력 내용은.. 간단하기 이를데 없다.. 만족.. ^^
<object.Person>
<name>Joe</name>
<age>30</age>
<fax>
<code>123</code>
<number>9999-999</number>
</fax>
<phone>
<code>123</code>
<number>1234-456</number>
</phone>
</object.Person>
object.Person은 좀 보기 싫어.. 별칭(alias)를 준다.
XStream xstream = new XStream();
xstream.alias("person", Person.class);
Person joe = new Person();
joe.setAge(30);
joe.setName("Joe");
joe.setPhone(new PhoneNumber(123, "1234-456"));
joe.setFax(new PhoneNumber(123, "9999-999"));
String xml = xstream.toXML(joe);
System.out.println(xml);
그럼.. 출력은 내 스타일(?)로 변모...
<person>
<name>Joe</name>
<age>30</age>
<fax>
<code>123</code>
<number>9999-999</number>
</fax>
<phone>
<code>123</code>
<number>1234-456</number>
</phone>
</person>
null값을 갖는 속성은 어찌 되는가?
XStream xstream = new XStream();
xstream.alias("person", Person.class);
Person joe = new Person();
// joe.setAge(30);
joe.setName("Joe");
joe.setPhone(new PhoneNumber(123, "1234-456"));
joe.setFax(new PhoneNumber(123, "9999-999"));
출력이 안되는군.
<person>
<name>Joe</name>
<fax>
<code>123</code>
<number>9999-999</number>
</fax>
<phone>
<code>123</code>
<number>1234-456</number>
</phone>
</person>
XML을 자바 객체로..
XStream xstream = new XStream();
xstream.alias("person", Person.class);
String xml =
"<person>" +
"<name>Joe</name>" +
"<fax>" +
"<code>123</code>" +
"<number>9999-999</number>" +
"</fax>" +
"<phone>" +
"<code>123</code>" +
"<number>1234-456</number>" +
"</phone>" +
"</person>" ;
Person joe = (Person)xstream.fromXML(xml);
alias 처리를 포함해도 세 문장이면 되는구만.
단.. 자바 객체 변환(Deserializing)시에는 xpp.jar(xstream zip 파일의 lib에 있음)가 필요하다.
Posted by 1010
반응형

JAXB를 활용한 Java 객체의 XML 자동 변환

Using JAXB for XML data binding

자바 SE 6에서 JAXB(Java Architecture for XML Binding)를 사용하여 JAVA -> XML 변환하는 테스트 샘플을 만들어 보았습니다. 물론 XStream으로도 가능합니다.

1. JAXB란?
JAXB를 사용하면 XML과 자바 간에 쉽게 앞뒤로 이동할 수 있습니다. JAXB 구현은 XML 스키마를 받아 해당 스키마에 매핑되는 자바 클래스를 생성하는 스키마 컴파일러를 제공합니다. XML 문서의 데이터는 JAXB의 바인딩 런타임 프레임워크를 통해, 스키마 컴파일러가 생성한 클래스에 자동으로 바인딩될 수 있습니다. 이 작업을 언마샬링(Unmarshalling)이라고 합니다. 언마샬링되면 필요에 따라 콘텐츠를 Java로 조작하거나 수정할 수 있습니다. JAXB는 자바 개체에서 XML 인스턴스 문서로 데이터를 쓸(마샬링할) 수도 있습니다.

2. 샘플 소스
*. Person bean 객체
package client;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "person")
public class Person
{
private String firstName;
private String lastName;
private Family family;

public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public Family getFamily() {
return family;
}

public void setFamily(Family family) {
this.family = family;
}
}

*. Family bean 객체
package client;
import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;

public class Family
{
private String description;
@XmlElementWrapper(name = "persons")
@XmlElement
private List<Person> members = new ArrayList<Person>();


public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}

public List<Person> getMembers() {
return members;
}
}

*. Java객체를 Xml로 변환하는 클라이언트 샘플
package client;

import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;

public class JAXBClient
{
public static void main(String[] args) {
JAXBContext context = null;
List<Person> list = null;
Person person1 = null;
Person person2 = null;
Family family = null;
Marshaller marshaller = null;

try {
context = JAXBContext.newInstance(Person.class);
list = new ArrayList<Person>();

person1 = new Person();
family = new Family();

family.setDescription("Family Mimul");
person1.setFirstName("IlDong");
person1.setLastName("Hong");
person1.setFamily(family);
list.add(person1);

person2 = new Person();
person2.setFirstName("LeeDong");
person2.setLastName("Hong");
person2.setFamily(family);
list.add(person2);

// Marshal 객체를 XML로 변환
// Unmarshal the objects from XML

marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_ENCODING, "utf-8");
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
Boolean.TRUE);

marshaller.marshal(person2, System.out);

} catch (JAXBException e) {
e.printStackTrace();
}
}
}


3. 실행 결과
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<person>
<family>
<persons/>
<description>Family Mimul</description>
</family>
<firstName>LeeDong</firstName>
<lastName>Hong</lastName>
</person>
Posted by 1010
반응형

How to create XML file in Java – (JDOM Parser)
Published: August 4, 2011 , Updated: August 4, 2011 , Author: mkyong

In this example, we show you how to use JDOM parser to create document, element and attribute in a XML file.

1. XML File

At the end of this example, following XML file will be created.

File : file.xml

<?xml version="1.0" encoding="UTF-8"?>
<company>
  <staff id="1">
    <firstname>yong</firstname>
    <lastname>mook kim</lastname>
    <nickname>mkyong</nickname>
    <salary>199999</salary>
  </staff>
  <staff id="2">
    <firstname>low</firstname>
    <lastname>yin fong</lastname>
    <nickname>fong fong</nickname>
    <salary>188888</salary>
  </staff>
</company>

3. JDOM Example

JDOM example to create above XML file.

import java.io.FileWriter;
import java.io.IOException;
import org.jdom.Attribute;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
 
public class WriteXMLFile {
	public static void main(String[] args) {
 
	  try {
 
		Element company = new Element("company");
		Document doc = new Document(company);
		doc.setRootElement(company);
 
		Element staff = new Element("staff");
		staff.setAttribute(new Attribute("id", "1"));
		staff.addContent(new Element("firstname").setText("yong"));
		staff.addContent(new Element("lastname").setText("mook kim"));
		staff.addContent(new Element("nickname").setText("mkyong"));
		staff.addContent(new Element("salary").setText("199999"));
 
		doc.getRootElement().addContent(staff);
 
		Element staff2 = new Element("staff");
		staff2.setAttribute(new Attribute("id", "2"));
		staff2.addContent(new Element("firstname").setText("low"));
		staff2.addContent(new Element("lastname").setText("yin fong"));
		staff2.addContent(new Element("nickname").setText("fong fong"));
		staff2.addContent(new Element("salary").setText("188888"));
 
		doc.getRootElement().addContent(staff2);
 
		// new XMLOutputter().output(doc, System.out);
		XMLOutputter xmlOutput = new XMLOutputter();
 
		// display nice nice
		xmlOutput.setFormat(Format.getPrettyFormat());
		xmlOutput.output(doc, new FileWriter("c:\\file.xml"));
 
		System.out.println("File Saved!");
	  } catch (IOException io) {
		System.out.println(io.getMessage());
	  }
	}
}
Posted by 1010
반응형
How to modify XML file in Java – (JDOM Parser)
Published: April 3, 2010 , Updated: August 4, 2011 , Author: mkyong

JDOM XML parser example to modify an existing XML file :

  1. Add a new element
  2. Update existing element attribute
  3. Update existing element value
  4. Delete existing element

1. XML File

See before and after XML file.

File : file.xml – Original XML file.

<?xml version="1.0" encoding="UTF-8"?>
<company>
  <staff id="1">
    <firstname>yong</firstname>
    <lastname>mook kim</lastname>
    <nickname>mkyong</nickname>
    <salary>5000</salary>
  </staff>
</company>

Later, update above XML file via JDOM XML Parser.

  1. Add a new “age” element under staff
  2. Update the staff attribute id = 2
  3. Update salary value to 7000
  4. Delete “firstname” element under staff

File : file.xml – Newly modified XML file.

<?xml version="1.0" encoding="UTF-8"?>
<company>
  <staff id="2">
    <lastname>mook kim</lastname>
    <nickname>mkyong</nickname>
    <salary>7000</salary>
    <age>28</age>
  </staff>
</company>

2. JDOM Example

JDOM parser to update or modify an existing XML file.

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
 
public class ModifyXMLFile {
	public static void main(String[] args) {
 
	  try {
 
		SAXBuilder builder = new SAXBuilder();
		File xmlFile = new File("c:\\file.xml");
 
		Document doc = (Document) builder.build(xmlFile);
		Element rootNode = doc.getRootElement();
 
		// update staff id attribute
		Element staff = rootNode.getChild("staff");
		staff.getAttribute("id").setValue("2");
 
		// add new age element
		Element age = new Element("age").setText("28");
		staff.addContent(age);
 
		// update salary value
		staff.getChild("salary").setText("7000");
 
		// remove firstname element
		staff.removeChild("firstname");
 
		XMLOutputter xmlOutput = new XMLOutputter();
 
		// display nice nice
		xmlOutput.setFormat(Format.getPrettyFormat());
		xmlOutput.output(doc, new FileWriter("c:\\file.xml"));
 
		// xmlOutput.output(doc, System.out);
 
		System.out.println("File updated!");
	  } catch (IOException io) {
		io.printStackTrace();
	  } catch (JDOMException e) {
		e.printStackTrace();
	  }
	}
}

Posted by 1010
반응형

How to read XML file in Java – (JDOM Parser)
Published: December 21, 2009 , Updated: August 4, 2011 , Author: mkyong

JDOM is, quite simply, a Java representation of an XML document. JDOM provides a way to represent that document for easy and efficient reading, manipulation, and writing. It has a straightforward API, is a lightweight and fast, and is optimized for the Java programmer. It’s an alternative to DOM and SAX, although it integrates well with both DOM and SAX.

JDOM, Java XML parser, is more user friendly in the way of accessing the XML document.

In this example, we show you how to use JDOM to read a XML file, and print out each element orderly.

1. Download the JDOM library

JDOM is not like SAX or DOM, which bundled in JDK. To use JDOM, you need to download the library manually.

Get JDOM from JDOM official site or declares following dependency if you are using Maven.

    <dependency>
	<groupId>jdom</groupId>
	<artifactId>jdom</artifactId>
	<version>1.1</version>
    </dependency>

2. XML File

XML file as following

<?xml version="1.0"?>
<company>
	<staff>
		<firstname>yong</firstname>
		<lastname>mook kim</lastname>
		<nickname>mkyong</nickname>
		<salary>100000</salary>
	</staff>
	<staff>
		<firstname>low</firstname>
		<lastname>yin fong</lastname>
		<nickname>fong fong</nickname>
		<salary>200000</salary>
	</staff>
</company>

3. Java File

Use JDOM parser to parse above XML file.

import java.io.File;
import java.io.IOException;
import java.util.List;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
 
public class ReadXMLFile {
	public static void main(String[] args) {
 
	  SAXBuilder builder = new SAXBuilder();
	  File xmlFile = new File("c:\\file.xml");
 
	  try {
 
		Document document = (Document) builder.build(xmlFile);
		Element rootNode = document.getRootElement();
		List list = rootNode.getChildren("staff");
 
		for (int i = 0; i < list.size(); i++) {
 
		   Element node = (Element) list.get(i);
 
		   System.out.println("First Name : " + node.getChildText("firstname"));
		   System.out.println("Last Name : " + node.getChildText("lastname"));
		   System.out.println("Nick Name : " + node.getChildText("nickname"));
		   System.out.println("Salary : " + node.getChildText("salary"));
 
		}
 
	  } catch (IOException io) {
		System.out.println(io.getMessage());
	  } catch (JDOMException jdomex) {
		System.out.println(jdomex.getMessage());
	  }
	}
}

Output

First Name : yong
Last Name : mook kim
Nick Name : mkyong
Salary : 100000
First Name : low
Last Name : yin fong
Nick Name : fong fong
Salary : 200000
Posted by 1010
03.HTML 4.X, HTML5, XML...2011. 6. 12. 16:25
반응형


<script type="text/javascript">
  function loginLayerOn(id){
   if (document.getElementById(id).style.display == "inline"){ 
    document.getElementById(id).style.display = "none";   
   }else{
    var cfmOllehLayerPopUp340 = document.getElementById(id);
    var tmpTop = 0;
     if(browser() == "Chrome" || browser() =="MSIE 5.5"){
      tmpTop = document.body.scrollTop;
     }else if(browser() =="Safari"){
      tmpTop = window.pageYOffset ;
     }else{
      tmpTop = document.documentElement.scrollTop;
     }
     cfmOllehLayerPopUp340.style.position = "absolute";
     cfmOllehLayerPopUp340.style.display = "inline";
     cfmOllehLayerPopUp340.style.left = document.body.clientWidth/2 - cfmOllehLayerPopUp340.offsetWidth/2 + "px";
     cfmOllehLayerPopUp340.style.top = document.body.clientHeight/2 - cfmOllehLayerPopUp340.offsetHeight/2 + tmpTop + "px";
   }
  }

 function browser() {
   var appAgent = navigator.userAgent;
   var returnStr ;
   if (appAgent.indexOf('MSIE 8.0')>0)  returnStr  =  "MSIE 8.0";
   if (appAgent.indexOf('MSIE 7.0')>0)  returnStr  =  "MSIE 7.0";
   if (appAgent.indexOf('MSIE 6.0')>0)  returnStr  =  "MSIE 6.0";
   if (appAgent.indexOf('MSIE 5.5')>0)  returnStr  =  "MSIE 5.5";
   if (appAgent.indexOf('MSIE 5.0')>0)  returnStr  =  "MSIE 5.0";
   if (appAgent.indexOf('Chrome')>0)  returnStr  =  "Chrome";
   if (appAgent.indexOf('Firefox')>0)  returnStr  =  "Firefox";
   if (appAgent.indexOf('Chrome')<0 && appAgent.indexOf('Safari')>0) returnStr  =  "Safari";
   return returnStr;
 }
 </script>


<Div id="pop" style="position:absolute;left:10px; top:12px; width:100px; height:70px;z-index:1;display:none;BACKGROUND: red">
내용 들어가는 부분
</Div>

<a href="#" onclick="loginLayerOn('pop');"><img src="/images/egovframework/sosang/topmenu/main_menu01_off.gif" width="80" height="30" border="0" alt="정책정보" /></a>

Posted by 1010
03.HTML 4.X, HTML5, XML...2011. 6. 11. 19:49
반응형

//if(this.bIE){button=document.createElement("<BUTTON type='button'>");}
if(navigator.appVersion.indexOf("MSIE 9") > -1){ button=document.createElement("BUTTON");button.type="button"; } else if(this.bIE){button=document.createElement("<BUTTON type='button'>");}


ie9에서는 문법이 맞지 않아서 생긴다.
Posted by 1010
03.HTML 4.X, HTML5, XML...2011. 6. 11. 18:07
반응형

Attribute value java.net.URLEncoder.encode("한글") is quoted h " which must be escaped when used within the value

위와 같은 로그가 쌓이면서 태그 라이브러리 형태의 jsp 코드에서 에러가 발생할 경우...

tomcat/conf/catalina.properties 의 맨 마지막 줄에 다음의 한 줄을 추가!

org.apache.jasper.compiler.Parser.STRICT_QUOTE_ESCAPING=false


Posted by 1010
반응형
Posted by 1010
반응형
ㅇ try catch문

   사용할때 : 보통 자바스크립트로 작업하다 보면 정말 어떨때는 구문에서 틀리지도 않았는데,
               브라우저 버젼에 따라 에러가 발생하기도 하고, 정말 몇달간 디버깅에 지칠때도 있다.
               대부분 열심히하면 나타나는데, 다음의 try catch문을 사용하면 편리하다.
   사용예   :
             try
             {
                  // 실제 실행시킬부분
                  var a   = opener.Location.href;
             }
             catch (e)
             {
                  // 위의 "실행시킬부분"에서 에러가 났을때 처리해줄 부분
                  alert ("opener를 찾을수 없습니다.");
             }
             finally
             {
                  // 에러가 나든 나지 않든 무조건 실행시키는 부분
                  window.status   = "opener.locatoin.href 부분 실행되었음";
             }
ㅇ typeof문
   사용할때 : 보통 데이터나 오브젝트 타입등을 검사할때 많이 사용하는데.
                만약 "undefined"이면 인식을 못한거고 "unknown"이 나올때가
                있다.. 만약 부모창에서 새창을 열고 부모창을 닫았는지 새창에서 검사할때
                if (typeof (opener) == "unknown") 이면 으로 검사할때 유용하다~ㅇ

ㅇ regExp (정규표현식)
   사용할때 : 만약 <textarea name="taContent"></textarea>에 사용자가 입력한  value값중에서
                "/아싸1/" ~ "/아싸10/" 까지를 다 "/호호1/" ~ "/호호10/" 까지로 바꿀려면 어케할까?
               
                var sTaContent   = taContent.value;
                for (var nI = 1; nI <= 10; nI++)
                {
                       var expTest = new RegExp("/아싸" + nI + "/", "ig");   // i는 대소문자 구분없고, g는 중복되어도 다처리
                       sTaContent   = sTaContent.r-place (expTest, "/호호" + nI + "/");
                }
                taContent.value   = sTaContent;
             
                하면 된다~ㅇ

                위의 expTest의 메소드들도 몇개있으므로 알아두면 많이 도움이 된다~ㅇ
                또한, 게시판의 글보기에 나오는 글들에 자동링크 걸때도 사용한다~ㅇ



ㅇ var a="08", b="09"일때
   parseInt (a)나 parseInt (b)의 값은 0 이다
   Number (a)나 Number (b)값을 해야 제대로 8과 9의 값이 나온다~ㅇ
   한번 고생한적이 있어서여~ㅇ 다른분들에게 도움이 되었으면...



ㅇ   <img name="pic1" src="">
   <img name="pic2" src="">
   <img name="pic3" src="">

   위와 같이 있고 javascript에서 pic1 ~ pic3의 src주소값을 바꾸고자 할때
   
   for (var nI = 1; nI <= 3; nI ++)
   {
        e-al("document.pic" + nI + ".src ='http://image.aaa.com/p" + nI + ".gif'");
   }
   
   위와 같이 eval을 넣어주어야 되더라구여~ㅇ



ㅇ 현재의 html파일을 다른이름을로 저장할때 뜨는 dialog박스를 열어서 저장하고 싶을때
   
   그냥 다음한줄을 실행시키면 저장 dialog박스가 뜨는걸로 뭐하는지 알겁니다~ㅇ
   document.execCommand("SaveAs", null, "a.html")

   다르게하면 다음의 한줄을 넣고
   <iframe name="ID_LOG" style="display:none"></iframe>가 body에 있다고 하고

   var sHTML = "<center>Testing...</center>";
   document.all.ID_LOG.document.close ();
   document.all.ID_LOG.document.write (sHTML);
   document.all.ID_LOG.document.execCommand("SaveAs", null, sFileName);

   하면 Testing가 찍히는 html문서를 저장할수 있져~ㅇ 그런데 이거는 IE 5.5이상에서만 됩니다.

   5.0에서는

   var sHTML   = "<input type='button' value='저장' 허용되지않은 태그 사용중=\"window.document.execCommand('SaveAs', null, 'a.html')\">";
       sHTML   += "<br><center> Testing..</center>";
   
   var oLogWin   = window.open ("", "popLog", "어쩌구...");
   
   oLogWin.document.write (sHTML);

   해서 새창띄워서 클릭하게 하면 됩니다~ㅇ



ㅇ 그리고 Javascript에서 name이나 id값이 같은것이 있으면 Array로 변하더군요...
   Javascript많이 사용하다보면 많이 접하셨을겁니다~ㅇ
   
   동적으로 name이나 id값이 1나 1이상을로 늘어날때에

   <span id="ID_A"></span>
   <span id="ID_A"></span>
   이 있다고 할때

   Javascript 안에서 에서

   var oID_A   = document.all.ID_A;

   if (typeof (oID_A [0]) != "undefined")) // 1개 이상일때
   {
   
   }
   else   // 1개만 있을경우
   {
   
   }

   물론 "ID_A" id값을 가지고 있는것이 있는지 먼저 검사하면 좋져~ㅇ



ㅇ 만약 a와 b와 c의 값을 구분자 ","로 구분하는 String (a,b,c)을 만들고 싶을때

   var oTmpArray = new Array ("a", "b", "c");
   var sValue = oTmpArray.j-in (",");



ㅇ javascript 연관배열
   
   var oMethod =   {
        "ALERT"   : goAlert,
        "MSG"   : goMsg
   }

   oMethod ["ALERT"] 는
   goAlert가 됩니다.



ㅇ 허용되지않은 태그 사허용되지않은 태그 사용중그 사용중, onMousewheel... 등등의 이벤트를 붙이거나 떼기
   
   window.attachEvent ("onscroll", procScroll);
    하면 onscroll이벤트 발생시 procScroll함수 실행
   
   window.detachEvent ("onscroll", procScroll);
   하면 onscroll이벤트 떼기



ㅇ 움직이는 gif이미지를 key이벤트나 등등 이벤트사용하면 움직이던 gif이미지가 멈추어버립니다.
   알고보니 return값땜시 "event.returnValue = 'false'" 해주면 되더라구여~ㅇ



ㅇ ActiveX를 사용시 ActiveX클라이언트가 ActiveX를 다운 받았는지 확인할때는
   
   <object name=AX1 id=AX1></object> 가 있을때

   var bnResult   = typeof (AX1.proc) == "unknown")? true : false;
   proc는 AX1의 method입니다~ㅇ
   이렇게 확인하면 되더라구여~ㅇ



ㅇ F5번 누를때 경고창(confirm같은것)띄워서 새로고침 할건지 물어보기
   
   window.onbeforeunload   = hoho ();

   function hoho ()
   {
        var sMsg = "새로고침을 정말로 정말로 정말로 할꺼예여?";
        return (sMsg);
   }
   물론 F5번 눌렀을때를 key Event로 잡아서 함수안에서 실행해도 됩니다~ㅇ



ㅇ VBscript에만 있는줄 알았던 with 많이 쓰일때가 있더군요 switch문을 안에다가 사용하면 정말 깔끔!
   
   with (window)
   {
           = pageOnLoad;
        o-unload = pageUnload;
   }

Posted by 1010
반응형

/**********************************************************************
 *
 *  cookie 공통 모듈
 *
 **********************************************************************/
/**
  * 쿠키정보 가져오기
  * @param name  쿠키명
  */
function getCookie(name) {
 var Found = false;
 var start, end;
 var i = 0;
 var cookieData = document.cookie;
 while(i <= cookieData.length) {
    start = i;
   end = start + name.length;
   
   if(cookieData.substring(start, end) == name) {
      Found = true;
      break;
    }
    i++;
 }
 if(Found == true) {
    start = end + 1;
    end = cookieData.indexOf(";", start);
    if(end < start)
      end = cookieData.length;
     return cookieData.substring(start, end);
   }
    
 return "";
}

/**
  * 쿠키 설정
  * @param cookieName 쿠키명
  * @param cookieValue 쿠키값
  * @param expireDay 쿠키 유효날짜
  */
function setCookie( cookieName, cookieValue){
   var today = new Date();
   today.setDate( today.getDate() + 365 );   // 저장 기간
   document.cookie = cookieName + "=" +  cookieValue  + "; path=/; expires=" + today.toGMTString() + ";";
}

/**
  * 쿠키 삭제
  * @param cookieName 삭제할 쿠키명
  */
function deleteCookie(cookieName ){
   var expireDate = new Date();
 
   //어제 날짜를 쿠키 소멸 날짜로 설정한다.
   expireDate.setDate( expireDate.getDate() - 1 );
   document.cookie = cookieName + "=" + "; expires=" + expireDate.toGMTString() + "; path=/";
 
}

/**********************************************************************
 *
 *  관심자료 cookie
 *
 **********************************************************************/

/**
  * 관심자료 목록 가져오기
  * return : list1[]
  */
function getCernDatList(){
 var list =  "";
 if (navigator.appName.charAt(0) == 'N') {
  list = fromUtf8(getCookie('cernDatList'));
 } else if (navigator.appName.charAt(0) == 'M') {
  list = getCookie('cernDatList');
 }
 if(list.length>0){
  list =  list.split("---");
 }else{
  list = "";
 }
 return list;
}


/**
  * 관심자료 등록 
  */
function setCernDatList(url,title){
 if(title!=""){
  //1.관심자료 목록 가져오기
  var datList = getCernDatList();
  var tempData = "";
  var mode = 0;
  var first = 0;
  var uName = "";
  if(datList.length>0){
   //2. 중복자료 검사
   var para = "";
   var titleV = "";
   var temp = "";
   for(var i=0;i<datList.length;i++){
    temp = datList[i].split("--");
    if(temp != null){
     para = temp[0].substring(4);
     titleV = temp[1].substring(6);
     if(para==url){
      mode = 1;
      break;
     }else{
      // 2-1 데이터 저장
      if(tempData==""){
        uName = 'url=';
      }else{
        uName = '---url=';
      }
      if (navigator.appName.charAt(0) == 'N') {
       tempData += uName+toUtf8(para)+'--title='+toUtf8(titleV);
      } else if (navigator.appName.charAt(0) == 'M') {
       tempData += uName+para+'--title='+titleV;
      }
     }
    }
   }
  }else{
   first = 1;
  }
  //3. 등록 
  if(mode == 0){
   if(datList.length <= 20){    // 저장 개수 설정
    if(first==1){
     uName = 'url=';
    }else{
     uName = tempData+'---url=';
    }
    if (navigator.appName.charAt(0) == 'N') {
     setCookie('cernDatList',uName+toUtf8(url)+'--title='+toUtf8(title));
    } else if (navigator.appName.charAt(0) == 'M') {
     setCookie('cernDatList',uName+url+'--title='+title);
    }
   
    //4. 등록 확인
    var resultSize = getCernDatList();
    if(datList.length<resultSize.length){
     alert("관심자료에 등록되었습니다.");
    }else{
     alert("관심자료 등록 중 오류가 발생하였습니다.");
    }
   }else{
    alert("저장 개수가 초과되었습니다.\n(20개까지 저장 가능합니다.)");
   }
  }else{
   alert("이미 등록된 자료입니다.");
  } 
 }else{
  alert("등록 자료가 없습니다.");
 }
}

/**
  * 관심자료 삭제
  */
function delCernDatList(){
 var oldCernSize = getCernDatList();
 //if(!document.cernFrm.allCernLi.checked){
  
  var delNo = "";
  var cernList = "";
  var temp = "";
  var para = "";
  var titleV = "";
  var tempData = "";
  var boo = "";
  var cntCheckNo = 0;
  for(var i=0;i<els("cernLi").length;i++){
   if(els("cernLi").length==1){
    boo = els("cernLi")[i].checked
    delNo = els("cernLi")[i].value;
    
   }else{
    boo = els("cernLi")[i].checked
    delNo = els("cernLi")[i].value;
   }
    cernList = getCernDatList();
    tempData = "";
   if(getCookie('cernDatList')!=""){
    for(var j=0;j<cernList.length;j++){
     temp = cernList[j].split("--");
     para = temp[0].substring(4);
     titleV = temp[1].substring(6);
     if(para==delNo && boo==true){
      cntCheckNo = 1;
     }else{
      if(tempData==""){
        uName = 'url=';
      }else{
        uName = '---url=';
      }
      if (navigator.appName.charAt(0) == 'N') {
       tempData += uName+toUtf8(para)+'--title='+toUtf8(titleV);
      } else if (navigator.appName.charAt(0) == 'M') {
       tempData += uName+para+'--title='+titleV;
      }
     }
    }
    // 삭제 리스트 제외한 리스트 저장
    setCookie('cernDatList',tempData);
   }
  }
  if(cntCheckNo>0){
   //setCookie('cernDatList',tempData);
   var afList = getCernDatList();
   if(oldCernSize.length>afList.length){
    alert("관심자료 삭제 성공");
   }else{
    alert("관심자료 삭제 실패");
   }
  }else{
   alert("선택된 자료가 없습니다.");
  }
 outputList();
}


/**
  * 관심자료 리스트 뿌려주기
  */
function outputList() {
    var temp = "";
 if (navigator.appName.charAt(0) == 'N') {
     temp = fromUtf8(getCookie('cernDatList'));
   } else if (navigator.appName.charAt(0) == 'M') {
     temp = getCookie('cernDatList');
   }
 var text = temp.split("---");
 var outText = "";
 var divHtml = "<ul>";
 if(temp!=""){
  var sortNo = text.length-1;
  var tempNo = 0;
  for(var i = 0; i<text.length;i++){
    outText = text[sortNo].split("--");
    tempNo = i+1;
    divHtml += "<li><input type=\"checkbox\" class=\"vmid\" name=\"cernLi\" value=\""+outText[0].substring(4)+"\"/><a href=\"#\" onclick=\"javascript:openPop('"
      + outText[0].substring(4) + "');\">&nbsp;" + tempNo +".&nbsp;"
      + outText[1].substring(6).replace("00000","<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;") +
      "</a></li>";
    sortNo--;
     }
 }else{
   divHtml += "<li>자료 없음</li>";
 }
 //alert(divHtml);
    document.getElementById("cernDat").innerHTML = divHtml+"</ul>";

 
/**
  * 관심자료 리스트 보여주기
  */
function fCernDat(){
 var mode = document.getElementById("cernDat").style.display;
 if(mode==""){
  document.getElementById("cernDat").style.display = "none";
 }else{
  document.getElementById("cernDat").style.display = "";
  outputList();
 }
 
   
}
 
/**********************************************************************
 *
 *  Unicode ⇔ UTF-8
 *
 **********************************************************************/

function toUtf8(s) {
  var c, d = "";
  for (var i = 0; i < s.length; i++) {
    c = s.charCodeAt(i);
    if (c <= 0x7f) {
      d += s.charAt(i);
    } else if (c >= 0x80 && c <= 0x7ff) {
      d += String.fromCharCode(((c >> 6) & 0x1f) | 0xc0);
      d += String.fromCharCode((c & 0x3f) | 0x80);
    } else {
      d += String.fromCharCode((c >> 12) | 0xe0);
      d += String.fromCharCode(((c >> 6) & 0x3f) | 0x80);
      d += String.fromCharCode((c & 0x3f) | 0x80);
    }
  }
  return d;
}

function fromUtf8(s) {
  var c, d = "", flag = 0, tmp;
  for (var i = 0; i < s.length; i++) {
    c = s.charCodeAt(i);
    if (flag == 0) {
      if ((c & 0xe0) == 0xe0) {
        flag = 2;
        tmp = (c & 0x0f) << 12;
      } else if ((c & 0xc0) == 0xc0) {
        flag = 1;
        tmp = (c & 0x1f) << 6;
      } else if ((c & 0x80) == 0) {
        d += s.charAt(i);
      } else {
        flag = 0;
      }
    } else if (flag == 1) {
      flag = 0;
      d += String.fromCharCode(tmp | (c & 0x3f));
    } else if (flag == 2) {
      flag = 3;
      tmp |= (c & 0x3f) << 6;
    } else if (flag == 3) {
      flag = 0;
      d += String.fromCharCode(tmp | (c & 0x3f));
    } else {
      flag = 0;
    }
  }
  return d;
}

 /**********************************************************************
 *
 *  내가 찾은 자료  & 검색어 목록
 *
 **********************************************************************/
 
/**
  * 리스트 보여주기
  */
function fQuickDat(dataId){
 var mode = document.getElementById(dataId+"List").style.display;
 if(mode==""){
  document.getElementById(dataId+"List").style.display = "none";
 }else{
  document.getElementById(dataId+"List").style.display = "";
  outputDataList(dataId);
 }
 
   
}
 
 
/**
  * 목록 가져오기
  * return : list1[]
  */
function getDatList(dataId){
 var list =  "";
 if (navigator.appName.charAt(0) == 'N') {
  list = fromUtf8(getCookie(dataId));
 } else if (navigator.appName.charAt(0) == 'M') {
  list = getCookie(dataId);
 }
 if(list.length>0){
  list =  list.split("---");
 }else{
  list = "";
 }
 return list;
}

/**
  * 등록 
  */
function setDatList(dataId, url, title){
 
 if(title != ""){
  //1.목록 가져오기
  var datList = getDatList(dataId);
  var tempData = "";
  var first = 0;
  var uName = "";
  if(datList.length > 0){
   //2. 중복자료 검사
   var preSavedUrl = "";
   var preSavedTitle = "";
   var temp = "";
  
   for(var i = 0; i < datList.length; i++){
    temp = datList[i].split("--");
    preSavedUrl = temp[0].substring(4);
    preSavedTitle = temp[1].substring(6);
   
    if(preSavedUrl == url){
     //alert(preSavedUrl); 최상위로 올림
     //return false;
     
    }else{
     // 2-1 데이터 저장
     if(tempData == ""){
       uName = 'url=';
     }else{
       uName = '---url=';
     }
     if (navigator.appName.charAt(0) == 'N') {
      tempData += uName + toUtf8(preSavedUrl) + '--title=' + toUtf8(preSavedTitle);
     } else if (navigator.appName.charAt(0) == 'M') {
      tempData += uName + preSavedUrl + '--title=' + preSavedTitle;
     }
    }
   }
  }
  else{
   first = 1;
  }
  
  //3. 등록 
  //alert(mode+"---"+datList.length);
  if(first==1){
   uName = 'url=';
  }
  else{
   uName = tempData + '---url=';
  }
 
  if (navigator.appName.charAt(0) == 'N') {
   setCookie(dataId, uName + toUtf8(url) + '--title=' + toUtf8(title));
  }
  else if (navigator.appName.charAt(0) == 'M') {
   setCookie(dataId, uName + url + '--title=' + title);
  }
 
  //alert(datList.length);
  if(datList.length > 20){  // 저장 개수 설정
   delDatList(dataId, 1);
  }
 }
 
}

 
 
/**
  * 삭제        (쿠키 id, 삭제 모드)
  */
function delDatList(dataId,mode){
 var oldCernSize = getDatList(dataId);
 if(mode==1){
  var cernList = "";
  var temp = "";
  var para = "";
  var titleV = "";
  var tempData = "";
 
    cernList = getDatList(dataId);
    tempData = "";
   if(getCookie(dataId)!=""){
    for(var j=0;j<cernList.length;j++){
     temp = cernList[j].split("--");
     para = temp[0].substring(4);
     titleV = temp[1].substring(6);
     if(j==0){
      
     }else{
      if(tempData==""){
        uName = 'url=';
      }else{
        uName = '---url=';
      }
      if (navigator.appName.charAt(0) == 'N') {
       tempData += uName+toUtf8(para)+'--title='+toUtf8(titleV);
      } else if (navigator.appName.charAt(0) == 'M') {
       tempData += uName+para+'--title='+titleV;
      }
     }
    }
    // 삭제 리스트 제외한 리스트 저장
    setCookie(dataId,tempData);
   }
  
 }else{
  deleteCookie(dataId);
  var resultSize = getDatList(dataId);
  if(oldCernSize.length>resultSize.length){
   alert("삭제 성공");
  }else{
   alert("삭제 실패");
  }
 }
 //outputDataList(dataId);
}
 
 
/**
  * 리스트 뿌려주기
  */
function outputDataList(dataId) {
    var temp = "";
 if (navigator.appName.charAt(0) == 'N') {
     temp = fromUtf8(getCookie(dataId));
   } else if (navigator.appName.charAt(0) == 'M') {
     temp = getCookie(dataId);
   }
 var text = temp.split("---");
 var outText = "";
 var divHtml = "";
 var conTit = "";
 if(temp!=""){
  var sortNo = text.length-1;
  for(var i = 0; i < text.length && i < mainListSize;i++){
    outText = text[sortNo].split("--");
   if(outText != ""){
    if(dataId=="myFindDat"){
     idxStart = outText[1].indexOf("[");
   
     if(idxStart > 6) subject = outText[1].substring(6, idxStart);
     else    subject = outText[1].substring(6);
     subject = subject.replace("00000","").replace("_", "").replace("title=", "").replace("n", "");
     if(subject.length > 23) subject = subject.substring(0, 24) + "...";
     
     if(idxStart > 0){
         content = outText[1].substring(idxStart);
         conTit  = outText[1].substring(idxStart);
        
     } else {
         content = "";
         conTit  = "";
     }
     
     if(content.length > 8) content = content.substring(0, 9) + "...";
   
     divHtml += "<dt><a href=\"#\" onclick=\"javascript:openPop('" + outText[0].substring(4) + "');\" >"
      //+ (i + 1) + ". "
      + subject + "</a></dt>";    
     divHtml += "<dd><span title='"+conTit+"'>" + content + "</span></dd><br>";
    }else{
     divHtml += "<p><a href=\"#\" onclick=\"javascript:openPop('" + outText[0].substring(4) + "');\" >"
      + (i + 1) + ". " + outText[1].substring(6) + "</a></p><br>";
    }
   }
    sortNo--;
     }
         /*alert(outText[0].substring(4));
         alert(outText[1].substring(6));*/
 }else{
   divHtml += "<dt>조회한 이력이 없습니다.</dt>";
 }
    document.getElementById(dataId).innerHTML = "<dl>" + divHtml + "</dl>";

function outputDataNmList(dataId) {

    var temp = "";
 if (navigator.appName.charAt(0) == 'N') {
     temp = fromUtf8(getCookie(dataId));
   } else if (navigator.appName.charAt(0) == 'M') {
     temp = getCookie(dataId);
   }
 var text = temp.split("---");
 var outText = "";
 var divHtml = "";
 if(temp!=""){
  var sortNo = text.length-1;
  for(var i = 0; i < text.length;i++){
    outText = text[sortNo].split("--");
    divHtml += "<p><a href=" + outText[0].substring(4) + " >"
      + (i + 1) + ". " + outText[1].substring(6) + "</a></p>";
    sortNo--;
     }
         /*alert(outText[0].substring(4));
         alert(outText[1].substring(6));*/
 }else{
   divHtml += "<p>자료 없음</p>";
 }
    document.getElementById(dataId).innerHTML = divHtml;


/**
  * 검색어 쿠키 등록
  */
function fSearchKeySaveF(){
 setDatList('schTrmDat','searchKeyWord',document.getElementById("searchKeyWord").value);
}

function searchTrmSave(url, id){
 setDatList('schTrmDat', url, el(id).value);
}

/**
  * 검색어 쿠키 등록  (다음 실행 함수)
  */
function fSearchKeySave(nextProc){
 setDatList('schTrmDat','searchKeyWord',document.getElementById("searchKeyWord").value);
 nextProc();
}

function addMyFindDat(url, id){
    try{
 url = url.replaceAll("<strong>", "").replaceAll("</strong>", "");
 setDatList("myFindDat", url, id)
 }catch(e){deleteCookie("myFindDat");}
}

// 내가 찾은용어  검색 라인에 보여주기
function searchTrmView(callBackName){
 var temp = "";
 var dataId = "schTrmDat";
 if (navigator.appName.charAt(0) == 'N') {
     temp = fromUtf8(getCookie(dataId));
   } else if (navigator.appName.charAt(0) == 'M') {
     temp = getCookie(dataId);
   }
 var text = temp.split("---");
 var outText = "";
 var divHtml = "";
 if(temp == null || temp.trim() == ""){
   divHtml += "검색어를 입력하세요.";
 }
 else{
  var sortNo = text.length;
  if(sortNo > 5){
   sortNo = 5;
  }
  var tempNo = text.length - 1;
  var txtTitle = "";
  for(var i = 0; i < sortNo; i++){
    outText = text[tempNo].split("--");
    txtTitle = outText[1].substring(6);
    if(txtTitle.length > 7){
     txtTitle = txtTitle.substring(0,7) + "...";
    }

   if(i > 0) divHtml += ", ";
   if(typeof(callBackName) != "undefined" && callBackName != null){
    divHtml += "<a href=# onclick=\"javascript:" + callBackName + "('" + outText[1].substring(6) + "');\" >" + txtTitle + "</a>";
   }
   else{
     divHtml += "<a href=" + outText[0].substring(4) + " title="+outText[1].substring(6)+">" + txtTitle + "</a>";
   }

    tempNo --;
     }
  divHtml = divHtml.substring(0, divHtml.length - 1); 
 }

    document.getElementById("searchTrm").innerHTML = divHtml;
}


 /**********************************************************************
 *
 *  내가 찾은 법령 이력
 *
 **********************************************************************/
var maxDetailCookie = 10;
function setDetailSelectCookie(lawKubun,seq){
 var dataId = "lawHistory";
 var dataSeq = "";
 var dataSeq = lawKubun+","+seq;
 
 if(dataSeq != ""){
  var datList = getDatList(dataId);
  var tempData = "";
  var uName = "";
  var isFirst = true;
  if(datList.length > 0){
   for(var i = 0; i < datList.length; i++){
    if ( datList[i] == dataSeq ) continue;

    if(tempData == ""){
      uName = "";
    }else{
      uName = "---";
    }
    if (navigator.appName.charAt(0) == 'N') {
     tempData += uName + toUtf8(datList[i]);
    } else if (navigator.appName.charAt(0) == 'M') {
     tempData += uName + datList[i];
    }       
   }
   isFirst = false;
  }
 
  if( isFirst == true ) {
   uName = "";
  } else {
   uName = tempData + "---";
  }
 
  if (navigator.appName.charAt(0) == 'N') {
   setCookie(dataId, uName + toUtf8(dataSeq));
  } else if (navigator.appName.charAt(0) == 'M') {
   setCookie(dataId, uName + dataSeq);
  } 
 
  if(datList.length >= maxDetailCookie){  // 저장 개수 설정
   delDetailSelectCookie(dataId);
  }     
 }
}

/**
  * 20개 이상 쿠키 삭제
  */
function delDetailSelectCookie(dataId){
 var oldList = getDatList(dataId);
 
 if ( oldList.length <= maxDetailCookie ) return;
 
 var tmpData = "";
 var isFirst = true;
 var uName = "";
 
 
 oldList.reverse();
 
 for(var i = 0; i < maxDetailCookie; i ++) {
  if ( i == 0 )
   uName = "";
  else
   uName = "---";
  if (navigator.appName.charAt(0) == 'N') {
   tmpData = toUtf8(oldList[i]) + uName + tmpData;
  } else if (navigator.appName.charAt(0) == 'M') {
   tmpData = oldList[i] + uName + tmpData;
  }
 }
 
 // 삭제 리스트 제외한 리스트 저장
 setCookie(dataId,tmpData);
}

function getDetailSelectCookie(dataId){
 var list =  "";
 if (navigator.appName.charAt(0) == 'N') {
  list = fromUtf8(getCookie(dataId));
 } else if (navigator.appName.charAt(0) == 'M') {
  list = getCookie(dataId);
 }
 return list;
}



/**********************************************************************
 *
 *  Nethru_pcId 모듈
 *
 **********************************************************************/

function Nethru_getCookieVal(offset)
{
 var endstr = document.cookie.indexOf (";", offset);
 if (endstr == -1)
  endstr = document.cookie.length;
 return unescape(document.cookie.substring(offset, endstr));
}

function Nethru_SetCookie(name, value){
   var argv = Nethru_SetCookie.arguments;
   var argc = Nethru_SetCookie.arguments.length;
   var expires = (2 < argc) ? argv[2] : null;
   var path = (3 < argc) ? argv[3] : null;
   var domain = (4 < argc) ? argv[4] : null;
   var secure = (5 < argc) ? argv[5] : false;
 //alert(value);
   //alert("DOMAIN = " + domain);
   document.cookie = name + "=" + escape (value) +
        ((expires == null) ? "" : ("; expires="+expires.toGMTString())) +
     ((path == null) ? "" : ("; path=" + path)) +
     ((domain == null) ? "" : ("; domain=" + domain)) +
        ((secure == true) ? "; secure" : "");

 //alert(document.cookie);
}

function Nethru_GetCookie(name){
   var arg = name + "=";
   var alen = arg.length;
   var clen = document.cookie.length;
   var i = 0;
   while (i < clen)
      {
      var j = i + alen;
      if (document.cookie.substring(i, j) == arg)
         return Nethru_getCookieVal (j);
      i = document.cookie.indexOf(" ", i) + 1;
      if (i == 0)
         break;
      }
  return null;
}

function Nethru_makePersistentCookie(name,length,path,domain)
{
// alert(name+" -- "+length+"--"+path+"--"+domain);
    var today = new Date();
    var expiredDate = new Date(2011,1,1);
    var cookie;
 var value;

    cookie = Nethru_GetCookie(name);
    if ( cookie ) {
//  alert(cookie);
        return 1;
 }

 var values = new Array();
 for ( i=0; i < length ; i++ ) {
  values[i] = "" + Math.random();
 }

 value = today.getTime();

 // use first decimal
 for ( i=0; i < length ; i++ ) {
  value += values[i].charAt(2);
 }

    Nethru_SetCookie(name,value,expiredDate,path,domain);
}

function Nethru_getDomain() {
 var _host   = document.domain;
 var so      = _host.split('.');
 var dm    = so[so.length-2] + '.' + so[so.length-1];
 return (so[so.length-1].length == 2) ? so[so.length-3] + '.' + dm : dm;
}

var Nethru_domain  = Nethru_getDomain();
Nethru_makePersistentCookie("PCID",10,"/",Nethru_domain);



Posted by 1010
반응형

/// #############################################################################
/// #####
/// ##### 한국신용정보주식회사 서비스 운영에 필요한 Crypto JavaScript 소스
/// #####
/// ##### =====================================================================
/// #####
/// ##### Descriptions
/// #####  - 서비스 운영에 필요한 Javascript Crypto Algorithm을 관리한다.
/// #####
/// ##### ---------------------------------------------------------------------
/// #####
/// ##### 작성자   : (주)유비아이에스컨설팅 (www.ubisc.com)
/// ##### 원본참조 :
/// ##### 원본파일 :
/// ##### 작성일자 : 2006.02.06
/// #####
/// #############################################################################

// -----------------------------------------------------
// ----- 보안 처리를 위한 Object 처리 정보
// -----------------------------------------------------

var cryptoObject = new Object();
cryptoObject.KeyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

//
// Base 64 Decode
//
cryptoObject.decode64 = function( input )
{
 var output = "";
 var chr1, chr2, chr3;
    var enc1, enc2, enc3, enc4;
    var i = 0;
    var strValue = input;

    // remove all characters that are not A-Z, a-z, 0-9, +, /, or =
 var re = /[^A-Za-z0-9\+\/\=]/g;
    strValue = strValue.replace( re, "" );

    do
    {
       enc1 = cryptoObject.KeyStr.indexOf(strValue.charAt(i++));
       enc2 = cryptoObject.KeyStr.indexOf(strValue.charAt(i++));
       enc3 = cryptoObject.KeyStr.indexOf(strValue.charAt(i++));
       enc4 = cryptoObject.KeyStr.indexOf(strValue.charAt(i++));

       chr1 = (enc1 << 2) | (enc2 >> 4);
       chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
       chr3 = ((enc3 & 3) << 6) | enc4;

       output = output + String.fromCharCode(chr1);

       if (enc3 != 64)
       {
          output = output + String.fromCharCode(chr2);
       }

       if (enc4 != 64)
       {
          output = output + String.fromCharCode(chr3);
       }
    }
    while (i < strValue.length);

   return output;
}

//
// Base 64 Encode
//
cryptoObject.encode64 = function( input )
{
    var output = "";
    var chr1, chr2, chr3;
    var enc1, enc2, enc3, enc4;
    var i = 0;

    do
    {
       chr1 = input.charCodeAt(i++);
       chr2 = input.charCodeAt(i++);
       chr3 = input.charCodeAt(i++);

       enc1 = chr1 >> 2;
       enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
       enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
       enc4 = chr3 & 63;

       if (isNaN(chr2))
       {
         enc3 = enc4 = 64;
       }
       else if (isNaN(chr3))
       {
        enc4 = 64;
       }

       output = output + cryptoObject.KeyStr.charAt(enc1) + cryptoObject.KeyStr.charAt(enc2) +
          cryptoObject.KeyStr.charAt(enc3) + cryptoObject.KeyStr.charAt(enc4);
    }
    while (i < input.length);

    return output;
}

//
// MD5 Hash
//
cryptoObject.md5 = function( sMessage )
{
  function RotateLeft(lValue, iShiftBits) { return (lValue<<iShiftBits) | (lValue>>>(32-iShiftBits)); }
  function AddUnsigned(lX,lY) {
  var lX4,lY4,lX8,lY8,lResult;
  lX8 = (lX & 0x80000000);
  lY8 = (lY & 0x80000000);
  lX4 = (lX & 0x40000000);
  lY4 = (lY & 0x40000000);
  lResult = (lX & 0x3FFFFFFF)+(lY & 0x3FFFFFFF);
  if (lX4 & lY4) return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
  if (lX4 | lY4)
  {
   if (lResult & 0x40000000) return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
   else return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
  }
  else return (lResult ^ lX8 ^ lY8);
 }
 function F(x,y,z) { return (x & y) | ((~x) & z); }
 function G(x,y,z) { return (x & z) | (y & (~z)); }
 function H(x,y,z) { return (x ^ y ^ z); }
 function I(x,y,z) { return (y ^ (x | (~z))); }
 function FF(a,b,c,d,x,s,ac) {
  a = AddUnsigned(a, AddUnsigned(AddUnsigned(F(b, c, d), x), ac));
  return AddUnsigned(RotateLeft(a, s), b);
 }
 function GG(a,b,c,d,x,s,ac) {
  a = AddUnsigned(a, AddUnsigned(AddUnsigned(G(b, c, d), x), ac));
  return AddUnsigned(RotateLeft(a, s), b);
 }
 function HH(a,b,c,d,x,s,ac) {
  a = AddUnsigned(a, AddUnsigned(AddUnsigned(H(b, c, d), x), ac));
  return AddUnsigned(RotateLeft(a, s), b);
 }
 function II(a,b,c,d,x,s,ac) {
  a = AddUnsigned(a, AddUnsigned(AddUnsigned(I(b, c, d), x), ac));
  return AddUnsigned(RotateLeft(a, s), b);
 }
 function ConvertToWordArray(sMessage)
 {
  var strMsg = new String( sMessage );
  var lWordCount;
  var lMessageLength = strMsg.length;
  var lNumberOfWords_temp1=lMessageLength + 8;
  var lNumberOfWords_temp2=(lNumberOfWords_temp1-(lNumberOfWords_temp1 % 64))/64;
  var lNumberOfWords = (lNumberOfWords_temp2+1)*16;
  var lWordArray=Array(lNumberOfWords-1);
  var lBytePosition = 0;
  var lByteCount = 0;
  while ( lByteCount < lMessageLength ) {
   lWordCount = (lByteCount-(lByteCount % 4))/4;
   lBytePosition = (lByteCount % 4)*8;
   lWordArray[lWordCount] = (lWordArray[lWordCount] | (strMsg.charCodeAt(lByteCount)<<lBytePosition));
   lByteCount++;
  }
  lWordCount = (lByteCount-(lByteCount % 4))/4;
  lBytePosition = (lByteCount % 4)*8;
  lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80<<lBytePosition);
  lWordArray[lNumberOfWords-2] = lMessageLength<<3;
  lWordArray[lNumberOfWords-1] = lMessageLength>>>29;
  return lWordArray;
 }
 function WordToHex(lValue) {
  var WordToHexValue="",WordToHexValue_temp="",lByte,lCount;
  for (lCount = 0;lCount<=3;lCount++) {
   lByte = (lValue>>>(lCount*8)) & 255;
   WordToHexValue_temp = "0" + lByte.toString(16);
   WordToHexValue = WordToHexValue + WordToHexValue_temp.substr(WordToHexValue_temp.length-2,2);
  }
  return WordToHexValue;
 }

 var strMsg = new String( sMessage );
 var x=Array();
 var k,AA,BB,CC,DD,a,b,c,d
 var S11=7, S12=12, S13=17, S14=22;
 var S21=5, S22=9 , S23=14, S24=20;
 var S31=4, S32=11, S33=16, S34=23;
 var S41=6, S42=10, S43=15, S44=21;
 // Steps 1 and 2.  Append padding bits and length and convert to words
 x = ConvertToWordArray(strMsg);
 // Step 3.  Initialise
 a = 0x67452301; b = 0xEFCDAB89; c = 0x98BADCFE; d = 0x10325476;
 // Step 4.  Process the message in 16-word blocks
 for (k=0;k<x.length;k+=16) {
  AA=a; BB=b; CC=c; DD=d;
  a=FF(a,b,c,d,x[k+0], S11,0xD76AA478);
  d=FF(d,a,b,c,x[k+1], S12,0xE8C7B756);
  c=FF(c,d,a,b,x[k+2], S13,0x242070DB);
  b=FF(b,c,d,a,x[k+3], S14,0xC1BDCEEE);
  a=FF(a,b,c,d,x[k+4], S11,0xF57C0FAF);
  d=FF(d,a,b,c,x[k+5], S12,0x4787C62A);
  c=FF(c,d,a,b,x[k+6], S13,0xA8304613);
  b=FF(b,c,d,a,x[k+7], S14,0xFD469501);
  a=FF(a,b,c,d,x[k+8], S11,0x698098D8);
  d=FF(d,a,b,c,x[k+9], S12,0x8B44F7AF);
  c=FF(c,d,a,b,x[k+10],S13,0xFFFF5BB1);
  b=FF(b,c,d,a,x[k+11],S14,0x895CD7BE);
  a=FF(a,b,c,d,x[k+12],S11,0x6B901122);
  d=FF(d,a,b,c,x[k+13],S12,0xFD987193);
  c=FF(c,d,a,b,x[k+14],S13,0xA679438E);
  b=FF(b,c,d,a,x[k+15],S14,0x49B40821);
  a=GG(a,b,c,d,x[k+1], S21,0xF61E2562);
  d=GG(d,a,b,c,x[k+6], S22,0xC040B340);
  c=GG(c,d,a,b,x[k+11],S23,0x265E5A51);
  b=GG(b,c,d,a,x[k+0], S24,0xE9B6C7AA);
  a=GG(a,b,c,d,x[k+5], S21,0xD62F105D);
  d=GG(d,a,b,c,x[k+10],S22,0x2441453);
  c=GG(c,d,a,b,x[k+15],S23,0xD8A1E681);
  b=GG(b,c,d,a,x[k+4], S24,0xE7D3FBC8);
  a=GG(a,b,c,d,x[k+9], S21,0x21E1CDE6);
  d=GG(d,a,b,c,x[k+14],S22,0xC33707D6);
  c=GG(c,d,a,b,x[k+3], S23,0xF4D50D87);
  b=GG(b,c,d,a,x[k+8], S24,0x455A14ED);
  a=GG(a,b,c,d,x[k+13],S21,0xA9E3E905);
  d=GG(d,a,b,c,x[k+2], S22,0xFCEFA3F8);
  c=GG(c,d,a,b,x[k+7], S23,0x676F02D9);
  b=GG(b,c,d,a,x[k+12],S24,0x8D2A4C8A);
  a=HH(a,b,c,d,x[k+5], S31,0xFFFA3942);
  d=HH(d,a,b,c,x[k+8], S32,0x8771F681);
  c=HH(c,d,a,b,x[k+11],S33,0x6D9D6122);
  b=HH(b,c,d,a,x[k+14],S34,0xFDE5380C);
  a=HH(a,b,c,d,x[k+1], S31,0xA4BEEA44);
  d=HH(d,a,b,c,x[k+4], S32,0x4BDECFA9);
  c=HH(c,d,a,b,x[k+7], S33,0xF6BB4B60);
  b=HH(b,c,d,a,x[k+10],S34,0xBEBFBC70);
  a=HH(a,b,c,d,x[k+13],S31,0x289B7EC6);
  d=HH(d,a,b,c,x[k+0], S32,0xEAA127FA);
  c=HH(c,d,a,b,x[k+3], S33,0xD4EF3085);
  b=HH(b,c,d,a,x[k+6], S34,0x4881D05);
  a=HH(a,b,c,d,x[k+9], S31,0xD9D4D039);
  d=HH(d,a,b,c,x[k+12],S32,0xE6DB99E5);
  c=HH(c,d,a,b,x[k+15],S33,0x1FA27CF8);
  b=HH(b,c,d,a,x[k+2], S34,0xC4AC5665);
  a=II(a,b,c,d,x[k+0], S41,0xF4292244);
  d=II(d,a,b,c,x[k+7], S42,0x432AFF97);
  c=II(c,d,a,b,x[k+14],S43,0xAB9423A7);
  b=II(b,c,d,a,x[k+5], S44,0xFC93A039);
  a=II(a,b,c,d,x[k+12],S41,0x655B59C3);
  d=II(d,a,b,c,x[k+3], S42,0x8F0CCC92);
  c=II(c,d,a,b,x[k+10],S43,0xFFEFF47D);
  b=II(b,c,d,a,x[k+1], S44,0x85845DD1);
  a=II(a,b,c,d,x[k+8], S41,0x6FA87E4F);
  d=II(d,a,b,c,x[k+15],S42,0xFE2CE6E0);
  c=II(c,d,a,b,x[k+6], S43,0xA3014314);
  b=II(b,c,d,a,x[k+13],S44,0x4E0811A1);
  a=II(a,b,c,d,x[k+4], S41,0xF7537E82);
  d=II(d,a,b,c,x[k+11],S42,0xBD3AF235);
  c=II(c,d,a,b,x[k+2], S43,0x2AD7D2BB);
  b=II(b,c,d,a,x[k+9], S44,0xEB86D391);
  a=AddUnsigned(a,AA); b=AddUnsigned(b,BB); c=AddUnsigned(c,CC); d=AddUnsigned(d,DD);
 }
 // Step 5.  Output the 128 bit digest
 var temp= WordToHex(a)+WordToHex(b)+WordToHex(c)+WordToHex(d);
 return temp.toLowerCase();
}

//
// DES Symmetric Key
//
cryptoObject.des = function( key, message, encrypt, mode, iv )
{
 //des_createKeys
 //this takes as input a 64 bit key (even though only 56 bits are used)
 //as an array of 2 integers, and returns 16 48 bit keys
 function des_createKeys( key )
 {
  //declaring this locally speeds things up a bit
    pc2bytes0  = new Array (0,0x4,0x20000000,0x20000004,0x10000,0x10004,0x20010000,0x20010004,0x200,0x204,0x20000200,0x20000204,0x10200,0x10204,0x20010200,0x20010204);
    pc2bytes1  = new Array (0,0x1,0x100000,0x100001,0x4000000,0x4000001,0x4100000,0x4100001,0x100,0x101,0x100100,0x100101,0x4000100,0x4000101,0x4100100,0x4100101);
    pc2bytes2  = new Array (0,0x8,0x800,0x808,0x1000000,0x1000008,0x1000800,0x1000808,0,0x8,0x800,0x808,0x1000000,0x1000008,0x1000800,0x1000808);
    pc2bytes3  = new Array (0,0x200000,0x8000000,0x8200000,0x2000,0x202000,0x8002000,0x8202000,0x20000,0x220000,0x8020000,0x8220000,0x22000,0x222000,0x8022000,0x8222000);
    pc2bytes4  = new Array (0,0x40000,0x10,0x40010,0,0x40000,0x10,0x40010,0x1000,0x41000,0x1010,0x41010,0x1000,0x41000,0x1010,0x41010);
    pc2bytes5  = new Array (0,0x400,0x20,0x420,0,0x400,0x20,0x420,0x2000000,0x2000400,0x2000020,0x2000420,0x2000000,0x2000400,0x2000020,0x2000420);
    pc2bytes6  = new Array (0,0x10000000,0x80000,0x10080000,0x2,0x10000002,0x80002,0x10080002,0,0x10000000,0x80000,0x10080000,0x2,0x10000002,0x80002,0x10080002);
    pc2bytes7  = new Array (0,0x10000,0x800,0x10800,0x20000000,0x20010000,0x20000800,0x20010800,0x20000,0x30000,0x20800,0x30800,0x20020000,0x20030000,0x20020800,0x20030800);
    pc2bytes8  = new Array (0,0x40000,0,0x40000,0x2,0x40002,0x2,0x40002,0x2000000,0x2040000,0x2000000,0x2040000,0x2000002,0x2040002,0x2000002,0x2040002);
    pc2bytes9  = new Array (0,0x10000000,0x8,0x10000008,0,0x10000000,0x8,0x10000008,0x400,0x10000400,0x408,0x10000408,0x400,0x10000400,0x408,0x10000408);
    pc2bytes10 = new Array (0,0x20,0,0x20,0x100000,0x100020,0x100000,0x100020,0x2000,0x2020,0x2000,0x2020,0x102000,0x102020,0x102000,0x102020);
    pc2bytes11 = new Array (0,0x1000000,0x200,0x1000200,0x200000,0x1200000,0x200200,0x1200200,0x4000000,0x5000000,0x4000200,0x5000200,0x4200000,0x5200000,0x4200200,0x5200200);
    pc2bytes12 = new Array (0,0x1000,0x8000000,0x8001000,0x80000,0x81000,0x8080000,0x8081000,0x10,0x1010,0x8000010,0x8001010,0x80010,0x81010,0x8080010,0x8081010);
    pc2bytes13 = new Array (0,0x4,0x100,0x104,0,0x4,0x100,0x104,0x1,0x5,0x101,0x105,0x1,0x5,0x101,0x105);

    //how many iterations (1 for des, 3 for triple des)
    var iterations = key.length >= 24 ? 3 : 1;
    //stores the return keys
    var keys = new Array (32 * iterations);
    //now define the left shifts which need to be done
    var shifts = new Array (0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0);
    //other variables
    var lefttemp, righttemp, m=0, n=0, temp;

    for (var j=0; j<iterations; j++)
    { //either 1 or 3 iterations
     left = (key.charCodeAt(m++) << 24) | (key.charCodeAt(m++) << 16) | (key.charCodeAt(m++) << 8) | key.charCodeAt(m++);
       right = (key.charCodeAt(m++) << 24) | (key.charCodeAt(m++) << 16) | (key.charCodeAt(m++) << 8) | key.charCodeAt(m++);

       temp = ((left >>> 4) ^ right) & 0x0f0f0f0f; right ^= temp; left ^= (temp << 4);
       temp = ((right >>> -16) ^ left) & 0x0000ffff; left ^= temp; right ^= (temp << -16);
       temp = ((left >>> 2) ^ right) & 0x33333333; right ^= temp; left ^= (temp << 2);
       temp = ((right >>> -16) ^ left) & 0x0000ffff; left ^= temp; right ^= (temp << -16);
       temp = ((left >>> 1) ^ right) & 0x55555555; right ^= temp; left ^= (temp << 1);
       temp = ((right >>> 8) ^ left) & 0x00ff00ff; left ^= temp; right ^= (temp << 8);
       temp = ((left >>> 1) ^ right) & 0x55555555; right ^= temp; left ^= (temp << 1);

       //the right side needs to be shifted and to get the last four bits of the left side
       temp = (left << 8) | ((right >>> 20) & 0x000000f0);
       //left needs to be put upside down
       left = (right << 24) | ((right << 8) & 0xff0000) | ((right >>> 8) & 0xff00) | ((right >>> 24) & 0xf0);
       right = temp;

       //now go through and perform these shifts on the left and right keys
       for (i=0; i < shifts.length; i++)
       {
         //shift the keys either one or two bits to the left
         if (shifts[i]) {left = (left << 2) | (left >>> 26); right = (right << 2) | (right >>> 26);}
         else {left = (left << 1) | (left >>> 27); right = (right << 1) | (right >>> 27);}
         left &= 0xfffffff0; right &= 0xfffffff0;

         //now apply PC-2, in such a way that E is easier when encrypting or decrypting
         //this conversion will look like PC-2 except only the last 6 bits of each byte are used
         //rather than 48 consecutive bits and the order of lines will be according to
         //how the S selection functions will be applied: S2, S4, S6, S8, S1, S3, S5, S7
         lefttemp = pc2bytes0[left >>> 28] | pc2bytes1[(left >>> 24) & 0xf]
                 | pc2bytes2[(left >>> 20) & 0xf] | pc2bytes3[(left >>> 16) & 0xf]
                 | pc2bytes4[(left >>> 12) & 0xf] | pc2bytes5[(left >>> 8) & 0xf]
                 | pc2bytes6[(left >>> 4) & 0xf];
         righttemp = pc2bytes7[right >>> 28] | pc2bytes8[(right >>> 24) & 0xf]
                   | pc2bytes9[(right >>> 20) & 0xf] | pc2bytes10[(right >>> 16) & 0xf]
                   | pc2bytes11[(right >>> 12) & 0xf] | pc2bytes12[(right >>> 8) & 0xf]
                   | pc2bytes13[(right >>> 4) & 0xf];
         temp = ((righttemp >>> 16) ^ lefttemp) & 0x0000ffff;
         keys[n++] = lefttemp ^ temp; keys[n++] = righttemp ^ (temp << 16);
       }
    } //for each iterations

    //return the keys we've created
    return keys;
 } //end of des_createKeys

 //declaring this locally speeds things up a bit
   var spfunction1 = new Array (0x1010400,0,0x10000,0x1010404,0x1010004,0x10404,0x4,0x10000,0x400,0x1010400,0x1010404,0x400,0x1000404,0x1010004,0x1000000,0x4,0x404,0x1000400,0x1000400,0x10400,0x10400,0x1010000,0x1010000,0x1000404,0x10004,0x1000004,0x1000004,0x10004,0,0x404,0x10404,0x1000000,0x10000,0x1010404,0x4,0x1010000,0x1010400,0x1000000,0x1000000,0x400,0x1010004,0x10000,0x10400,0x1000004,0x400,0x4,0x1000404,0x10404,0x1010404,0x10004,0x1010000,0x1000404,0x1000004,0x404,0x10404,0x1010400,0x404,0x1000400,0x1000400,0,0x10004,0x10400,0,0x1010004);
   var spfunction2 = new Array (0x80108020,0x80008000,0x8000,0x108020,0x100000,0x20,0x80100020,0x80008020,0x80000020,0x80108020,0x80108000,0x80000000,0x80008000,0x100000,0x20,0x80100020,0x108000,0x100020,0x80008020,0,0x80000000,0x8000,0x108020,0x80100000,0x100020,0x80000020,0,0x108000,0x8020,0x80108000,0x80100000,0x8020,0,0x108020,0x80100020,0x100000,0x80008020,0x80100000,0x80108000,0x8000,0x80100000,0x80008000,0x20,0x80108020,0x108020,0x20,0x8000,0x80000000,0x8020,0x80108000,0x100000,0x80000020,0x100020,0x80008020,0x80000020,0x100020,0x108000,0,0x80008000,0x8020,0x80000000,0x80100020,0x80108020,0x108000);
   var spfunction3 = new Array (0x208,0x8020200,0,0x8020008,0x8000200,0,0x20208,0x8000200,0x20008,0x8000008,0x8000008,0x20000,0x8020208,0x20008,0x8020000,0x208,0x8000000,0x8,0x8020200,0x200,0x20200,0x8020000,0x8020008,0x20208,0x8000208,0x20200,0x20000,0x8000208,0x8,0x8020208,0x200,0x8000000,0x8020200,0x8000000,0x20008,0x208,0x20000,0x8020200,0x8000200,0,0x200,0x20008,0x8020208,0x8000200,0x8000008,0x200,0,0x8020008,0x8000208,0x20000,0x8000000,0x8020208,0x8,0x20208,0x20200,0x8000008,0x8020000,0x8000208,0x208,0x8020000,0x20208,0x8,0x8020008,0x20200);
   var spfunction4 = new Array (0x802001,0x2081,0x2081,0x80,0x802080,0x800081,0x800001,0x2001,0,0x802000,0x802000,0x802081,0x81,0,0x800080,0x800001,0x1,0x2000,0x800000,0x802001,0x80,0x800000,0x2001,0x2080,0x800081,0x1,0x2080,0x800080,0x2000,0x802080,0x802081,0x81,0x800080,0x800001,0x802000,0x802081,0x81,0,0,0x802000,0x2080,0x800080,0x800081,0x1,0x802001,0x2081,0x2081,0x80,0x802081,0x81,0x1,0x2000,0x800001,0x2001,0x802080,0x800081,0x2001,0x2080,0x800000,0x802001,0x80,0x800000,0x2000,0x802080);
   var spfunction5 = new Array (0x100,0x2080100,0x2080000,0x42000100,0x80000,0x100,0x40000000,0x2080000,0x40080100,0x80000,0x2000100,0x40080100,0x42000100,0x42080000,0x80100,0x40000000,0x2000000,0x40080000,0x40080000,0,0x40000100,0x42080100,0x42080100,0x2000100,0x42080000,0x40000100,0,0x42000000,0x2080100,0x2000000,0x42000000,0x80100,0x80000,0x42000100,0x100,0x2000000,0x40000000,0x2080000,0x42000100,0x40080100,0x2000100,0x40000000,0x42080000,0x2080100,0x40080100,0x100,0x2000000,0x42080000,0x42080100,0x80100,0x42000000,0x42080100,0x2080000,0,0x40080000,0x42000000,0x80100,0x2000100,0x40000100,0x80000,0,0x40080000,0x2080100,0x40000100);
   var spfunction6 = new Array (0x20000010,0x20400000,0x4000,0x20404010,0x20400000,0x10,0x20404010,0x400000,0x20004000,0x404010,0x400000,0x20000010,0x400010,0x20004000,0x20000000,0x4010,0,0x400010,0x20004010,0x4000,0x404000,0x20004010,0x10,0x20400010,0x20400010,0,0x404010,0x20404000,0x4010,0x404000,0x20404000,0x20000000,0x20004000,0x10,0x20400010,0x404000,0x20404010,0x400000,0x4010,0x20000010,0x400000,0x20004000,0x20000000,0x4010,0x20000010,0x20404010,0x404000,0x20400000,0x404010,0x20404000,0,0x20400010,0x10,0x4000,0x20400000,0x404010,0x4000,0x400010,0x20004010,0,0x20404000,0x20000000,0x400010,0x20004010);
   var spfunction7 = new Array (0x200000,0x4200002,0x4000802,0,0x800,0x4000802,0x200802,0x4200800,0x4200802,0x200000,0,0x4000002,0x2,0x4000000,0x4200002,0x802,0x4000800,0x200802,0x200002,0x4000800,0x4000002,0x4200000,0x4200800,0x200002,0x4200000,0x800,0x802,0x4200802,0x200800,0x2,0x4000000,0x200800,0x4000000,0x200800,0x200000,0x4000802,0x4000802,0x4200002,0x4200002,0x2,0x200002,0x4000000,0x4000800,0x200000,0x4200800,0x802,0x200802,0x4200800,0x802,0x4000002,0x4200802,0x4200000,0x200800,0,0x2,0x4200802,0,0x200802,0x4200000,0x800,0x4000002,0x4000800,0x800,0x200002);
   var spfunction8 = new Array (0x10001040,0x1000,0x40000,0x10041040,0x10000000,0x10001040,0x40,0x10000000,0x40040,0x10040000,0x10041040,0x41000,0x10041000,0x41040,0x1000,0x40,0x10040000,0x10000040,0x10001000,0x1040,0x41000,0x40040,0x10040040,0x10041000,0x1040,0,0,0x10040040,0x10000040,0x10001000,0x41040,0x40000,0x41040,0x40000,0x10041000,0x1000,0x40,0x10040040,0x1000,0x41040,0x10001000,0x40,0x10000040,0x10040000,0x10040040,0x10000000,0x40000,0x10001040,0,0x10041040,0x40040,0x10000040,0x10040000,0x10001000,0x10001040,0,0x10041040,0x41000,0x41000,0x1040,0x1040,0x40040,0x10000000,0x10041000);

   //create the 16 or 48 subkeys we will need
   var keys = des_createKeys (key);
   var m=0, i, j, temp, temp2, right1, right2, left, right, looping;
   var cbcleft, cbcleft2, cbcright, cbcright2
   var endloop, loopinc;
   var len = message.length;
   var chunk = 0;
   //set up the loops for single and triple des
   var iterations = keys.length == 32 ? 3 : 9; //single or triple des
   if (iterations == 3) {looping = encrypt ? new Array (0, 32, 2) : new Array (30, -2, -2);}
   else {looping = encrypt ? new Array (0, 32, 2, 62, 30, -2, 64, 96, 2) : new Array (94, 62, -2, 32, 64, 2, 30, -2, -2);}

   message += "\0\0\0\0\0\0\0\0"; //pad the message out with null bytes
   //store the result here
   result = "";
   tempresult = "";

   if (mode == 1) { //CBC mode
     cbcleft = (iv.charCodeAt(m++) << 24) | (iv.charCodeAt(m++) << 16) | (iv.charCodeAt(m++) << 8) | iv.charCodeAt(m++);
     cbcright = (iv.charCodeAt(m++) << 24) | (iv.charCodeAt(m++) << 16) | (iv.charCodeAt(m++) << 8) | iv.charCodeAt(m++);
     m=0;
   }

   //loop through each 64 bit chunk of the message
   while (m < len)
   {
     left = (message.charCodeAt(m++) << 24) | (message.charCodeAt(m++) << 16) | (message.charCodeAt(m++) << 8) | message.charCodeAt(m++);
     right = (message.charCodeAt(m++) << 24) | (message.charCodeAt(m++) << 16) | (message.charCodeAt(m++) << 8) | message.charCodeAt(m++);

     //for Cipher Block Chaining mode, xor the message with the previous result
     if (mode == 1) {if (encrypt) {left ^= cbcleft; right ^= cbcright;} else {cbcleft2 = cbcleft; cbcright2 = cbcright; cbcleft = left; cbcright = right;}}

     //first each 64 but chunk of the message must be permuted according to IP
     temp = ((left >>> 4) ^ right) & 0x0f0f0f0f; right ^= temp; left ^= (temp << 4);
     temp = ((left >>> 16) ^ right) & 0x0000ffff; right ^= temp; left ^= (temp << 16);
     temp = ((right >>> 2) ^ left) & 0x33333333; left ^= temp; right ^= (temp << 2);
     temp = ((right >>> 8) ^ left) & 0x00ff00ff; left ^= temp; right ^= (temp << 8);
     temp = ((left >>> 1) ^ right) & 0x55555555; right ^= temp; left ^= (temp << 1);

     left = ((left << 1) | (left >>> 31));
     right = ((right << 1) | (right >>> 31));

     //do this either 1 or 3 times for each chunk of the message
     for (j=0; j<iterations; j+=3)
     {
        endloop = looping[j+1];
        loopinc = looping[j+2];
        //now go through and perform the encryption or decryption
        for (i=looping[j]; i!=endloop; i+=loopinc)
        { //for efficiency
          right1 = right ^ keys[i];
          right2 = ((right >>> 4) | (right << 28)) ^ keys[i+1];
          //the result is attained by passing these bytes through the S selection functions
          temp = left;
          left = right;
          right = temp ^ (spfunction2[(right1 >>> 24) & 0x3f] | spfunction4[(right1 >>> 16) & 0x3f]
                | spfunction6[(right1 >>>  8) & 0x3f] | spfunction8[right1 & 0x3f]
                | spfunction1[(right2 >>> 24) & 0x3f] | spfunction3[(right2 >>> 16) & 0x3f]
                | spfunction5[(right2 >>>  8) & 0x3f] | spfunction7[right2 & 0x3f]);
        }

        temp = left; left = right; right = temp; //unreverse left and right
     } //for either 1 or 3 iterations

     //move then each one bit to the right
     left = ((left >>> 1) | (left << 31));
     right = ((right >>> 1) | (right << 31));

     //now perform IP-1, which is IP in the opposite direction
     temp = ((left >>> 1) ^ right) & 0x55555555; right ^= temp; left ^= (temp << 1);
     temp = ((right >>> 8) ^ left) & 0x00ff00ff; left ^= temp; right ^= (temp << 8);
     temp = ((right >>> 2) ^ left) & 0x33333333; left ^= temp; right ^= (temp << 2);
     temp = ((left >>> 16) ^ right) & 0x0000ffff; right ^= temp; left ^= (temp << 16);
     temp = ((left >>> 4) ^ right) & 0x0f0f0f0f; right ^= temp; left ^= (temp << 4);

     //for Cipher Block Chaining mode, xor the message with the previous result
     if (mode == 1) {if (encrypt) {cbcleft = left; cbcright = right;} else {left ^= cbcleft2; right ^= cbcright2;}}
     tempresult += String.fromCharCode ((left>>>24), ((left>>>16) & 0xff), ((left>>>8) & 0xff), (left & 0xff), (right>>>24), ((right>>>16) & 0xff), ((right>>>8) & 0xff), (right & 0xff));

     chunk += 8;
     if (chunk == 512) {result += tempresult; tempresult = ""; chunk = 0;}
   } //for every 8 characters, or 64 bits in the message

   //return the result as an array
   return result + tempresult;
} //end of des

//
// Print Hex Array
//
cryptoObject.printHex = function( s )
{
 var r = "0x";
   var hexes = new Array ("0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f");
   for (var i=0; i<s.length; i++) {r += hexes [s.charCodeAt(i) >> 4] + hexes [s.charCodeAt(i) & 0xf];}
   return r;
}

//
// Print UnHex Array
//
cryptoObject.unHex = function( s )
{
 var r = "";
   for (var i=2; i<s.length;i+=2) {
    x1 = s.charCodeAt(i);
    x1 = x1 >= 48 && x1 < 58 ? x1 - 48 : x1 - 97 + 10;
    x2 = s.charCodeAt(i+1);
    x2 = x2 >= 48 && x2 < 58 ? x2 - 48 : x2 - 97 + 10;
    r += String.fromCharCode (((x1 << 4) & 0xF0) | (x2 & 0x0F));
   }

   return r;
}

//
// Client Random Key 생성
//

cryptoObject.getRandomKey = function( digits )
{
 var rndKey, nIndex;

 rndKey = "";

 do
 {
  nIndex = Math.floor( Math.random() * cryptoObject.KeyStr.length ) + 1;
  rndKey = rndKey + cryptoObject.KeyStr.substr( nIndex, 1 );
 }
 while ( rndKey.length < digits )

 return rndKey;
}

Posted by 1010
반응형
/^[a-z0-9_]{4,20}$/;
Posted by 1010
반응형
 


네이버나 포탈사이트 등을 방문 하다보면 위와같이

앞글자 혹은 중간글자만 쳐도 나머지 글자들이 나오는 화면을 볼수있는데

이를 자동완성기능 혹은 autocomplete 라고 한다..

기본적으로 브라우저내에서 자동완성기능을 지원하긴 하지만

DB와 연동해서 뿌려주는 기능은 별도 제작을 해야한다.

캐릭터셋이 utf-8 이냐 euc kr 이냐에 따라서도 사용방법이 약간은 다르다.

아래는 간단한 예제와 샘플파일이다.


위 파일은 autocomplete 기능을 사용하게 해주는 plug in 이며

jquery.com 의 plugins 에서도 다운이 가능하다.

우선 jquery 스크립트를 넣어준 뒤 위 플러그인을 삽입해주면 된다.

<?include "data_js.php";?>

<SCRIPT type="text/javascript" src="../jquery/jquery-1.4.2.min.js"></script>
<link rel="stylesheet" type="text/css" href="./autocomplete/jquery.autocomplete.css"/>
<script type="text/javascript" src="./autocomplete/jquery.autocomplete.js"></script>

<script type="text/javascript">
$(document).ready(function() {
 $("#search").autocomplete(goods,{
  matchContains: true
 });
});
</script>

<input type="text" id="search" autocomplete="off">

* 상세소스는 http://jaweb.co.kr/jstudy/18.php 접속후 소스보기하면 다 나오는데
위의 소스만으로도 구동에는 전혀 문제가 없다.


위 내용은 search 라는 id 필드는 autocomplete 기능을 사용할 것이고

데이터는 goods 데이터를 기반으로 내용중 일부라도 맞는경우 (matchContains: true)

보여지게 하겠다는 속성이다.

데이터(goods)를 가져올때는 여러가지 방법이 있는데

난 DB에서 데이터 이용방법과 js 파일 생성방식 두가지로 선택했다.


data_js.php 파일은  단순하게 파일내에 입력을 하게되면 알아서 적용된다. (내용이 간단하니 파일을 참고하면 좋다.)


data_db.php 파일은 db셋팅이 되어있는 파일내에서 어느부분인지를 선택 한 뒤 작업을 해주면 된다.

헌데 소스내용을 보면 굳이 urlencode 를 해서 array_push로 배열안에 값을 넣고

실제 뿌려줄때는 urldecode 를 해서 json 방식으로 다시 인코딩 한 뒤 값을 뿌려준다.

urlencode 의 사용목적은 바로 한글문제..

utf-8 환경에선 urlencode 없이도 무리없이 정상작동 하지만

euckr 환경에선 글씨가 깨져서 들어가거나

null값으로 출력이되어 오류가 나게 된다.


그럴때 json으로 인코딩을 하기 전 urlencode 로 한번 인코딩을 해주고

실제 뿌려줄때 decode를 안하게되면 %45%D 이런식으로 문자가 깨져서 보이기에

글씨 깨짐을 방지하기 위해서 위와같이 작업을 한것이다.


autocomplete 플러그인 내에서는 지원하는 기능이 내가 설명한 정도보다는 훨씬 많다.

줄에 맞춰서 값을 가져오거나

key값에 따라 값을 뿌려주는 기능...

이미지를 이용 출력해는 기능 등~   (참고 : http://jaweb.nayana.com/search.php   우측상단 펫 검색란에 1,2 등을 치거나 펫 이름을 치면 결과가 나오는데.. jquery 처음 배울때 작업한 것이라 소스가 상당히 조잡한 편이다.)

쓸데가 상당히 많아보이는 플러그인이니 공부할때 참고하면 좋을 것 같다.


출처 : http://jaweb.tistory.com/159

------------------------------------------------------

Ajax AutoComplete for jQuery

AutoComplete is like Magic!

Ajax Autocomplete for jQuery allows you to easily create autocomplete/autosuggest boxes for text input fields.

It is built with focus on performance. Results for every query are cached and pulled from local cache for the same repeating query. If there are no results for particular query it stops sending requests to the server for other queries with the same root.

Demo

Ajax autosuggest sample (start typing country name):


Local(no ajax) autosuggest sample (start typing month name):

Suggest:   

Note: Delimiter support has been added in v1.0.5. Try separate countries by "," or ";".

What's New in 1.1

$('#query').autocomplete(options) now returns an Autocomplete instance only for the first matched element.

Autocomplete functionality can be disabled or enabled programmatically.

var ac = $('#query').autocomplete(options);
ac.disable();
ac.enable();

Options can be changed programmatically at any time, only options that are passed get set:

ac.setOptions({ zIndex: 1001 });

If you need to pass additional parameters, you can set them via setOptions too:

ac.setOptions({ params: { first:'John', last:'Doe' } });

New parameters when initializing autocomplete. They can also be set via setOptions.

- zIndex: default value is 9999.

- fnFormatResult: function that formats values that are displayed in the autosuggest list. It takes three parameters: suggested value, data and current query value. Default function for this:

var reEscape = new RegExp('(\\' + ['/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\'].join('|\\') + ')', 'g');

function fnFormatResult(value, data, currentValue) {
  var pattern = '(' + currentValue.replace(reEscape, '\\$1') + ')';
  return value.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>');
}

Installation

Include jQuery in your header. After its included, add autocomplete script.

<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="jquery.autocomplete.js"></script>

How to Use

Here is an Ajax Autocomplete sample for the text field with id "query"

<input type="text" name="q" id="query" />

Create an instance of the Autocomplete object. You can have multiple instances on a single page.

Important: Autocomplete must be initialized after DOM has finished loading. Otherwise you will get an error in IE.

var options, a;
jQuery(function(){
  options = { serviceUrl:'service/autocomplete.ashx' };
  a = $('#query').autocomplete(options);
});

You can add extra options:

  var a = $('#query').autocomplete({ 
    serviceUrl:'service/autocomplete.ashx',
    minChars:2, 
    delimiter: /(,|;)\s*/, // regex or character
    maxHeight:400,
    width:300,
    zIndex: 9999,
    deferRequestBy: 0, //miliseconds
    params: { country:'Yes' }, //aditional parameters
    noCache: false, //default is false, set to true to disable caching
    // callback function:
    onSelect: function(value, data){ alert('You selected: ' + value + ', ' + data); },
    // local autosugest options:
    lookup: ['January', 'February', 'March', 'April', 'May'] //local lookup values 
  });

Use lookup option only if you prefer to inject an array of autocompletion options, rather than sending Ajax queries.

Web page that provides data for Ajax Autocomplete, in our case autocomplete.ashx will receive GET request with querystring ?query=Li, and it must return JSON data in the following format:

{
 query:'Li',
 suggestions:['Liberia','Libyan Arab Jamahiriya','Liechtenstein','Lithuania'],
 data:['LR','LY','LI','LT']
}

Notes:

  • query - original query value
  • suggestions - comma separated array of suggested values
  • data (optional) - data array, that contains values for callback function when data is selected.

Styling

Script generates the following HTML (sample query Li). Active element when you navigate up and down is marked with class "selected". You can style it any way you wish.

<div class="autocomplete-w1">
  <div style="width:299px;" id="Autocomplete_1240430421731" class="autocomplete">
    <div><strong>Li</strong>beria</div>
    <div><strong>Li</strong>byan Arab Jamahiriya</div>
    <div><strong>Li</strong>echtenstein</div>
    <div class="selected"><strong>Li</strong>thuania</div>
  </div>
</div>

Here is style used in the sample above:

.autocomplete-w1 { background:url(img/shadow.png) no-repeat bottom right; position:absolute; top:0px; left:0px; margin:6px 0 0 6px; /* IE6 fix: */ _background:none; _margin:1px 0 0 0; }
.autocomplete { border:1px solid #999; background:#FFF; cursor:default; text-align:left; max-height:350px; overflow:auto; margin:-6px 6px 6px -6px; /* IE6 specific: */ _height:350px;  _margin:0; _overflow-x:hidden; }
.autocomplete .selected { background:#F0F0F0; }
.autocomplete div { padding:2px 5px; white-space:nowrap; overflow:hidden; }
.autocomplete strong { font-weight:normal; color:#3399FF; }

If you will use this CSS, please make sure to correct path to the shadow.png image. Image is included in the package. It uses CSS Drop Shadow technique by Sergio Villarreal.

Download

Download Ajax AutoComplete for jQuery

Download DevBridge Ajax Autocomplete v1.1.3 for jQuery

Ajax Autocomplete for jQuery is freely distributable under the terms of an MIT-style license.

Currently supported browsers: IE 7+, FF 2+, Safari 3+, Opera 9+


Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


Posted by 1010
반응형
누가 물어봐서 찾아본 김에 그냥 정리합니다. 아시다시피 Javascript는 명시적인 타입정의가 없습니다. int나 String같이 타입을 명시해서 변수를 정의하지 않고 그냥 var타입으로 정의하면 Javascript가 알아서 적절한 타입을 지정합니다. 명시적인 타입이 없다는건 때론 타입때문에 헷갈리기도 하고 원치 않는 결과가 나타나기도 합니다.

그래서 보통은 약간 편법적인 방법으로 String을 Number로 바꾼다던지 Number를 String으로 바꾼다던지 합니다.

  1. // 숫자를 스트링로 바꾸기  
  2. var tt = 2  
  3. tt += "";  
  4. alert(typeof tt);   // Result : string  
  5.  
  6. // 스트링을 숫자로 바꾸기  
  7. tt = "2" 
  8. tt *= 1;  
  9. alert(typeof tt);    // Result : number  

위의 방법이 가장 간단하게 형변환을 하는 방법입니다. 쉽게 자바스크립트의 자동형변환을 이용한 겁니다. 숫자타입에 문자열을 더하면 결과가 문자열이 되고 문자열에 숫자를 곱하면 숫자타입이 되는 특성을 이용해서 결과는 달라지지 않게 타입만 변환되도록 한 것입니다.

해본 사람을 보면 알기는 하겠지만 잘 모르는 사람이 보면 어떤 의도로 한 소스인지 명확하지 않은 단점이 있기도 하고 좀더 명시적으로 타입변환이 필요할 때가 있습니다.

  1. // 숫자를 스트링로 바꾸기  
  2. var tt = 2  
  3. alert(typeof tt);    // Result : number  
  4. tt = String(tt);  
  5. alert(typeof tt);    // Result : string  
  6.  
  7. // 스트링을 숫자로 바꾸기  
  8. tt = "2" 
  9. alert(typeof tt);    // Result : string  
  10. tt = Number(tt);  
  11. alert(typeof tt);    // Result : number  

타입변환을 하는 함수인 Number()와 String()을 이용한 소스입니다.



또한 아래처럼 parseInt()나 parseFloat()를 이용해서도 형변환을 할 수 있습니다. 함수명에서 알 수 있듯이 parseInt()는 Integer타입으로 변환을 하고 parseFloat()는 Float타입으로 변환을 합니다.
  1. var tt = "2" 
  2. alert(typeof tt);    // Result : string  
  3. tt = parseInt(tt);  
  4. alert(typeof tt);    // Result : number  
  5.               
  6. tt = "2" 
  7. alert(typeof tt);    // Result : string  
  8. tt = parseFloat(tt);  
  9. alert(typeof tt);    // Result : number  

parseInt()나 parseFloat()는 형변환 자체가 목적은 아니기 때문에 얘기가 나온 김에 좀 더 살펴보겠습니다. parseIn()와 parseFloat()는 정수와 실수로 파싱해 주는 역할을 하고 있습니다.

parseInt(string, radix)
parseFloat(string)

API정의를 보면 위처럼 정의되어 있습니다. parseInt()에서 radix는 기수로 parse할 때 기준이 되는 진수입니다. 정수로 파싱하는 parseInt에만 정의되어 있습니다. 2~ 36진수까지를 정의할 수 있고 optional값으로 없을 경우 10진수로 parse합니다.

  1. parseInt("123.456");        // 123  
  2. parseInt("100mile");        // 100  
  3. parseInt("w25");               // NaN  
  4. parseInt("05");                  // 5  
  5. parseInt("09");                  // 0  
  6. parseInt("0x35");              // 53  
  7. parseInt("1101", 2);         // 13  
  8. parseInt("09", 10);            // 9  
  9. parseInt("10", 8);              // 8  
  10.  
  11. parseFloat("123.456");       // 123.456  
  12. parseFloat("100.5mile");    // 100.5  
  13. parseFloat("w25");               // NaN  
  14. parseFloat("05");                  // 5  
  15. parseFloat("09");                  // 9  
  16. parseFloat("0x35");              // 0  

Javascript에서 "0"으로 시작하는 숫자는 8진수 "0x"로 시작하는 숫자는 16진수로 정의되고 있기 때문에 5번라인에서 9가 8진수에서 사용할 수 없기 때문에 의도하지 않은 0이 나왔습니다.


출처 : http://blog.outsider.ne.kr/361
Posted by 1010