1 
  2 /**
  3  * @fileOverview Librería para la producción de contenidos de la web 
  4  * @version 1.0
  5  * @author taejin (drumtj@gmail.com)
  6  */
  7 
  8 /**
  9  * @see <a href="http://jquery.com/">http://jquery.com/</a>
 10  * @name jQuery 
 11  * @class
 12  * Refiere jQuery Library (http://jquery.com/) para ver los detalles completos. Esto solo documenta las funciones y clases que son añadidos por este plug-in de jQuery. 
 13  */
 14 
 15 
 16 /**
 17  * @see <a href="http://jquery.com/">http://jquery.com/</a>
 18  * @name fn
 19  * @class
 20  * Refiere jQuery Library (http://jquery.com/) para ver los detalles completos. Esto solo documenta la función y clases que son añadidos a jQuery por este plug-in. 
 21  * @memberOf jQuery
 22  */
 23 
 24 (function(){
 25 	
 26 	if( !("jQuery" in window) ){
 27 		throw new Error("sg library is require jQuery");
 28 	}
 29 	
 30 	var toString = {}.toString
 31 		, slice = [].slice;
 32 	
 33 	var //readyCallbackList = []
 34 		initCallbackList = []
 35 		, customTagList = {}
 36 		, customAttrList = {}
 37 		, setStageFunc
 38 		, setScaleModeFunc
 39 		, progressImg;
 40 	
 41 	//private
 42 	var version = "1.0"
 43 		, scaleMode = "none"
 44 		, scaleX = 0
 45 		, scaleY = 0
 46 		, stageWidth = 0
 47 		, stageHeight = 0
 48 		, $stage = null
 49 		, $content = null
 50 		, $body = null
 51 		, $window = $( window );
 52 	
 53 	//support
 54 	if( !("forEach" in Array.prototype) ){
 55 		Array.prototype.forEach = function ( callback ){
 56 			for( var i=0; i<this.length; i++ ){
 57 				callback.call( window, this[ i ] );
 58 			}
 59 		}
 60 	}
 61 	
 62 	/**
 63 	 * Configura el cursor del mouse como puntero. 
 64 	 * @function
 65 	 * @name pointer
 66 	 * @memberOf jQuery.fn
 67 	 * @example
 68 	 * $( element ).pointer();
 69 	 * @example
 70 	 * $( element ).pointer( false );
 71 	 * @param {boolean} bool
 72 	 * @returns Objeto de jQuery 
 73 	 * @type jQuery Object
 74 	 */
 75 	jQuery.fn.pointer = function(){
 76 		return $( this ).css( "cursor", arguments[0] == false ? "auto" : "pointer" );
 77 	};
 78 	
 79 	/**
 80 	 * Devuelve el valor numérico del CSS. 
 81 	 * @function
 82 	 * @name cssVal
 83 	 * @memberOf jQuery.fn
 84 	 * @example
 85 	 * $( element ).cssVal( "margin-top" );
 86 	 * @param {string} cssName
 87 	 * @returns value
 88 	 * @type number
 89 	 */
 90 	jQuery.fn.cssVal = function( cssName ){
 91 		var num = parseFloat( $( this ).css( cssName ) );
 92 		return isNaN( num ) ? 0 : num;
 93 	};
 94 	
 95 	/**
 96 	 * Es una función que extrae las etiquetas personalizadas específicas. Extrae las etiquetas personalizadas entre los elementos hijos. 
 97 	 * @function
 98 	 * @name getCustomTag
 99 	 * @memberOf jQuery.fn
100 	 * @example
101 	 * $( 'p' ).getCustomTag( "sg-btn-hide" );
102 	 * @param {string} tagName
103 	 * @returns Objeto de jQuery 
104 	 * @type jQuery Object
105 	 * @link sg.addCustomTag referir las funciones definidas de etiquetas personalizadas. 
106 	 */
107 	jQuery.fn.getCustomTag = function( tagName ){
108 		var isRoot = (this == $);
109 		for( var o in customTagList ){
110 			if( tagName == o ){
111 				if( isRoot ) return $( "[" + customTagList[ o ].identifier + "]" );
112 				else return $( this ).children( "[" + customTagList[ o ].identifier + "]" );
113 			}
114 		}
115 		return $;
116 	};
117 	
118 	/**
119 	 * Función que extrae las etiquetas personalizadas específicas. 
120 	 * @function
121 	 * @name getCustomTag
122 	 * @memberOf jQuery
123 	 * @example
124 	 * $.getCustomTag( "sg-btn-hide" );
125 	 * @param {string} tagName
126 	 * @returns objeto de jQuery
127 	 * @type jQuery Object
128 	 * @link sg.addCustomTag referir funciones definidas de etiquetas personalizadas. 
129 	 */
130 	jQuery.getCustomTag = jQuery.fn.getCustomTag;
131 	
132 	
133 	
134 	function swapTag( obj, findTagName, swapTagName, identifier ) {
135 		if ( document.querySelector( findTagName ) ) {
136 			identifier = identifier ? ' ' + identifier + ' ' : '';
137 			obj.html = obj.html
138 				.replace( new RegExp( '<' + findTagName, 'g' ), '<' + swapTagName + identifier )
139 				.replace( new RegExp( '</' + findTagName + '>', 'g' ), '</' + swapTagName + '>' );
140 		}else{
141 			customTagList[ findTagName ].nothing = true;
142 		}
143 	}
144 	
145 	function replaceTagList(){
146 		var obj = {	html: document.body.innerHTML }
147 			, customTagName
148 			, customAttrName
149 			, ctInfo, caInfo, i, j, k;
150 		
151 		for( customTagName in customTagList ){
152 			ctInfo = customTagList[ customTagName ];
153 			swapTag(obj, customTagName, ctInfo.originTag, ctInfo.identifier);
154 		};
155 
156 		//add custom attribute prefix : data-
157 		var sgAttrNameReg = /\ssg([\-][\w]*){1,5}(\s)?=/gi,
158 			s1 = obj.html.split('<'),
159 			s2, matchArr, r2 = [];
160 
161 		for ( i = 0; i < s1.length; i++ ) {
162 			s2 = s1[ i ].split( '>' );
163 			for ( j = 0; j < s2.length; j++ ) {
164 				if ( j % 2 == 0 ) {
165 					matchArr = s2[ j ].match( sgAttrNameReg );
166 					if ( matchArr ) {
167 						for ( k = 0; k < matchArr.length; k++ ) {
168 							s2[ j ] = s2[ j ].replace( matchArr[ k ], " data-" + matchArr[ k ].substr( 1 ) );
169 						}
170 					}
171 				}
172 			}
173 			r2.push( s2.join( '>' ) );
174 		}
175 		
176 		obj.html = r2.join( '<' );
177 		document.body.innerHTML = obj.html;
178 		
179 		delete s1;
180 		delete s2;
181 		delete r2;
182 		delete obj;
183 		delete matchArr;
184 		
185 		//support placeholder bug
186 		$( "[placeholder]" ).each(function(i,e){
187 			$( this ).text("").attr( "placeholder", $( this ).attr("placeholder") );
188 		});
189 		
190 		//function apply for custom tags
191 		var $customTag;
192 		for( customTagName in customTagList ){
193 			ctInfo = customTagList[ customTagName ];
194 			if( ctInfo.nothing ) continue;
195 			
196 			$customTag = $.getCustomTag( customTagName );
197 			
198 			if( sg.isFunction( ctInfo[ "initFunc" ] ) ){
199 				ctInfo[ "initFunc" ].call( sg );
200 			}
201 			
202 			//execute to init function of custom attribute for each custom tag
203 			$customTag.each(function(index, element) {
204 				$( element ).data( "_customTagName", customTagName );
205 				sg.setOption( element );
206 				if( /^sg-btn-/.test( customTagName ) ) $( element ).pointer();
207 				if( sg.isFunction( ctInfo[ "eachInitFunc" ] ) ){
208 					ctInfo[ "eachInitFunc" ].call( element, element );
209 				}
210 				sg.initAttr( element );
211 			});
212 			
213 			//execute to action function of custom attribute when called event handle
214 			if( ctInfo[ "eventName" ] ){
215 				$customTag.bind( ctInfo[ "eventName" ], function( e ){
216 					var ctname = $( this ).data( "_customTagName" );
217 					if ( !$( this ).data( "options" ).enabled ) return;
218 					if( sg.isFunction( customTagList[ ctname ][ "eventFunc" ] ) ) customTagList[ ctname ][ "eventFunc" ].call( this, this, e );
219 					sg.actionAttr( this );
220 				});
221 			};
222 			$customTag = null;
223 		};
224 		
225 		//apply custom attribute for all tag
226 		for( customAttrName in customAttrList ){
227 			caInfo = customAttrList[ customAttrName ];
228 			if( caInfo.isForEveryTags ){
229 				if( caInfo && sg.isFunction( caInfo[ "init" ] ) ){
230 					$( "[data-" + customAttrName + "]" ).each(function( i, element ){
231 						sg.setOption( element );
232 						caInfo[ "init" ].call( element, element, element.getAttribute( "data-" + customAttrName ) );
233 					});
234 				}
235 			}
236 		}
237 	}
238 	
239 	//call by 'resize' event
240 	var _ww, _hh, _ch, _msc;
241 	function applyScaleMode(){
242 		_ww = $window.width();
243 		_hh = $window.height();
244 		_ch = $content.height();
245 		_ch += $content.cssVal( "border-top-width" ) + $content.cssVal( "border-bottom-width" );
246 		_ch += $content.cssVal( "margin-top" ) + $content.cssVal( "margin-bottom" );
247 		_ch += $content.cssVal( "padding-top" ) + $content.cssVal( "padding-bottom" );
248 		
249 		switch( scaleMode ){
250 			case "showall":
251 				_msc = Math.min(_ww / stageWidth, _hh / stageHeight);
252 				if(_ch - stageHeight <= 1){
253 					//컨텐츠가 스테이지보다 클 때
254 					if(_ch * _msc > _hh){
255 						//console.log("top 0, overflow:visible");
256 						$stage.css({
257 							"transform" : "scale(" + _msc + ")",
258 							"transform-origin" : "0 0",
259 							"left" : ((_ww - stageWidth * _msc) * 0.5) + "px",
260 							"top" : 0
261 						});
262 						
263 						$stage.parent().css({
264 							"overflow-y" : "visible"
265 						});
266 					}
267 					//컨텐츠가 스테이지 안에 있을 때
268 					else{
269 						//console.log("top center, overflow:hidden");
270 						$stage.css({
271 							"transform" : "scale(" + _msc + ")",
272 							"transform-origin" : "0 0",
273 							"left" : ((_ww - stageWidth * _msc) * 0.5) + "px",
274 							"top" : ((_hh - _ch * _msc) * 0.5) + "px"
275 						});
276 						
277 						$stage.parent().css({
278 							"overflow-y" : "hidden"
279 						});
280 					}
281 				}
282 				else{
283 					//console.log("top center, overflow:auto");
284 					$stage.css({
285 						"transform" : "scale(" + _msc + ")",
286 						"transform-origin" : "0 0",
287 						"left" : ((_ww - stageWidth * _msc) * 0.5) + "px",
288 						"top" : ((_hh - stageHeight * _msc) * 0.5) + "px"
289 					});
290 					
291 					$stage.parent().css({
292 						"overflow-y" : "auto"
293 					});	
294 				}
295 				scaleX = scaleY = _msc;
296 			break;
297 			
298 			case "noscale":
299 				scaleX = scaleY = 1;
300 				$stage.css({
301 					"transform" : "scale(" + scaleX + ")",
302 					"transform-origin" : "0 0"
303 				});
304 			break;
305 			
306 			case "exactfit":
307 				scaleX = _ww / stageWidth;
308 				scaleY = _hh / stageHeight;
309 				$stage.css({
310 					"transform" : "scale(" + scaleX + ", " + scaleY + ")",
311 					"transform-origin" : "0 0"
312 				});
313 			break;
314 		}
315 	}
316 	
317 	
318 	/**
319 	 * @namespace Librería para la producción de contenidos de la web
320 	 * @author taejin (drumtj@gmail.com)
321 	 * @name sg
322 	 * @version 1.0
323 	 * @since 2014.09.22
324 	 * @description
325 	 * sg library es una librería que requiere jQuery. <br>
326 	 * Ofrece configuración de scaleMode, atributos personalizados y API para la producción de etiquetas personalizadas.<br>
327 	 */
328 	var sg = {
329 		/**
330 		 * [Read Only] es información sobre versions de la librería sg.
331 		 * @name version
332 		 * @memberOf sg
333 		 * @type string
334 		 */
335 		get version() { return version },
336 		
337 		/**
338 		 * [Read Only] Método de escala de stage. Se lo configura con Sg.setScaleMode y se puede colocar "showall", "exactfit" o "none" como su valor. 
339 		 * @name scaleMode
340 		 * @memberOf sg
341 		 * @type string
342 		 */
343 		get scaleMode() { return scaleMode },
344 		
345 		/**
346 		 *[Read Only]  Es el valor del eje X de stage. Se calcula el valor cuando se ajusta scaleMode como la función de  sg.set.
347 		 * Su proporción se calcula en base del width de stage.
348 		 * @name scaleX
349 		 * @memberOf sg
350 		 * @type number 0.0 ~ 1.0
351 		 */
352 		get scaleX() { return scaleX },
353 		
354 		/**
355 		 * [Read Only] stage의 Es el valor del eje Y de stage. Se calcula el valor cuando se ajusta scaleMode como la función de  sg.set.
356 		 * Su proporción se calcula en base del width de stage. 
357 		 * @name scaleY
358 		 * @memberOf sg
359 		 * @type number 0.0 ~ 1.0
360 		 */
361 		get scaleY() { return scaleY },
362 		
363 		/**
364 		 * [Read Only] El valor de width de stage. Se importa el valor de width de stage al configurar stage con la función de set Stage.
365 		 * @name stageWidth
366 		 * @memberOf sg
367 		 * @type number
368 		 */
369 		get stageWidth() { return stageWidth },
370 		
371 		/**
372 		 * [Read Only] El valor de height de stage. Se importa el valor de height de stage al configurar stage con la función de set Stage.
373 		 * @name stageHeight
374 		 * @memberOf sg
375 		 * @type number
376 		 */
377 		get stageHeight() { return stageHeight },
378 		
379 		/**
380 		 * [Read Only] Es un elemento configurado como stage. Se lo configura con sg.setStage.
381 		 * @name $stage
382 		 * @memberOf sg
383 		 * @type jQuery Object
384 		 */
385 		get $stage() { return $stage },
386 		
387 		/**
388 		 * [Read Only] Es un contenedor que contiene los elementos hijos de stage. Se crea cuando se configura $stage.
389 		 * @name $content
390 		 * @memberOf sg
391 		 * @type jQuery Object
392 		 */
393 		get $content() { return $content },
394 		
395 		/**
396 		 * [Read Only] $("body")
397 		 * @name $body
398 		 * @memberOf sg
399 		 * @type jQuery Object
400 		 */
401 		get $body() { return $body },
402 		
403 		/**
404 		 * [Read Only] $(window)
405 		 * @name $window
406 		 * @memberOf sg
407 		 * @type jQuery Object
408 		 */
409 		get $window() { return $window },
410 		
411 		/**
412 		 * Se puede añadir o extender funciones en sg. 
413 		 * @function
414 		 * @name extend
415 		 * @memberOf sg
416 		 * @example
417 		 * sg.extend({
418 		 * 	myfunc: function( ){
419 		 *		//TO DO
420 		 * 	}
421 		 * });
422 		 *
423 		 * sg.myfunc();
424 		 * @param {object} property
425 		 * @link sg.super Referencia
426 		 */
427 		extend: function( prop ){
428 			if(typeof prop !== "object"){ throw new Error("sg.extend arguments is not Object!"); }
429 			
430 			for( var name in prop ){
431 				//sg.hasOwnProperty( name )
432 				if( name in sg ) prop[ name ]._super = sg[ name ];
433 				sg[ name ] = prop[ name ];
434 			}
435 		},
436 		
437 		/**
438 		 * importa la etiqueta original desde la función extendida a través de sg.extend.
439 		 * @function
440 		 * @name super
441 		 * @memberOf sg
442 		 * @example
443 		 * sg.extend({
444 		 * 	myfunc: function( str ){
445 		 *		return '<<' + str + '>>';
446 		 * 	}
447 		 * });
448 		 *
449 		 * sg.myfunc( 'abc' ); //return "<<abc>>"
450 		 *
451 		 * sg.extend({
452 		 * 	myfunc: function( str ){
453 		 *		return this.super( str.toUpperCase() );
454 		 * 	}
455 		 * });
456 		 *
457 		 * sg.myfunc( 'abc' ); //return "<<ABC>>"
458 		 * @param {object} [arguments=undefined] Parámetros de la función original.
459 		 * @return {*} el valor devuelto de la función original. 
460 		 * @type *
461 		 * @link sg.extend Refencia
462 		 */
463 		super: function(){
464 			var _super = arguments.callee.caller._super;
465 			return sg.isFunction( _super ) ? _super.apply( this, arguments ) : null;
466 		}
467 	};
468 	
469 	
470 	sg.extend({
471 		/**
472 		 * Verificar si el objeto es función. Usar isFunction de jQuery.
473 		 * @function
474 		 * @name isFunction
475 		 * @memberOf sg
476 		 * @param {object} object
477 		 * @returns true o false
478 		 * @type boolean
479 		 */
480 		isFunction: $.isFunction,
481 		
482 		/**
483 		 * Verificar si el objeto es array. Usar la función isArray de jQuery. 
484 		 * @function
485 		 * @name isArray
486 		 * @memberOf sg
487 		 * @param {object} object
488 		 * @returns true o false
489 		 * @type boolean
490 		 */
491 		isArray: $.isArray,
492 		
493 		/**
494 		 * Verificar si el objeto es objeto de window. Usar la función isWindow de jQuery.
495 		 * @function
496 		 * @name isWindow
497 		 * @memberOf sg
498 		 * @param {object} object
499 		 * @returns true o false
500 		 * @type boolean
501 		 */
502 		isWindow: $.isWindow,
503 		
504 		/**
505 		 * Verificar si el objeto es número. Usar la función isNumeric de jQuery.
506 		 * @function
507 		 * @name isNumeric
508 		 * @memberOf sg
509 		 * @param {object} object
510 		 * @returns true o false
511 		 * @type boolean
512 		 */
513 		isNumeric: $.isNumeric,
514 		
515 		/**
516 		 * Verificar si el objeto es un objeto vacío. Usar la función isEmptyObject de jQuery. 
517 		 * @function
518 		 * @name isEmptyObject
519 		 * @memberOf sg
520 		 * @param {object} object
521 		 * @returns true o false
522 		 * @type boolean
523 		 */
524 		isEmptyObject: $.isEmptyObject,
525 		
526 		/**
527 		 * Verificar si el objeto está incluido en el array. Usar la función inArray de jQuery. 
528 		 * @function
529 		 * @name inArray
530 		 * @memberOf sg
531 		 * @param {object} element
532 		 * @param {array} array
533 		 * @param {number} index
534 		 * @returns true o false
535 		 * @type string
536 		 */
537 		inArray: $.inArray,
538 		
539 		/**
540 		 * Devuelve data type del objeto. Usar la función type de jQuery. 
541 		 * @function
542 		 * @name type
543 		 * @memberOf sg
544 		 * @param {object}
545 		 * @returns true o false
546 		 * @type string
547 		 */
548 		type: $.type
549 	});
550 	
551 	
552 	
553 	sg.extend({
554 		
555 		/**
556 		 * Añadir la función de inicialización (callback). Las funciones (callback) añadidas se ejecutan después de la inicialización.
557 		 * @function
558 		 * @name addInit
559 		 * @memberOf sg
560 		 * @example
561 		 * sg.addInit( function(){} );
562 		 * @param {function} callback
563 		 */
564 		addInit: function( callback ){
565 			initCallbackList.push( callback );
566 		},
567 		
568 		/**
569 		 * Configurar la ruta de la imagen de cargando. La imagen configurada se visualiza en la pantalla durante la ejecución de página. 
570 		 * @function
571 		 * @name setLoadingImage
572 		 * @memberOf sg
573 		 * @example
574 		 * sg.setLoadingImage( '../common/img/progress.gif' );
575 		 * @param {string} path
576 		 */
577 		setLoadingImage: function( path ){
578 			progressImg = new Image();
579 			progressImg.setAttribute("data-sg-id", "progressImg");
580 			progressImg["onload"] = function( e ){
581 				this.style.left = (((window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth) - this.width) * 0.5) + "px";
582 				this.style.top = (((window.innerHeight || document.documentElement.clientWidth || document.body.clientWidth) - this.height) * 0.5) + "px";
583 				if( !sg.isReady ) document.body.appendChild( progressImg );
584 				else delete progressImg;
585 			};
586 			progressImg.src = path;
587 			progressImg.style.position = "fixed";
588 			progressImg.style.visibility = "visible";
589 		},
590 		
591 		/**
592 		 * Configura stage. El stage configurado tiene acceso al sg.$stage. El stage es el criterio de controlar la escala. 
593 		 * @function
594 		 * @name setStage
595 		 * @memberOf sg
596 		 * @example
597 		 * sg.setStage( "#stage" );
598 		 * @param {object} elementOrSelector
599 		 */
600 		setStage: function( elementOrSelector ){
601 			setStageFunc = function(){
602 				var $temp = $( elementOrSelector );
603 				if( $temp.length == 0 ) throw new Error( "setStage : $stage is not select. (selector : " + elementOrSelector + ")" );
604 				
605 				$temp.attr( "data-sg-id", "stage" );
606 				$content = $( "<div data-sg-id='content'></div>" );
607 				$content.append( $temp.contents() );
608 				
609 				$temp.append( $content ).css( "position", "absolute" );
610 				$temp.parent().css( "overflow-x", "hidden" );
611 				
612 				//border가 없으면, 때로는 크기가 잘 못 계산되기 때문에
613 				if( $temp.cssVal( "border-top-width" ) == 0 ){
614 					$temp.css( "border", "solid 1px rgba(255,255,255,0)" );
615 				}
616 				
617 				stageWidth = $temp.width();
618 				stageHeight = $temp.height();
619 				
620 				$content.css({
621 					"min-height": stageHeight,
622 					"visibility": "hidden"
623 				});
624 							
625 				$stage = $temp;
626 				
627 				//apply scaleMode
628 				if( setScaleModeFunc ){
629 					setScaleModeFunc.apply( sg );
630 					setScaleModeFunc = null;
631 				}
632 			}
633 			
634 			if( sg.isReady ){
635 				setStageFunc.apply( sg );
636 				setStageFunc = null;
637 			}
638 		},
639 		
640 		/**
641 		 * Configura scaleMode. Se habilita siempre y cuando tenga configurado el stage, y hay modos de "showall", "exactfit" y "none".
642 		 * @function
643 		 * @name setScaleMode
644 		 * @memberOf sg
645 		 * @example
646 		 * sg.setStage( "#stage" );
647 		 * sg.setScaleMode( "showall" );
648 		 * @example
649 		 * sg.setStage( "#stage" );
650 		 * sg.setScaleMode( "exactfit" );
651 		 * @param {string} scaleMode
652 		 */
653 		setScaleMode: function( _scaleMode ){
654 			scaleMode = _scaleMode;
655 			setScaleModeFunc = function(){
656 				$window.bind( "resize" , function(){
657 					applyScaleMode();
658 				});
659 				applyScaleMode();
660 			}
661 			
662 			if( $stage ){
663 				setScaleModeFunc.apply( this );
664 				setScaleModeFunc = null;
665 			}
666 		},
667 		
668 		//options setting for custom tags
669 		/**
670 		 * Se guarda el valor a ser aplicado al ejecutar la etiqueta personalizada en $(target).data("options").
671 		 * @function
672 		 * @name setOption
673 		 * @memberOf sg
674 		 * @example
675 		 * sg.setOption( element );
676 		 * @example
677 		 * sg.setOption( element , {myClicked: false} );
678 		 * @param {object} elementOrSelector 	- elemento o selector de jQuery
679 		 * @param {object} [options=undefined]	- Objeto con el conjunto de valores
680 		 */
681 		setOption: function ( target, options ){
682 			var op = { enabled: true };
683 			for( var o in options ) op[ o ] = options[ o ];
684 			$( target ).data( "options", op );
685 		},
686 		
687 		/**
688 		 * Añadir atributos personalizados.<br>
689 		 * Al definir los atributos, se puede colocar true en el valor de applyAll con el fin de utlizarlos en todas las etiquetas.<br>
690 		 * Cuando el valor es false, se habilita la función del atributo al usarlo en la etiqueta personalizada. En general,
691 		 * los atributos personalizados definidos poseen una función especial, y esta función es habilitada con los eventos de las etiquetas personalizadas,
692 		 * y por ende, se deja el valor básico de applyAll como false.
693 		 * @function
694 		 * @name addCustomAttr
695 		 * @memberOf sg
696 		 * @param {object} 		option 						- inicializar el objeto de atributo personalizado
697 		 * @param {string} 		option.name 				- nombre de atributo personalizado.
698 		 * @param {function} 	[option.init=undefined] 	- función de inicialización.
699 		 * @param {function} 	[option.action=undefined] 	- función a ejecutar: se ejecuta cuando se procede los eventos de la etiquetas
700 		 * personalizadas que utilitza estos atributos personalizados. 
701 		 * @param {boolean} 	[option.applyAll=true] 		- determina si se habilita la función de este atributo en todas las etiquetas básicas. 
702 		 * @example
703 		 * //script
704 		 * sg.addCustomAttr({
705 		 *	name: "sg-fadeIn",
706 		 *	init: function( element, attrValue ){
707 		 *		$( element ).fadeIn();
708 		 *	},
709 		 * 	applyAll: true
710 		 * });
711 		 * //html
712 		 * <div sg-fadeIn> ABCD </div>
713 		 * @example
714 		 * //script
715 		 * sg.addCustomAttr({
716 		 *	name: "sg-color",
717 		 *	init: function( element, attrValue ){
718 		 * 		$( element ).css( "color", attrValue );
719 		 * 	},
720 		 *	applyAll: true
721 		 * });
722 		 * //html
723 		 * <div sg-color="red"> ABCD </div>
724 		 * @example
725 		 * sg.addCustomAttr({
726 		 *	name: "sg-alert",
727 		 *	action: function( element, attrValue ){
728 		 * 		if( attrValue ) alert( attrValue );
729 		 * 	}
730 		 * });
731 		 * @link sg.addCustomTag referir la función definida para etiquetas personalizdas.
732 		 */
733 		addCustomAttr: function( obj ){
734 			customAttrList[ obj.name ] = {
735 				init: obj.init,
736 				action: obj.action,
737 				isForEveryTags: obj.applyAll
738 			}
739 		},
740 		
741 		/**
742 		 * Añadir etiquetas personalizadas.<br>
743 		 * El mecanismo básico de la etiqueta personalizada es reemplazar las líneas de código html. <br>
744 		 * Después de la carga de la página, se busca las etiquetas personalizadas en el body de html, y las reemplaza a las etiquetas básicas definidas. <br>
745 		 * Al definir las etiquetas personalizadas, se escribe el nombre de la etiqueta original en originTag. Puede ser que las etiquetas personalizadas tengan evento o no.
746 		 * Se puede crear una etiqueta personalizada que sirve para cambiar la estructura interna de la etiqueta definiendo una función en tagInit.
747 		 * Por otra parte, se puede crear las etiquetas personalizadas que se habilitan con eventos específicos con una definión de función eventHandle.
748 		 * @function
749 		 * @name addCustomTag
750 		 * @memberOf sg
751 		 * @param {object} 		option 							- inicializar el objeto de etiqueta personalizado
752 		 * @param {string}		option.name						- Nombre de etiqueta personalizada. 
753 		 * @param {string}		[option.originTag="div"]		- El nombre de la etiqueta a ser reemplazada.
754 		 * @param {string}		[option.id="data-sg-id={name of custom tag}"]
755 		 *														- Identificador de etiqueta personalizada. Si no es un caso específico, se usa el valor básico.
756 		 * @param {array}		[option.attr=undefined]			- un array donde se listan los nombres de los atributos personalizados a ser usados en la etiqueta personalizada. 
757 		 * @param {function}	[option.init=undefined]			- se define las funciones si hay algo que se tiene que ejecutar al inicializar. 
758 		 * @param {function}	[option.tagInit=undefined]		- se define las funciones si hay algo que se tiene que ejecutar en cada etiqueta al inicializar. 
759 		 * @param {string}		[option.event=undefined]		- si se habilita con un evento específico, se escribe el nombre. 
760 		 * @param {function}	[option.eventHandle=undefined]	- se define la función que ejecute evento.  
761 		 * @example
762 		 * //script
763 		 * sg.addCustomTag({
764 		 *	name: "sg-depth",
765 		 * 	tagInit: function( element ){
766 		 *		$("<p></p>").append( $( element ).contents() ).appendTo( $( element ) );
767 		 * 	}
768 		 * });
769 		 * //html
770 		 * <sg-depth> ABCD <sg-depth>
771 		 * //result
772 		 * <sg-depth> <p>ABCD</p> <sg-depth>
773 		 * @example
774 		 * //script
775 		 * sg.addCustomTag({
776 		 *	name: "sg-h1",
777 		 *	attr: [ "sg-color", "sg-alert" ],
778 		 * 	tagInit: function( element ){
779 		 * 		$( element ).css( "font-size", "40pt" );
780 		 * 	},
781 		 * 	event: "click",
782 		 * 	eventHandle: function( element ){
783 		 * 		$( element ).animate( {"font-size": "80pt"} );
784 		 * 	}
785 		 * });
786 		 * //html
787 		 * <sg-h1 sc-color="blue" sg-alert="hello!"> ABCD </sg-h1>
788 		 * @link jQuery.getCustomTag Hacer referencia la función extraída de la etiqueta personalizada.
789 		 * @link sg.addCustomAttr Hacer referencia la función definida del atributo personalizado. 
790 		 */
791 		addCustomTag: function( obj ){
792 			customTagList[ obj.name ] = {
793 				originTag: obj.originTag ? obj.originTag : "div",
794 				identifier: obj.id ? obj.id : "data-sg-id='" + obj.name + "'",
795 				eventName: obj.event,
796 				attrList: (function( list ){
797 					if( !list ) return null;
798 					else list = slice.call( list );//copy array
799 					var i=0, attrName;
800 					list.forEach( function(attrName){
801 						if( !(attrName in customAttrList) ) list.splice( i, 1 );
802 						else i++;
803 					});
804 					return list;
805 				})( obj.attr ),
806 				initFunc: obj.init,
807 				eachInitFunc: obj.tagInit,
808 				eventFunc: obj.eventHandle
809 			}
810 		},
811 		
812 		//initialize about custom attribute in custom tag
813 		/**
814 		 * La función de inicialización sobre los atributos configurados al definir la etiqueta personalizada. 
815 		 * @function
816 		 * @name initAttr
817 		 * @memberOf sg
818 		 * @example sg.initAttr( element );
819 		 * @param {object} element
820 		 */
821 		initAttr: function( element ){
822 			//console.log( element, arguments.callee );
823 			var customTagName = $( element ).data( "_customTagName" )
824 				, attrList, attr, attrValue;
825 				
826 			if( customTagName ){
827 				attrList = customTagList[ customTagName ].attrList;
828 				if( attrList ){
829 					attrList.forEach(function( attrName ){
830 						attr = customAttrList[ attrName ];
831 						attrValue = element.getAttribute( "data-" + attrName );
832 						if( attr && attr[ "init" ] && !attr.isForEveryTags ){
833 							attr[ "init" ].call( element, element, attrValue );
834 						}
835 					});
836 				}
837 			}
838 		},
839 		
840 		//execute function about custom attribute in custom tag
841 		/**
842 		 * Ejecuta la función action del atributo personalizado definedo en la etiqueta personalizada. 
843 		 * @function
844 		 * @name actionAttr
845 		 * @memberOf sg
846 		 * @example sg.actionAttr( element );
847 		 * @param {object} element
848 		 */
849 		actionAttr: function( element ){
850 			var customTagName = $( element ).data( "_customTagName" )
851 				, attrList, attr, attrValue;
852 				
853 			if( customTagName ){
854 				attrList = customTagList[ customTagName ].attrList;
855 				if( attrList ){
856 					attrList.forEach(function( attrName ){
857 						attr = customAttrList[ attrName ];
858 						attrValue = element.getAttribute( "data-" + attrName );
859 						if( attr && attr[ "action" ] ){
860 							attr[ "action" ].call( element, element, attrValue );
861 						}
862 					});
863 				}
864 			}
865 		},
866 		
867 		
868 		
869 		/**
870 		 * jQuery.hide
871 		 * @function
872 		 * @name hide
873 		 * @memberOf sg
874 		 * @example
875 		 * sg.hide( 'p' );	//$( 'p' ).hide();
876 		 * sg.hide( this ); //$( this ).hide();
877 		 * @param {object} elementOrSelector
878 		 */
879 		hide: function( elementOrSelector ){
880 			$( elementOrSelector ).hide();
881 		},
882 		
883 		/**
884 		 * jQuery.show
885 		 * @function
886 		 * @name show
887 		 * @memberOf sg
888 		 * @example
889 		 * sg.show( 'p' );	//$( 'p' ).show();
890 		 * sg.show( this ); //$( this ).show();
891 		 * @param {object} elementOrSelector
892 		 */
893 		show: function( elementOrSelector ){
894 			$( elementOrSelector ).show();
895 		},
896 		
897 		/**
898 		 * jQuery.fadeIn("slow")
899 		 * @function
900 		 * @name fadeIn
901 		 * @memberOf sg
902 		 * @example
903 		 * sg.fadeIn( 'p' );	//$( 'p' ).fadeIn( 'slow' );
904 		 * sg.fadeIn( this );	//$( this ).fadeIn( 'slow' );
905 		 * @param {object} elementOrSelector
906 		 */
907 		fadeIn: function( elementOrSelector ){
908 			$( elementOrSelector ).fadeIn("slow");
909 		},
910 		
911 		/**
912 		 * jQuery.fadeOut("slow")
913 		 * @function
914 		 * @name fadeOut
915 		 * @memberOf sg
916 		 * @example
917 		 * sg.fadeOut( 'p' );	//$( 'p' ).fadeOut( 'slow' );
918 		 * sg.fadeOut( this );	//$( this ).fadeOut( 'slow' );
919 		 * @param {object} elementOrSelector
920 		 */
921 		fadeOut: function( elementOrSelector ){
922 			$( elementOrSelector ).fadeOut("slow");
923 		},
924 		
925 		/**
926 		 * Deshabilitar los eventos en el componente, y configura el cursor como puntero. 
927 		 * @function
928 		 * @name enabled
929 		 * @memberOf sg
930 		 * @example
931 		 * sg.enabled( this );
932 		 * sg.enabled( '#myButton' );
933 		 * sg.enabled( $.getCustomTag( 'sg-btn-hide' ) );
934 		 * @param {object} elementOrSelector
935 		 * @returns objeto de jQuery
936 		 * @type jQuery Object
937 		 */
938 		enabled: function ( elementOrSelector ){
939 			return $(elementOrSelector).each(function(i,e){
940 				var $this = $(this);
941 				$this.css("cursor","pointer");
942 				var options = $this.data("options") || {};
943 				options.enabled = true;
944 				$this.data("options", options);
945 			});
946 		},
947 		
948 		/**
949 		 * Deshabilitar los eventos en el componente, y configura el cursor por defecto. 
950 		 * @function
951 		 * @name disabled
952 		 * @memberOf sg
953 		 * @example
954 		 * sg.disabled( this );
955 		 * sg.disabled( '#myButton' );
956 		 * sg.disabled( $.getCustomTag( 'sg-btn-hide' ) );
957 		 * @param {object} elementOrSelector
958 		 * @returns objeto de jQuery
959 		 * @type jQuery Object
960 		 */
961 		disabled: function ( elementOrSelector ){		
962 			return $(elementOrSelector).each(function(i,e){
963 				var $this = $(this);
964 				$this.css("cursor","default");
965 				var options = $this.data("options") || {};
966 				options.enabled = false;
967 				$this.data("options", options);
968 			});
969 		}
970 	});
971 	
972 	sg.extend({
973 		/**
974 		 * En el caso de que se pase la función (callback) como función de inicialización o parámetro, se ejecuta primero la inicialización y luego la función.<br>
975 		 * En el caso de sg.init(), se ejecuta primero html content(contenido de html) internamente y la inicialización.<br>
976 		 * Si hay algo que se debe ejecutar después de la inicialización, se pasa la función (callback) al parámetro de init(). 
977 		 * @function
978 		 * @name init
979 		 * @memberOf sg
980 		 * @example
981 		 * sg.setStage( "#stage" );
982 		 * sg.setScaleMode( "showall" );
983 		 * sg.init();
984 		 * @example
985 		 * sg.setStage( "#stage" );
986 		 * sg.setScaleMode( "showall" );
987 		 * sg.init( function(){} );
988 		 * @param {function} [callback=undefined]
989 		 */
990 		init: function ( callback ) {
991 			function _init(){
992 				//////setting
993 				//console.log("setting");
994 				$body = $( document.body );
995 				
996 				replaceTagList();
997 				
998 				if( setStageFunc ){
999 					setStageFunc.apply( sg );
1000 					setStageFunc = null;
1001 				}
1002 				
1003 				///compatibility for old versions
1004 				if( "init" in window && sg.isFunction( window[ "init" ] ) ){
1005 					window[ "init" ].apply( window );
1006 				}
1007 				
1008 				if( "initList" in window ){
1009 					initCallbackList = initCallbackList.concat( window[ "initList" ] );
1010 				}
1011 				///
1012 				
1013 				initCallbackList.forEach( function( initFunc ){
1014 					if( sg.isFunction( initFunc ) ) initFunc.apply( window );
1015 				});
1016 				
1017 				
1018 				$("[data-sg-id='progressImg']").remove();
1019 				$content = $("[data-sg-id='content']").css( "visibility", "visible" );
1020 				$stage = $("[data-sg-id='stage']");
1021 				sg.isReady = true;
1022 				
1023 				setTimeout(function(){
1024 					$window.trigger("resize");
1025 				}, 0);
1026 			}
1027 			
1028 			if( $.isReady ){
1029 				_init.apply( window );
1030 				if( sg.isFunction( callback ) ) callback.apply( window );
1031 			}else{
1032 				$( document ).ready(function(e) {
1033                     _init.apply( window );
1034 					if( sg.isFunction( callback ) ) callback.apply( window );
1035                 });
1036 			}
1037 		}
1038 	});
1039 	
1040 	window.sg = sg;
1041 	
1042 	return sg;
1043 })();